diff --git a/documentation/docs/shielding/Shield/Shield.mdx b/documentation/docs/shielding/Shield/Shield.mdx
new file mode 100644
index 0000000000..1d4f16b315
--- /dev/null
+++ b/documentation/docs/shielding/Shield/Shield.mdx
@@ -0,0 +1,50 @@
+---
+hide_title: false
+hide_table_of_contents: false
+pagination_next: null
+pagination_prev: null
+---
+# `Shield()`
+
+Load information about the given shield.
+
+Returns an object representing the shield if it is active, or throws an exception if the string is malformed or the shield doesn’t exist.
+
+Shield names are defined on [this webpage](https://www.fastly.com/documentation/guides/concepts/shielding/#shield-locations), in the “shield code” column. For example, the string “pdx-or-us” will look up our Portland, OR, USA shield site, while “paris-fr” will look up our Paris site.
+
+If you are using a major cloud provider for your primary origin site, consider looking at the “Recommended for” column, to find the Fastly POP most closely located to the given cloud provider.
+
+## Syntax
+
+```js
+new Shield(name)
+```
+
+> **Note:** `Shield()` can only be constructed with `new`. Attempting to call it without `new` throws a [`TypeError`](../../globals/TypeError/TypeError.mdx).
+
+### Exceptions
+
+- `TypeError`
+ - Thrown if no Shield exists with the provided name
+
+## Examples
+
+In this example, we create a Shield instance for the Sydney, Australia shield POP. If the code is running on that shield POP, it fetches directly from origin. Otherwise, it routes the request through the shield using an encrypted connection.
+
+```js
+///
+
+import { Shield } from "fastly:shielding";
+
+async function app(event) {
+ const shield = new Shield('wsi-australia-au');
+ // If running on the shield POP, fetch from the origin directly
+ if (shield.runningOn()) {
+ return await fetch('https://http-me.fastly.com/anything', { backend: 'httpme' });
+ }
+ // Otherwise, route the request through the shield using an encrypted connection
+ return await fetch(event.request, { backend: shield.encryptedBackend() });
+}
+
+addEventListener("fetch", (event) => event.respondWith(app(event)))
+```
diff --git a/documentation/docs/shielding/Shield/prototype/encryptedBackend.mdx b/documentation/docs/shielding/Shield/prototype/encryptedBackend.mdx
new file mode 100644
index 0000000000..3bb7ccd3bc
--- /dev/null
+++ b/documentation/docs/shielding/Shield/prototype/encryptedBackend.mdx
@@ -0,0 +1,13 @@
+---
+hide_title: false
+hide_table_of_contents: false
+pagination_next: null
+pagination_prev: null
+---
+# Shield.prototype.encryptedBackend
+
+▸ **encryptedBackend**(): `Backend`
+
+Returns a `Backend` representing an encrypted connection to the POP.
+
+For reference, this is almost always the backend that you want to use. Only use [`Shield::unencryptedBackend`](./unencryptedBackend.mdx) in situations in which you are 100% sure that all the data you will send and receive over the backend is already encrypted.
\ No newline at end of file
diff --git a/documentation/docs/shielding/Shield/prototype/runningOn.mdx b/documentation/docs/shielding/Shield/prototype/runningOn.mdx
new file mode 100644
index 0000000000..9ff395fe08
--- /dev/null
+++ b/documentation/docs/shielding/Shield/prototype/runningOn.mdx
@@ -0,0 +1,15 @@
+---
+hide_title: false
+hide_table_of_contents: false
+pagination_next: null
+pagination_prev: null
+---
+# Shield.prototype.runningOn
+
+▸ **runningOn**(): `boolean`
+
+Returns whether we are currently operating on the given shield.
+
+Technically, this may also return true in very isolated incidents in which Fastly is routing traffic from the target shield POP to the POP that this code is running on, but in these situations the results should be approximately identical.
+
+(For example, it may be the case that you are asking to shield to ‘pdx-or-us’. But, for load balancing, performance, or other reasons, Fastly is temporarily shifting shielding traffic from Portland to Seattle. In that case, this function may return true for hosts running on ‘bfi-wa-us’, our Seattle site, because effectively the shield has moved to that location. This should give you a slightly faster experience than the alternative, in which this function would return false, you would try to forward your traffic to the Portland site, and then that traffic would be caught and redirected back to Seattle.)
diff --git a/documentation/docs/shielding/Shield/prototype/unencryptedBackend.mdx b/documentation/docs/shielding/Shield/prototype/unencryptedBackend.mdx
new file mode 100644
index 0000000000..a8e42e5175
--- /dev/null
+++ b/documentation/docs/shielding/Shield/prototype/unencryptedBackend.mdx
@@ -0,0 +1,13 @@
+---
+hide_title: false
+hide_table_of_contents: false
+pagination_next: null
+pagination_prev: null
+---
+# Shield.prototype.unencryptedBackend
+
+▸ **unencryptedBackend**(): `Backend`
+
+Returns a `Backend` representing an unencrypted connection to the POP.
+
+Generally speaking, we encourage users to use [`Shield::encryptedBackend`](./encryptedBackend.mdx) instead of this function. Data sent over this backend – the unencrypted version – will be sent over the open internet, with no protections. In most cases, this is not what you want. However, in some cases – such as when you want to ship large data blobs that you know are already encrypted — using these backends can prevent a double-encryption performance penalty.
\ No newline at end of file
diff --git a/integration-tests/js-compute/fixtures/app/__input_bundled.js.map b/integration-tests/js-compute/fixtures/app/__input_bundled.js.map
new file mode 100644
index 0000000000..0ba93345ca
--- /dev/null
+++ b/integration-tests/js-compute/fixtures/app/__input_bundled.js.map
@@ -0,0 +1,7 @@
+{
+ "version": 3,
+ "sources": ["env", "src/routes.js", "experimental", "src/async-select.js", "src/assertions.js", "src/btoa.js", "src/byob.js", "cache-override", "src/byte-repeater.js", "src/cache-override.js", "cache", "body", "src/cache-core.js", "src/cache-simple.js", "src/client.js", "compute", "src/compute.js", "config-store", "src/config-store.js", "src/crypto.js", "device", "src/device.js", "dictionary", "src/dictionary.js", "src/early-hints.js", "edge-rate-limiter", "src/edge-rate-limiter.js", "src/env.js", "fanout", "src/fanout.js", "websocket", "src/websocket.js", "src/fastly-global.js", "backend", "src/fetch-errors.js", "geolocation", "src/geoip.js", "src/headers.js", "html-rewriter", "src/html-rewriter.js", "src/include-bytes.js", "image-optimizer", "src/image-optimizer.js", "logger", "src/logger.js", "src/manual-framing-headers.js", "src/missing-backend.js", "src/multiple-set-cookie.js", "src/performance.js", "src/random.js", "src/react-byob.js", "src/request-auto-decompress.js", "src/request-cache-key.js", "src/request-clone.js", "src/request-headers.js", "src/request-method.js", "src/response-json.js", "src/response-redirect.js", "src/response.js", "secret-store", "src/fast-check.js", "src/secret-store.js", "src/server.js", "shielding", "src/shielding.js", "src/tee.js", "src/timers.js", "src/urlsearchparams.js", "src/index.js"],
+ "sourcesContent": ["export const env = globalThis.fastly.env.get;", "import { env } from 'fastly:env';\n\n/**\n * @type {Map Promise>}\n */\nexport const routes = new Map();\nroutes.set('/', () => {\n routes.delete('/');\n let test_routes = Array.from(routes.keys());\n return new Response(JSON.stringify(test_routes), {\n headers: { 'content-type': 'application/json' },\n });\n});\n\nexport function isRunningLocally() {\n return (\n env('FASTLY_SERVICE_VERSION') === '' ||\n env('FASTLY_SERVICE_VERSION') === '0'\n );\n}\n", "\nexport const includeBytes = globalThis.fastly.includeBytes;\nexport const enableDebugLogging = globalThis.fastly.enableDebugLogging;\nexport const setBaseURL = Object.getOwnPropertyDescriptor(globalThis.fastly, 'baseURL').set;\nexport const setDefaultBackend = Object.getOwnPropertyDescriptor(globalThis.fastly, 'defaultBackend').set;\nexport const allowDynamicBackends = Object.getOwnPropertyDescriptor(globalThis.fastly, 'allowDynamicBackends').set;\nexport const sdkVersion = globalThis.fastly.sdkVersion;\nexport const mapAndLogError = (e) => globalThis.__fastlyMapAndLogError(e);\nexport const mapError = (e) => globalThis.__fastlyMapError(e);\n", "import { routes } from './routes';\n\nroutes.set('/async-select/hello', () => {\n let requestsData = [\n {\n url: 'https://compute-sdk-test-backend.edgecompute.app/async_select_1',\n backend: 'TheOrigin',\n header: 'fooname',\n },\n {\n url: 'https://compute-sdk-test-backend.edgecompute.app/async_select_2',\n backend: 'TheOrigin2',\n header: 'barname',\n },\n ];\n\n let pending = requestsData.map((data) => {\n let request = new Request(data.url);\n return fetch(request, { backend: data.backend });\n });\n\n return processUpstreamRequests(pending, requestsData);\n});\n\nasync function processUpstreamRequests(requests, requestsData) {\n // Create our response headers we will be sending downstream\n let responseHeaders = new Headers();\n\n // Loop through our requests\n for await (let response of select(requests)) {\n // Check which response we got, so we know which header to\n // copy over to our response headers\n let { header } = requestsData.find((data) => data.url == response.url);\n\n // Set the appropriate header on our response\n let headerValue = response.headers.get(header);\n if (headerValue == null) {\n throw new Error(\n 'No header value on the response from the request with url ' +\n response.url +\n ' and with the header name: ' +\n header,\n );\n }\n responseHeaders.set(header, headerValue);\n }\n\n // Send our response downstream\n return new Response('pong', {\n headers: responseHeaders,\n });\n}\n\nasync function* select(promises) {\n promises = promises.map((promise) => {\n promise.finally(() => {\n promises.splice(promises.indexOf(promise), 1);\n });\n return promise;\n });\n\n while (promises.length) {\n yield await Promise.any(promises);\n }\n}\n", "// Testing/Assertion functions //\n\nexport async function sleep(milliseconds) {\n return new Promise((resolve) => {\n setTimeout(resolve, milliseconds);\n });\n}\n\n// TODO: Implement ReadableStream getIterator() and [@@asyncIterator]() methods\nexport async function streamToString(stream) {\n const decoder = new TextDecoder();\n let string = '';\n let reader = stream.getReader();\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return string;\n }\n string += decoder.decode(value);\n }\n}\n\nexport function iteratableToStream(iterable) {\n return new ReadableStream({\n async pull(controller) {\n for await (const value of iterable) {\n controller.enqueue(value);\n }\n controller.close();\n },\n });\n}\n\nexport function pass(message = '') {\n return new Response(message);\n}\n\nfunction prettyPrintSymbol(a) {\n if (typeof a === 'symbol') {\n return String(a);\n }\n return a;\n}\nexport function assert(actual, expected, code) {\n if (!deepEqual(actual, expected)) {\n throw new Error(\n `Expected \\`${code}\\` to equal \\`${JSON.stringify(prettyPrintSymbol(expected))}\\` - Found \\`${JSON.stringify(prettyPrintSymbol(actual))}\\``,\n );\n }\n}\n\nexport { assert as strictEqual };\n\nexport function ok(truthy, code) {\n if (!truthy) {\n throw new Error(\n `Expected ${code ? code + ' ' : ''}to be truthy - Found \\`${JSON.stringify(prettyPrintSymbol(truthy))}\\``,\n );\n }\n}\n\nexport async function assertResolves(func) {\n try {\n await func();\n } catch (error) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to resolve - Found it rejected: ${error.name}: ${error.message}`,\n );\n }\n}\n\nexport async function assertRejects(func, errorClass, errorMessage) {\n try {\n await func();\n } catch (error) {\n if (errorClass) {\n if (error instanceof errorClass === false) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to reject instance of \\`${errorClass.name}\\` - Found instance of \\`${error.name}\\``,\n );\n }\n }\n\n if (errorMessage) {\n if (error.message !== errorMessage) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to reject error message of \\`${errorMessage}\\` - Found \\`${error.message}\\``,\n );\n }\n }\n\n return;\n }\n throw new Error(\n `Expected \\`${func.toString()}\\` to reject - Found it did not reject`,\n );\n}\n\nexport function assertThrows(func, errorClass, errorMessage) {\n try {\n func();\n } catch (error) {\n if (errorClass) {\n if (error instanceof errorClass === false) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to throw instance of \\`${errorClass.name}\\` - Found instance of \\`${error.name}\\`: ${error.message}\\n${error.stack}`,\n );\n }\n }\n\n if (errorMessage) {\n if (error.message !== errorMessage) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to throw error message of \\`${errorMessage}\\` - Found \\`${error.message}\\``,\n );\n }\n }\n\n return;\n }\n throw new Error(\n `Expected \\`${func.toString()}\\` to throw - Found it did not throw`,\n );\n}\n\nexport function assertDoesNotThrow(func) {\n try {\n func();\n } catch (error) {\n throw new Error(\n `Expected \\`${func.toString()}\\` to not throw - Found it did throw: ${error.name}: ${error.message}`,\n );\n }\n}\n\nexport function deepStrictEqual(a, b) {\n if (!deepEqual(a, b)) {\n throw new Error(`Expected ${a} to equal ${b}`);\n }\n}\n\nexport function deepEqual(a, b) {\n var aKeys;\n var bKeys;\n var typeA;\n var typeB;\n var key;\n var i;\n\n typeA = typeof a;\n typeB = typeof b;\n if (a === null || typeA !== 'object') {\n if (b === null || typeB !== 'object') {\n return a === b;\n }\n return false;\n }\n\n // Case: `a` is of type 'object'\n if (b === null || typeB !== 'object') {\n return false;\n }\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!deepEqual(a[i], b[i])) {\n return false;\n }\n }\n return true;\n }\n if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) {\n return false;\n }\n if (a instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (a instanceof RegExp) {\n return a.source === b.source && a.flags === b.flags;\n }\n if (a instanceof Error) {\n if (a.message !== b.message || a.name !== b.name) {\n return false;\n }\n }\n\n aKeys = Object.keys(a);\n bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n aKeys.sort();\n bKeys.sort();\n\n // Cheap key test:\n for (i = 0; i < aKeys.length; i++) {\n if (aKeys[i] !== bKeys[i]) {\n return false;\n }\n }\n // Possibly expensive deep equality test for each corresponding key:\n for (i = 0; i < aKeys.length; i++) {\n key = aKeys[i];\n if (!deepEqual(a[key], b[key])) {\n return false;\n }\n }\n return typeA === typeB;\n}\n", "import { assert, assertThrows } from './assertions.js';\nimport { routes } from './routes';\n\nroutes.set('/btoa', () => {\n // btoa\n {\n var everything = '';\n for (var i = 0; i < 256; i++) {\n everything += String.fromCharCode(i);\n }\n assert(\n btoa(everything),\n 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==',\n );\n\n assert(btoa(42), btoa('42'));\n assert(btoa(null), btoa('null'));\n assert(btoa({ x: 1 }), btoa('[object Object]'));\n\n assertThrows(() => btoa(), TypeError);\n assertThrows(() => btoa('\uD83D\uDC31'));\n\n assert(btoa(''), '', `btoa(\"\")`);\n assert(btoa('ab'), 'YWI=', `btoa(\"ab\")`);\n assert(btoa('abc'), 'YWJj', `btoa(\"abc\")`);\n assert(btoa('abcd'), 'YWJjZA==', `btoa(\"abcd\")`);\n assert(btoa('abcde'), 'YWJjZGU=', `btoa(\"abcde\")`);\n assert(btoa('\u00FF\u00FF\u00C0'), '///A', `btoa(\"\u00FF\u00FF\u00C0\")`);\n assert(btoa('\\0a'), 'AGE=', `btoa(\"\\\\0a\")`);\n assert(btoa('a\\0b'), 'YQBi', `btoa(\"a\\\\0b\")`);\n assert(btoa(undefined), 'dW5kZWZpbmVk', `btoa(undefined)`);\n assert(btoa(null), 'bnVsbA==', `btoa(null)`);\n assert(btoa(7), 'Nw==', `btoa(7)`);\n assert(btoa(12), 'MTI=', `btoa(12)`);\n assert(btoa(1.5), 'MS41', `btoa(1.5)`);\n assert(btoa(true), 'dHJ1ZQ==', `btoa(true)`);\n assert(btoa(false), 'ZmFsc2U=', `btoa(false)`);\n assert(btoa(NaN), 'TmFO', `btoa(NaN)`);\n assert(btoa(Infinity), 'SW5maW5pdHk=', `btoa(Infinity)`);\n assert(btoa(-Infinity), 'LUluZmluaXR5', `btoa(-Infinity)`);\n assert(btoa(0), 'MA==', `btoa(0)`);\n assert(btoa(-0), 'MA==', `btoa(-0)`);\n assert(btoa('\\0'), 'AA==', `btoa(\"\\\\0\")`);\n assert(btoa('\\x01'), 'AQ==', `btoa(\"\\\\x01\")`);\n assert(btoa('\\x02'), 'Ag==', `btoa(\"\\\\x02\")`);\n assert(btoa('\\x03'), 'Aw==', `btoa(\"\\\\x03\")`);\n assert(btoa('\\x04'), 'BA==', `btoa(\"\\\\x04\")`);\n assert(btoa('\\x05'), 'BQ==', `btoa(\"\\\\x05\")`);\n assert(btoa('\\x06'), 'Bg==', `btoa(\"\\\\x06\")`);\n assert(btoa('\\x07'), 'Bw==', `btoa(\"\\\\x07\")`);\n assert(btoa('\\b'), 'CA==', `btoa(\"\\\\b\")`);\n assert(btoa('\\t'), 'CQ==', `btoa(\"\\\\t\")`);\n assert(btoa('\\n'), 'Cg==', `btoa(\"\\\\n\")`);\n assert(btoa('\\v'), 'Cw==', `btoa(\"\\\\v\")`);\n assert(btoa('\\f'), 'DA==', `btoa(\"\\\\f\")`);\n assert(btoa('\\r'), 'DQ==', `btoa(\"\\\\r\")`);\n assert(btoa('\\x0e'), 'Dg==', `btoa(\"\\\\x0e\")`);\n assert(btoa('\\x0f'), 'Dw==', `btoa(\"\\\\x0f\")`);\n assert(btoa('\\x10'), 'EA==', `btoa(\"\\\\x10\")`);\n assert(btoa('\\x11'), 'EQ==', `btoa(\"\\\\x11\")`);\n assert(btoa('\\x12'), 'Eg==', `btoa(\"\\\\x12\")`);\n assert(btoa('\\x13'), 'Ew==', `btoa(\"\\\\x13\")`);\n assert(btoa('\\x14'), 'FA==', `btoa(\"\\\\x14\")`);\n assert(btoa('\\x15'), 'FQ==', `btoa(\"\\\\x15\")`);\n assert(btoa('\\x16'), 'Fg==', `btoa(\"\\\\x16\")`);\n assert(btoa('\\x17'), 'Fw==', `btoa(\"\\\\x17\")`);\n assert(btoa('\\x18'), 'GA==', `btoa(\"\\\\x18\")`);\n assert(btoa('\\x19'), 'GQ==', `btoa(\"\\\\x19\")`);\n assert(btoa('\\x1a'), 'Gg==', `btoa(\"\\\\x1a\")`);\n assert(btoa('\\x1b'), 'Gw==', `btoa(\"\\\\x1b\")`);\n assert(btoa('\\x1c'), 'HA==', `btoa(\"\\\\x1c\")`);\n assert(btoa('\\x1d'), 'HQ==', `btoa(\"\\\\x1d\")`);\n assert(btoa('\\x1e'), 'Hg==', `btoa(\"\\\\x1e\")`);\n assert(btoa('\\x1f'), 'Hw==', `btoa(\"\\\\x1f\")`);\n assert(btoa(' '), 'IA==', `btoa(\" \")`);\n assert(btoa('!'), 'IQ==', `btoa(\"!\")`);\n assert(btoa('#'), 'Iw==', `btoa(\"#\")`);\n assert(btoa('$'), 'JA==', `btoa(\"$\")`);\n assert(btoa('%'), 'JQ==', `btoa(\"%\")`);\n assert(btoa('&'), 'Jg==', `btoa(\"&\")`);\n assert(btoa(\"'\"), 'Jw==', `btoa(\"'\")`);\n assert(btoa('('), 'KA==', `btoa(\"(\")`);\n assert(btoa(')'), 'KQ==', `btoa(\")\")`);\n assert(btoa('*'), 'Kg==', `btoa(\"*\")`);\n assert(btoa('+'), 'Kw==', `btoa(\"+\")`);\n assert(btoa(','), 'LA==', `btoa(\",\")`);\n assert(btoa('-'), 'LQ==', `btoa(\"-\")`);\n assert(btoa('.'), 'Lg==', `btoa(\".\")`);\n assert(btoa('/'), 'Lw==', `btoa(\"/\")`);\n assert(btoa('0'), 'MA==', `btoa(\"0\")`);\n assert(btoa('1'), 'MQ==', `btoa(\"1\")`);\n assert(btoa('2'), 'Mg==', `btoa(\"2\")`);\n assert(btoa('3'), 'Mw==', `btoa(\"3\")`);\n assert(btoa('4'), 'NA==', `btoa(\"4\")`);\n assert(btoa('5'), 'NQ==', `btoa(\"5\")`);\n assert(btoa('6'), 'Ng==', `btoa(\"6\")`);\n assert(btoa('7'), 'Nw==', `btoa(\"7\")`);\n assert(btoa('8'), 'OA==', `btoa(\"8\")`);\n assert(btoa('9'), 'OQ==', `btoa(\"9\")`);\n assert(btoa(':'), 'Og==', `btoa(\":\")`);\n assert(btoa(';'), 'Ow==', `btoa(\";\")`);\n assert(btoa('<'), 'PA==', `btoa(\"<\")`);\n assert(btoa('='), 'PQ==', `btoa(\"=\")`);\n assert(btoa('>'), 'Pg==', `btoa(\">\")`);\n assert(btoa('?'), 'Pw==', `btoa(\"?\")`);\n assert(btoa('@'), 'QA==', `btoa(\"@\")`);\n assert(btoa('A'), 'QQ==', `btoa(\"A\")`);\n assert(btoa('B'), 'Qg==', `btoa(\"B\")`);\n assert(btoa('C'), 'Qw==', `btoa(\"C\")`);\n assert(btoa('D'), 'RA==', `btoa(\"D\")`);\n assert(btoa('E'), 'RQ==', `btoa(\"E\")`);\n assert(btoa('F'), 'Rg==', `btoa(\"F\")`);\n assert(btoa('G'), 'Rw==', `btoa(\"G\")`);\n assert(btoa('H'), 'SA==', `btoa(\"H\")`);\n assert(btoa('I'), 'SQ==', `btoa(\"I\")`);\n assert(btoa('J'), 'Sg==', `btoa(\"J\")`);\n assert(btoa('K'), 'Sw==', `btoa(\"K\")`);\n assert(btoa('L'), 'TA==', `btoa(\"L\")`);\n assert(btoa('M'), 'TQ==', `btoa(\"M\")`);\n assert(btoa('N'), 'Tg==', `btoa(\"N\")`);\n assert(btoa('O'), 'Tw==', `btoa(\"O\")`);\n assert(btoa('P'), 'UA==', `btoa(\"P\")`);\n assert(btoa('Q'), 'UQ==', `btoa(\"Q\")`);\n assert(btoa('R'), 'Ug==', `btoa(\"R\")`);\n assert(btoa('S'), 'Uw==', `btoa(\"S\")`);\n assert(btoa('T'), 'VA==', `btoa(\"T\")`);\n assert(btoa('U'), 'VQ==', `btoa(\"U\")`);\n assert(btoa('V'), 'Vg==', `btoa(\"V\")`);\n assert(btoa('W'), 'Vw==', `btoa(\"W\")`);\n assert(btoa('X'), 'WA==', `btoa(\"X\")`);\n assert(btoa('Y'), 'WQ==', `btoa(\"Y\")`);\n assert(btoa('Z'), 'Wg==', `btoa(\"Z\")`);\n assert(btoa('['), 'Ww==', `btoa(\"[\")`);\n assert(btoa('\\\\'), 'XA==', `btoa(\"\\\\\\\\\")`);\n assert(btoa(']'), 'XQ==', `btoa(\"]\")`);\n assert(btoa('^'), 'Xg==', `btoa(\"^\")`);\n assert(btoa('_'), 'Xw==', `btoa(\"_\")`);\n assert(btoa('a'), 'YQ==', `btoa(\"a\")`);\n assert(btoa('b'), 'Yg==', `btoa(\"b\")`);\n assert(btoa('c'), 'Yw==', `btoa(\"c\")`);\n assert(btoa('d'), 'ZA==', `btoa(\"d\")`);\n assert(btoa('e'), 'ZQ==', `btoa(\"e\")`);\n assert(btoa('f'), 'Zg==', `btoa(\"f\")`);\n assert(btoa('g'), 'Zw==', `btoa(\"g\")`);\n assert(btoa('h'), 'aA==', `btoa(\"h\")`);\n assert(btoa('i'), 'aQ==', `btoa(\"i\")`);\n assert(btoa('j'), 'ag==', `btoa(\"j\")`);\n assert(btoa('k'), 'aw==', `btoa(\"k\")`);\n assert(btoa('l'), 'bA==', `btoa(\"l\")`);\n assert(btoa('m'), 'bQ==', `btoa(\"m\")`);\n assert(btoa('n'), 'bg==', `btoa(\"n\")`);\n assert(btoa('o'), 'bw==', `btoa(\"o\")`);\n assert(btoa('p'), 'cA==', `btoa(\"p\")`);\n assert(btoa('q'), 'cQ==', `btoa(\"q\")`);\n assert(btoa('r'), 'cg==', `btoa(\"r\")`);\n assert(btoa('s'), 'cw==', `btoa(\"s\")`);\n assert(btoa('t'), 'dA==', `btoa(\"t\")`);\n assert(btoa('u'), 'dQ==', `btoa(\"u\")`);\n assert(btoa('v'), 'dg==', `btoa(\"v\")`);\n assert(btoa('w'), 'dw==', `btoa(\"w\")`);\n assert(btoa('x'), 'eA==', `btoa(\"x\")`);\n assert(btoa('y'), 'eQ==', `btoa(\"y\")`);\n assert(btoa('z'), 'eg==', `btoa(\"z\")`);\n assert(btoa('{'), 'ew==', `btoa(\"{\")`);\n assert(btoa('|'), 'fA==', `btoa(\"|\")`);\n assert(btoa('}'), 'fQ==', `btoa(\"}\")`);\n assert(btoa('~'), 'fg==', `btoa(\"~\")`);\n assert(btoa('\u007F'), 'fw==', `btoa(\"\u007F\")`);\n assert(btoa('\u0080'), 'gA==', `btoa(\"\u0080\")`);\n assert(btoa('\u0081'), 'gQ==', `btoa(\"\u0081\")`);\n assert(btoa('\u0082'), 'gg==', `btoa(\"\u0082\")`);\n assert(btoa('\u0083'), 'gw==', `btoa(\"\u0083\")`);\n assert(btoa('\u0084'), 'hA==', `btoa(\"\u0084\")`);\n // eslint-disable-next-line no-irregular-whitespace\n assert(btoa('\u0085'), 'hQ==', `btoa(\"\u0085\")`);\n assert(btoa('\u0086'), 'hg==', `btoa(\"\u0086\")`);\n assert(btoa('\u0087'), 'hw==', `btoa(\"\u0087\")`);\n assert(btoa('\u0088'), 'iA==', `btoa(\"\u0088\")`);\n assert(btoa('\u0089'), 'iQ==', `btoa(\"\u0089\")`);\n assert(btoa('\u008A'), 'ig==', `btoa(\"\u008A\")`);\n assert(btoa('\u008B'), 'iw==', `btoa(\"\u008B\")`);\n assert(btoa('\u008C'), 'jA==', `btoa(\"\u008C\")`);\n assert(btoa('\u008D'), 'jQ==', `btoa(\"\u008D\")`);\n assert(btoa('\u008E'), 'jg==', `btoa(\"\u008E\")`);\n assert(btoa('\u008F'), 'jw==', `btoa(\"\u008F\")`);\n assert(btoa('\u0090'), 'kA==', `btoa(\"\u0090\")`);\n assert(btoa('\u0091'), 'kQ==', `btoa(\"\u0091\")`);\n assert(btoa('\u0092'), 'kg==', `btoa(\"\u0092\")`);\n assert(btoa('\u0093'), 'kw==', `btoa(\"\u0093\")`);\n assert(btoa('\u0094'), 'lA==', `btoa(\"\u0094\")`);\n assert(btoa('\u0095'), 'lQ==', `btoa(\"\u0095\")`);\n assert(btoa('\u0096'), 'lg==', `btoa(\"\u0096\")`);\n assert(btoa('\u0097'), 'lw==', `btoa(\"\u0097\")`);\n assert(btoa('\u0098'), 'mA==', `btoa(\"\u0098\")`);\n assert(btoa('\u0099'), 'mQ==', `btoa(\"\u0099\")`);\n assert(btoa('\u009A'), 'mg==', `btoa(\"\u009A\")`);\n assert(btoa('\u009B'), 'mw==', `btoa(\"\u009B\")`);\n assert(btoa('\u009C'), 'nA==', `btoa(\"\u009C\")`);\n assert(btoa('\u009D'), 'nQ==', `btoa(\"\u009D\")`);\n assert(btoa('\u009E'), 'ng==', `btoa(\"\u009E\")`);\n assert(btoa('\u009F'), 'nw==', `btoa(\"\u009F\")`);\n // eslint-disable-next-line no-irregular-whitespace\n assert(btoa('\u00A0'), 'oA==', `btoa(\"\u00A0\")`);\n assert(btoa('\u00A1'), 'oQ==', `btoa(\"\u00A1\")`);\n assert(btoa('\u00A2'), 'og==', `btoa(\"\u00A2\")`);\n assert(btoa('\u00A3'), 'ow==', `btoa(\"\u00A3\")`);\n assert(btoa('\u00A4'), 'pA==', `btoa(\"\u00A4\")`);\n assert(btoa('\u00A5'), 'pQ==', `btoa(\"\u00A5\")`);\n assert(btoa('\u00A6'), 'pg==', `btoa(\"\u00A6\")`);\n assert(btoa('\u00A7'), 'pw==', `btoa(\"\u00A7\")`);\n assert(btoa('\u00A8'), 'qA==', `btoa(\"\u00A8\")`);\n assert(btoa('\u00A9'), 'qQ==', `btoa(\"\u00A9\")`);\n assert(btoa('\u00AA'), 'qg==', `btoa(\"\u00AA\")`);\n assert(btoa('\u00AB'), 'qw==', `btoa(\"\u00AB\")`);\n assert(btoa('\u00AC'), 'rA==', `btoa(\"\u00AC\")`);\n assert(btoa('\u00AD'), 'rQ==', `btoa(\"\u00AD\")`);\n assert(btoa('\u00AE'), 'rg==', `btoa(\"\u00AE\")`);\n assert(btoa('\u00AF'), 'rw==', `btoa(\"\u00AF\")`);\n assert(btoa('\u00B0'), 'sA==', `btoa(\"\u00B0\")`);\n assert(btoa('\u00B1'), 'sQ==', `btoa(\"\u00B1\")`);\n assert(btoa('\u00B2'), 'sg==', `btoa(\"\u00B2\")`);\n assert(btoa('\u00B3'), 'sw==', `btoa(\"\u00B3\")`);\n assert(btoa('\u00B4'), 'tA==', `btoa(\"\u00B4\")`);\n assert(btoa('\u00B5'), 'tQ==', `btoa(\"\u00B5\")`);\n assert(btoa('\u00B6'), 'tg==', `btoa(\"\u00B6\")`);\n assert(btoa('\u00B7'), 'tw==', `btoa(\"\u00B7\")`);\n assert(btoa('\u00B8'), 'uA==', `btoa(\"\u00B8\")`);\n assert(btoa('\u00B9'), 'uQ==', `btoa(\"\u00B9\")`);\n assert(btoa('\u00BA'), 'ug==', `btoa(\"\u00BA\")`);\n assert(btoa('\u00BB'), 'uw==', `btoa(\"\u00BB\")`);\n assert(btoa('\u00BC'), 'vA==', `btoa(\"\u00BC\")`);\n assert(btoa('\u00BD'), 'vQ==', `btoa(\"\u00BD\")`);\n assert(btoa('\u00BE'), 'vg==', `btoa(\"\u00BE\")`);\n assert(btoa('\u00BF'), 'vw==', `btoa(\"\u00BF\")`);\n assert(btoa('\u00C0'), 'wA==', `btoa(\"\u00C0\")`);\n assert(btoa('\u00C1'), 'wQ==', `btoa(\"\u00C1\")`);\n assert(btoa('\u00C2'), 'wg==', `btoa(\"\u00C2\")`);\n assert(btoa('\u00C3'), 'ww==', `btoa(\"\u00C3\")`);\n assert(btoa('\u00C4'), 'xA==', `btoa(\"\u00C4\")`);\n assert(btoa('\u00C5'), 'xQ==', `btoa(\"\u00C5\")`);\n assert(btoa('\u00C6'), 'xg==', `btoa(\"\u00C6\")`);\n assert(btoa('\u00C7'), 'xw==', `btoa(\"\u00C7\")`);\n assert(btoa('\u00C8'), 'yA==', `btoa(\"\u00C8\")`);\n assert(btoa('\u00C9'), 'yQ==', `btoa(\"\u00C9\")`);\n assert(btoa('\u00CA'), 'yg==', `btoa(\"\u00CA\")`);\n assert(btoa('\u00CB'), 'yw==', `btoa(\"\u00CB\")`);\n assert(btoa('\u00CC'), 'zA==', `btoa(\"\u00CC\")`);\n assert(btoa('\u00CD'), 'zQ==', `btoa(\"\u00CD\")`);\n assert(btoa('\u00CE'), 'zg==', `btoa(\"\u00CE\")`);\n assert(btoa('\u00CF'), 'zw==', `btoa(\"\u00CF\")`);\n assert(btoa('\u00D0'), '0A==', `btoa(\"\u00D0\")`);\n assert(btoa('\u00D1'), '0Q==', `btoa(\"\u00D1\")`);\n assert(btoa('\u00D2'), '0g==', `btoa(\"\u00D2\")`);\n assert(btoa('\u00D3'), '0w==', `btoa(\"\u00D3\")`);\n assert(btoa('\u00D4'), '1A==', `btoa(\"\u00D4\")`);\n assert(btoa('\u00D5'), '1Q==', `btoa(\"\u00D5\")`);\n assert(btoa('\u00D6'), '1g==', `btoa(\"\u00D6\")`);\n assert(btoa('\u00D7'), '1w==', `btoa(\"\u00D7\")`);\n assert(btoa('\u00D8'), '2A==', `btoa(\"\u00D8\")`);\n assert(btoa('\u00D9'), '2Q==', `btoa(\"\u00D9\")`);\n assert(btoa('\u00DA'), '2g==', `btoa(\"\u00DA\")`);\n assert(btoa('\u00DB'), '2w==', `btoa(\"\u00DB\")`);\n assert(btoa('\u00DC'), '3A==', `btoa(\"\u00DC\")`);\n assert(btoa('\u00DD'), '3Q==', `btoa(\"\u00DD\")`);\n assert(btoa('\u00DE'), '3g==', `btoa(\"\u00DE\")`);\n assert(btoa('\u00DF'), '3w==', `btoa(\"\u00DF\")`);\n assert(btoa('\u00E0'), '4A==', `btoa(\"\u00E0\")`);\n assert(btoa('\u00E1'), '4Q==', `btoa(\"\u00E1\")`);\n assert(btoa('\u00E2'), '4g==', `btoa(\"\u00E2\")`);\n assert(btoa('\u00E3'), '4w==', `btoa(\"\u00E3\")`);\n assert(btoa('\u00E4'), '5A==', `btoa(\"\u00E4\")`);\n assert(btoa('\u00E5'), '5Q==', `btoa(\"\u00E5\")`);\n assert(btoa('\u00E6'), '5g==', `btoa(\"\u00E6\")`);\n assert(btoa('\u00E7'), '5w==', `btoa(\"\u00E7\")`);\n assert(btoa('\u00E8'), '6A==', `btoa(\"\u00E8\")`);\n assert(btoa('\u00E9'), '6Q==', `btoa(\"\u00E9\")`);\n assert(btoa('\u00EA'), '6g==', `btoa(\"\u00EA\")`);\n assert(btoa('\u00EB'), '6w==', `btoa(\"\u00EB\")`);\n assert(btoa('\u00EC'), '7A==', `btoa(\"\u00EC\")`);\n assert(btoa('\u00ED'), '7Q==', `btoa(\"\u00ED\")`);\n assert(btoa('\u00EE'), '7g==', `btoa(\"\u00EE\")`);\n assert(btoa('\u00EF'), '7w==', `btoa(\"\u00EF\")`);\n assert(btoa('\u00F0'), '8A==', `btoa(\"\u00F0\")`);\n assert(btoa('\u00F1'), '8Q==', `btoa(\"\u00F1\")`);\n assert(btoa('\u00F2'), '8g==', `btoa(\"\u00F2\")`);\n assert(btoa('\u00F3'), '8w==', `btoa(\"\u00F3\")`);\n assert(btoa('\u00F4'), '9A==', `btoa(\"\u00F4\")`);\n assert(btoa('\u00F5'), '9Q==', `btoa(\"\u00F5\")`);\n assert(btoa('\u00F6'), '9g==', `btoa(\"\u00F6\")`);\n assert(btoa('\u00F7'), '9w==', `btoa(\"\u00F7\")`);\n assert(btoa('\u00F8'), '+A==', `btoa(\"\u00F8\")`);\n assert(btoa('\u00F9'), '+Q==', `btoa(\"\u00F9\")`);\n assert(btoa('\u00FA'), '+g==', `btoa(\"\u00FA\")`);\n assert(btoa('\u00FB'), '+w==', `btoa(\"\u00FB\")`);\n assert(btoa('\u00FC'), '/A==', `btoa(\"\u00FC\")`);\n assert(btoa('\u00FD'), '/Q==', `btoa(\"\u00FD\")`);\n assert(btoa('\u00FE'), '/g==', `btoa(\"\u00FE\")`);\n assert(btoa('\u00FF'), '/w==', `btoa(\"\u00FF\")`);\n }\n\n // atob\n {\n assert(atob(''), '', `atob(\"\")`);\n assert(atob('abcd'), 'i\u00B7\\x1D');\n assert(atob(' abcd'), 'i\u00B7\\x1D');\n assert(atob('abcd '), 'i\u00B7\\x1D');\n assertThrows(() => atob(' abcd==='));\n assertThrows(() => atob('abcd=== '));\n assertThrows(() => atob('abcd ==='));\n assertThrows(() => atob('a'));\n assert(atob('ab'), 'i');\n assert(atob('abc'), 'i\u00B7');\n assertThrows(() => atob('abcde'));\n assertThrows(() => atob('\uD800\uDC00'));\n assertThrows(() => atob('='));\n assertThrows(() => atob('=='));\n assertThrows(() => atob('==='));\n assertThrows(() => atob('===='));\n assertThrows(() => atob('====='));\n assertThrows(() => atob('a='));\n assertThrows(() => atob('a=='));\n assertThrows(() => atob('a==='));\n assertThrows(() => atob('a===='));\n assertThrows(() => atob('a====='));\n assertThrows(() => atob('ab='));\n assert(atob('ab=='), 'i');\n assertThrows(() => atob('ab==='));\n assertThrows(() => atob('ab===='));\n assertThrows(() => atob('ab====='));\n assert(atob('abc='), 'i\u00B7');\n assertThrows(() => atob('abc=='));\n assertThrows(() => atob('abc==='));\n assertThrows(() => atob('abc===='));\n assertThrows(() => atob('abc====='));\n assertThrows(() => atob('abcd='));\n assertThrows(() => atob('abcd=='));\n assertThrows(() => atob('abcd==='));\n assertThrows(() => atob('abcd===='));\n assertThrows(() => atob('abcd====='));\n assertThrows(() => atob('abcde='));\n assertThrows(() => atob('abcde=='));\n assertThrows(() => atob('abcde==='));\n assertThrows(() => atob('abcde===='));\n assertThrows(() => atob('abcde====='));\n assertThrows(() => atob('=a'));\n assertThrows(() => atob('=a='));\n assertThrows(() => atob('a=b'));\n assertThrows(() => atob('a=b='));\n assertThrows(() => atob('ab=c'));\n assertThrows(() => atob('ab=c='));\n assertThrows(() => atob('abc=d'));\n assertThrows(() => atob('abc=d='));\n assertThrows(() => atob('ab\\u000Bcd'));\n assertThrows(() => atob('ab\\u3000cd'));\n assertThrows(() => atob('ab\\u3001cd'));\n assert(atob('ab\\tcd'), 'i\u00B7\\x1D');\n assert(atob('ab\\ncd'), 'i\u00B7\\x1D');\n assert(atob('ab\\fcd'), 'i\u00B7\\x1D');\n assert(atob('ab\\rcd'), 'i\u00B7\\x1D');\n assert(atob('ab cd'), 'i\u00B7\\x1D');\n assertThrows(() => atob('ab\\u00a0cd'));\n assert(atob('ab\\t\\n\\f\\r cd'), 'i\u00B7\\x1D');\n assert(atob(' \\t\\n\\f\\r ab\\t\\n\\f\\r cd\\t\\n\\f\\r '), 'i\u00B7\\x1D');\n assert(atob('ab\\t\\n\\f\\r =\\t\\n\\f\\r =\\t\\n\\f\\r '), 'i');\n assertThrows(() => atob('A'));\n assert(atob('/A'), '\u00FC');\n assert(atob('//A'), '\u00FF\u00F0');\n assert(atob('///A'), '\u00FF\u00FF\u00C0');\n assertThrows(() => atob('////A'));\n assertThrows(() => atob('/'));\n assert(atob('A/'), '\\x03');\n assert(atob('AA/'), '\\x00\\x0F');\n assertThrows(() => atob('AAAA/'));\n assert(atob('AAA/'), '\\x00\\x00?');\n assertThrows(() => atob('\\u0000nonsense'));\n assertThrows(() => atob('abcd\\u0000nonsense'));\n assert(atob('YQ'), 'a');\n assert(atob('YR'), 'a');\n assertThrows(() => atob('~~'));\n assertThrows(() => atob('..'));\n assertThrows(() => atob('--'));\n assertThrows(() => atob('__'));\n }\n});\n", "import { routes } from './routes';\nroutes.set('/byob', () => {\n // eslint-disable-next-line no-undef\n const stream = new ReadableStream({\n type: 'bytes',\n autoAllocateChunkSize: 1024,\n async pull(controller) {\n const view = controller.byobRequest.view;\n view[0] = 104;\n view[1] = 101;\n view[2] = 121;\n view[3] = 51;\n controller.byobRequest.respond(4);\n controller.close();\n },\n });\n return new Response(stream);\n});\n", "export const CacheOverride = globalThis.CacheOverride;", "/* eslint-env serviceworker */\n\nimport { CacheOverride } from 'fastly:cache-override';\nimport { routes } from './routes';\n\nroutes.set('/byte-repeater', () => {\n let headers = new Headers();\n headers.set('AssemblyScriptHeader', 'AssemblyScriptValue');\n\n let streamController;\n let stream = new ReadableStream({\n start: (controller) => {\n streamController = controller;\n },\n });\n let response = new Response(stream, {\n headers,\n });\n\n // Make a request upstream\n let upstreamRequest = new Request(\n 'https://compute-sdk-test-backend.edgecompute.app/byte_repeater',\n );\n upstreamRequest.setCacheOverride(new CacheOverride('pass'));\n fetch(upstreamRequest, {\n backend: 'TheOrigin',\n }).then(async (upstreamResponse) => {\n let body = upstreamResponse.body;\n let streamReader = body.getReader();\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let chunk = await streamReader.read();\n\n // Check if we are done\n if (chunk.done) {\n break;\n }\n\n if (chunk.value.byteLength == 0) {\n continue;\n }\n\n // Otherwise get the byte and repeat them\n let upstreamBytes = chunk.value;\n let downstreamBytes = new Uint8Array(upstreamBytes.length * 2);\n for (let i = 0; i < upstreamBytes.length; i++) {\n let downstreamIndex = i * 2;\n downstreamBytes[downstreamIndex] = upstreamBytes[i];\n downstreamBytes[downstreamIndex + 1] = upstreamBytes[i];\n }\n\n streamController.enqueue(downstreamBytes);\n }\n streamController.close();\n });\n\n // Send downstream (back to the client)\n return response;\n});\n", "import { CacheOverride } from 'fastly:cache-override';\nimport { assert, assertThrows, assertDoesNotThrow } from './assertions.js';\nimport { isRunningLocally, routes } from './routes.js';\n\n// CacheOverride constructor\n{\n routes.set(\n '/cache-override/constructor/called-as-regular-function',\n async () => {\n assertThrows(\n () => {\n CacheOverride();\n },\n TypeError,\n `calling a builtin CacheOverride constructor without new is forbidden`,\n );\n },\n );\n routes.set('/cache-override/constructor/empty-parameter', async () => {\n assertThrows(\n () => {\n new CacheOverride();\n },\n TypeError,\n `CacheOverride constructor: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/cache-override/constructor/invalid-mode', async () => {\n // empty string not allowed\n assertThrows(\n () => {\n new CacheOverride('');\n },\n TypeError,\n `CacheOverride constructor: 'mode' has to be \"none\", \"pass\", or \"override\", but got \"\"`,\n );\n\n assertThrows(\n () => {\n new CacheOverride('be nice to the cache');\n },\n TypeError,\n `CacheOverride constructor: 'mode' has to be \"none\", \"pass\", or \"override\", but got \"be nice to the cache\"`,\n );\n });\n routes.set('/cache-override/constructor/valid-mode', async () => {\n assertDoesNotThrow(() => {\n new CacheOverride('none');\n });\n assertDoesNotThrow(() => {\n new CacheOverride('pass');\n });\n assertDoesNotThrow(() => {\n new CacheOverride('override', {});\n });\n assertDoesNotThrow(() => {\n new CacheOverride({});\n });\n });\n}\n// Using CacheOverride\n{\n routes.set('/cache-override/fetch/mode-none', async () => {\n if (isRunningLocally()) return;\n {\n const response = await fetch('https://http-me.glitch.me/now?status=200', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('none'),\n });\n assert(\n response.headers.has('x-cache'),\n true,\n `CacheOveride('none'); response.headers.has('x-cache') === true`,\n );\n }\n\n {\n const response = await fetch('https://http-me.glitch.me/now?status=200', {\n backend: 'httpme',\n cacheOverride: 'none',\n });\n assert(\n response.headers.has('x-cache'),\n true,\n `CacheOveride('none'); response.headers.has('x-cache') === true`,\n );\n }\n });\n routes.set('/cache-override/fetch/mode-pass', async () => {\n if (isRunningLocally()) return;\n\n {\n const response = await fetch('https://http-me.glitch.me/now?status=200', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('pass'),\n });\n assert(\n response.headers.has('x-cache'),\n false,\n `CacheOveride('pass'); response.headers.has('x-cache') === false`,\n );\n }\n\n {\n const response = await fetch('https://http-me.glitch.me/now?status=200', {\n backend: 'httpme',\n cacheOverride: 'pass',\n });\n assert(\n response.headers.has('x-cache'),\n false,\n `CacheOveride('pass'); response.headers.has('x-cache') === false`,\n );\n }\n });\n}\n", "\nexport const CacheEntry = globalThis.CacheEntry;\nexport const CacheState = globalThis.CacheState;\nexport const CoreCache = globalThis.CoreCache;\nexport const SimpleCache = globalThis.SimpleCache;\nexport const SimpleCacheEntry = globalThis.SimpleCacheEntry;\nexport const TransactionCacheEntry = globalThis.TransactionCacheEntry;\n", "export const FastlyBody = globalThis.FastlyBody;", "/// \n/* eslint-env serviceworker */\n\nimport {\n assert,\n assertDoesNotThrow,\n assertThrows,\n sleep,\n streamToString,\n assertResolves,\n} from './assertions.js';\nimport { routes } from './routes.js';\nimport {\n CoreCache,\n CacheEntry,\n CacheState,\n TransactionCacheEntry,\n} from 'fastly:cache';\nimport { FastlyBody } from 'fastly:body';\n\nfunction iteratableToStream(iterable) {\n return new ReadableStream({\n async pull(controller) {\n for await (const value of iterable) {\n controller.enqueue(value);\n }\n controller.close();\n },\n });\n}\n\nlet createdLion = false;\nfunction ensureLion() {\n if (createdLion) return;\n const writer = CoreCache.insert('lion', {\n maxAge: 600_000,\n });\n writer.append('raar');\n writer.close();\n createdLion = true;\n}\n\n// FastlyBody\n{\n routes.set('/FastlyBody/interface', () => {\n let actual = Reflect.ownKeys(FastlyBody);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(FastlyBody)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody, 'prototype');\n expected = {\n value: FastlyBody.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody, 'name');\n expected = {\n value: 'FastlyBody',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(FastlyBody.prototype);\n expected = [\n 'constructor',\n 'concat',\n 'read',\n 'append',\n 'prepend',\n 'close',\n 'abandon',\n Symbol.toStringTag,\n ];\n assert(actual, expected, `Reflect.ownKeys(FastlyBody.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: FastlyBody.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'constructor')`,\n );\n\n assert(\n typeof FastlyBody.prototype.constructor,\n 'function',\n `typeof FastlyBody.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'FastlyBody',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'FastlyBody',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof FastlyBody.prototype[Symbol.toStringTag],\n 'string',\n `typeof FastlyBody.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the concat method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'concat');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: FastlyBody.prototype.concat,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'concat')`,\n );\n\n assert(\n typeof FastlyBody.prototype.concat,\n 'function',\n `typeof FastlyBody.prototype.concat`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.concat,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.concat, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.concat,\n 'name',\n );\n expected = {\n value: 'concat',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.concat, 'name')`,\n );\n }\n\n // Check the read method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'read');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: FastlyBody.prototype.read,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'read')`,\n );\n\n assert(\n typeof FastlyBody.prototype.read,\n 'function',\n `typeof FastlyBody.prototype.read`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.read,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.read, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.read,\n 'name',\n );\n expected = {\n value: 'read',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.read, 'name')`,\n );\n }\n\n // Check the append method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'append');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: FastlyBody.prototype.append,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'append')`,\n );\n\n assert(\n typeof FastlyBody.prototype.append,\n 'function',\n `typeof FastlyBody.prototype.append`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.append,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.append, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.append,\n 'name',\n );\n expected = {\n value: 'append',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.append, 'name')`,\n );\n }\n\n // Check the prepend method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype,\n 'prepend',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: FastlyBody.prototype.prepend,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'prepend')`,\n );\n\n assert(\n typeof FastlyBody.prototype.prepend,\n 'function',\n `typeof FastlyBody.prototype.prepend`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.prepend,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.prepend, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.prepend,\n 'name',\n );\n expected = {\n value: 'prepend',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.prepend, 'name')`,\n );\n }\n\n // Check the close method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'close');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: FastlyBody.prototype.close,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype, 'close')`,\n );\n\n assert(\n typeof FastlyBody.prototype.close,\n 'function',\n `typeof FastlyBody.prototype.close`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.close,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.close, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n FastlyBody.prototype.close,\n 'name',\n );\n expected = {\n value: 'close',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(FastlyBody.prototype.close, 'name')`,\n );\n }\n });\n\n // constructor\n {\n routes.set('/FastlyBody/constructor/called-as-regular-function', () => {\n assertThrows(() => {\n FastlyBody();\n }, TypeError);\n });\n routes.set('/FastlyBody/constructor/called-as-constructor', () => {\n assertDoesNotThrow(() => new FastlyBody());\n });\n }\n // append(data: BodyInit): void;\n {\n routes.set('/FastlyBody/append/called-as-constructor', () => {\n assertThrows(() => {\n new FastlyBody.append('1');\n }, TypeError);\n });\n routes.set('/FastlyBody/append/data-parameter-not-supplied', () => {\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.append();\n },\n TypeError,\n `append: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/FastlyBody/append/data-parameter-wrong-type', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.append(Symbol());\n });\n });\n // - ReadableStream\n routes.set(\n '/FastlyBody/append/data-parameter-readablestream-guest-backed',\n () => {\n // TODO: update this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n const body = new FastlyBody();\n body.append(stream);\n },\n TypeError,\n `Content-provided streams are not yet supported for appending onto a FastlyBody`,\n );\n },\n );\n routes.set(\n '/FastlyBody/append/data-parameter-readablestream-host-backed',\n async () => {\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n const body = new FastlyBody();\n let result = body.append(res.body);\n assert(result, undefined, `body.append(res.body)`);\n },\n );\n // - URLSearchParams\n routes.set('/FastlyBody/append/data-parameter-URLSearchParams', () => {\n const items = [\n new URLSearchParams(),\n new URLSearchParams({ a: 'b', c: 'd' }),\n ];\n const body = new FastlyBody();\n for (const searchParams of items) {\n let result = body.append(searchParams);\n assert(result, undefined, `await body.append(searchParams)`);\n }\n });\n // - USV strings\n routes.set('/FastlyBody/append/data-parameter-strings', () => {\n const strings = [\n // empty\n '',\n // lone surrogate\n '\\uD800',\n // surrogate pair\n '\uD840\uDE13',\n String('carrot'),\n ];\n const body = new FastlyBody();\n for (const string of strings) {\n let result = body.append(string);\n assert(result, undefined, `body.append(string)`);\n }\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/FastlyBody/append/data-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol();\n const value = {\n toString() {\n throw sentinel;\n },\n };\n const body = new FastlyBody();\n body.append(value);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.append(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n },\n );\n\n // - buffer source\n routes.set('/FastlyBody/append/data-parameter-buffer', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.append(typedArray.buffer);\n assert(result, undefined, `body.append(typedArray.buffer)`);\n }\n });\n routes.set('/FastlyBody/append/data-parameter-arraybuffer', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.append(typedArray.buffer);\n assert(result, undefined, `body.append(typedArray.buffer)`);\n }\n });\n routes.set('/FastlyBody/append/data-parameter-typed-arrays', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.append(typedArray);\n assert(result, undefined, `body.append(typedArray)`);\n }\n });\n routes.set('/FastlyBody/append/data-parameter-dataview', () => {\n const typedArrayConstructors = [\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n const view = new DataView(typedArray.buffer);\n let result = body.append(view);\n assert(result, undefined, `body.append(typedArray)`);\n }\n });\n }\n // prepend(data: BodyInit): void;\n {\n routes.set('/FastlyBody/prepend/called-as-constructor', () => {\n assertThrows(() => {\n new FastlyBody.prepend('1');\n }, TypeError);\n });\n routes.set('/FastlyBody/prepend/data-parameter-not-supplied', () => {\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.prepend();\n },\n TypeError,\n `prepend: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/FastlyBody/prepend/data-parameter-wrong-type', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.prepend(Symbol());\n });\n });\n // - ReadableStream\n routes.set(\n '/FastlyBody/prepend/data-parameter-readablestream-guest-backed',\n () => {\n // TODO: update this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n const body = new FastlyBody();\n body.prepend(stream);\n },\n TypeError,\n `Content-provided streams are not yet supported for prepending onto a FastlyBody`,\n );\n },\n );\n routes.set(\n '/FastlyBody/prepend/data-parameter-readablestream-host-backed',\n async () => {\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n const body = new FastlyBody();\n let result = body.prepend(res.body);\n assert(result, undefined, `body.prepend(res.body)`);\n },\n );\n routes.set(\n '/FastlyBody/prepend/data-parameter-readablestream-locked',\n () => {\n const stream = iteratableToStream([]);\n // getReader() causes the stream to become locked\n stream.getReader();\n const body = new FastlyBody();\n assertThrows(\n () => {\n body.prepend(stream);\n },\n TypeError,\n `Can't use a ReadableStream that's locked or has ever been read from or canceled`,\n );\n },\n );\n\n // - URLSearchParams\n routes.set('/FastlyBody/prepend/data-parameter-URLSearchParams', () => {\n const items = [\n new URLSearchParams(),\n new URLSearchParams({ a: 'b', c: 'd' }),\n ];\n const body = new FastlyBody();\n for (const searchParams of items) {\n let result = body.prepend(searchParams);\n assert(result, undefined, `await body.prepend(searchParams)`);\n }\n });\n // - USV strings\n routes.set('/FastlyBody/prepend/data-parameter-strings', () => {\n const strings = [\n // empty\n '',\n // lone surrogate\n '\\uD800',\n // surrogate pair\n '\uD840\uDE13',\n String('carrot'),\n ];\n const body = new FastlyBody();\n for (const string of strings) {\n let result = body.prepend(string);\n assert(result, undefined, `body.prepend(string)`);\n }\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/FastlyBody/prepend/data-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol();\n const value = {\n toString() {\n throw sentinel;\n },\n };\n const body = new FastlyBody();\n body.prepend(value);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.prepend(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n },\n );\n\n // - buffer source\n routes.set('/FastlyBody/prepend/data-parameter-buffer', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.prepend(typedArray.buffer);\n assert(result, undefined, `body.prepend(typedArray.buffer)`);\n }\n });\n routes.set('/FastlyBody/prepend/data-parameter-arraybuffer', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.prepend(typedArray.buffer);\n assert(result, undefined, `body.prepend(typedArray.buffer)`);\n }\n });\n routes.set('/FastlyBody/prepend/data-parameter-typed-arrays', () => {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = body.prepend(typedArray);\n assert(result, undefined, `body.prepend(typedArray)`);\n }\n });\n routes.set('/FastlyBody/prepend/data-parameter-dataview', () => {\n const typedArrayConstructors = [\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n ];\n const body = new FastlyBody();\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n const view = new DataView(typedArray.buffer);\n let result = body.prepend(view);\n assert(result, undefined, `body.prepend(typedArray)`);\n }\n });\n }\n // concat(dest: FastlyBody): void;\n {\n routes.set('/FastlyBody/concat/called-as-constructor', () => {\n assertThrows(() => {\n new FastlyBody.concat(new FastlyBody());\n }, TypeError);\n });\n routes.set('/FastlyBody/concat/dest-parameter-not-supplied', () => {\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.concat();\n },\n TypeError,\n `concat: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/FastlyBody/concat/dest-parameter-wrong-type', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.concat('hello');\n });\n });\n routes.set('/FastlyBody/concat/concat-same-fastlybody-twice', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n const body2 = new FastlyBody();\n body.concat(body2);\n body.concat(body2);\n });\n });\n routes.set('/FastlyBody/concat/happy-path', () => {\n assertDoesNotThrow(() => {\n const body = new FastlyBody();\n body.concat(new FastlyBody());\n });\n });\n }\n // read(chunkSize: number): ArrayBuffer;\n {\n routes.set('/FastlyBody/read/called-as-constructor', () => {\n assertThrows(() => {\n new FastlyBody.read(1);\n }, TypeError);\n });\n routes.set('/FastlyBody/read/chunkSize-parameter-not-supplied', () => {\n assertThrows(\n () => {\n const body = new FastlyBody();\n body.read();\n },\n TypeError,\n `read: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/FastlyBody/read/chunkSize-parameter-wrong-type', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.read(Symbol());\n });\n });\n // negative\n routes.set('/FastlyBody/read/chunkSize-parameter-negative', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.append('hello world');\n body.read(-1);\n });\n });\n // infinity\n routes.set('/FastlyBody/read/chunkSize-parameter-infinity', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.append('hello world');\n body.read(Infinity);\n });\n });\n // NaN\n routes.set('/FastlyBody/read/chunkSize-parameter-NaN', () => {\n assertThrows(() => {\n const body = new FastlyBody();\n body.append('hello world');\n body.read(NaN);\n });\n });\n routes.set('/FastlyBody/read/happy-path', () => {\n const body = new FastlyBody();\n body.append('world');\n body.prepend('hello ');\n const body2 = new FastlyBody();\n body2.append('!');\n body.concat(body2);\n const decoder = new TextDecoder();\n let result = decoder.decode(body.read(1));\n assert(result, 'h', `body.read(1)`);\n result = decoder.decode(body.read(1));\n assert(result, 'e', `body.read(1)`);\n });\n }\n // close(): void;\n {\n routes.set('/FastlyBody/close/called-as-constructor', () => {\n assertThrows(() => {\n new CoreCache.lookup('1');\n }, TypeError);\n });\n routes.set('/FastlyBody/close/called-once', () => {\n assertThrows(\n () => {\n CoreCache.lookup();\n },\n TypeError,\n `CoreCache.lookup: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/FastlyBody/close/called-twice', () => {\n assertThrows(() => {\n CoreCache.lookup('cat', { headers: '' });\n });\n });\n }\n}\n\n// CoreCache\n{\n routes.set('/core-cache/interface', () => {\n let actual = Reflect.ownKeys(CoreCache);\n let expected = [\n 'prototype',\n 'lookup',\n 'insert',\n 'transactionLookup',\n 'length',\n 'name',\n ];\n assert(actual, expected, `Reflect.ownKeys(CoreCache)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'prototype');\n expected = {\n value: CoreCache.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'name');\n expected = {\n value: 'CoreCache',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(CoreCache.prototype);\n expected = ['constructor', Symbol.toStringTag];\n assert(actual, expected, `Reflect.ownKeys(CoreCache.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: CoreCache.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.prototype, 'constructor')`,\n );\n\n assert(\n typeof CoreCache.prototype.constructor,\n 'function',\n `typeof CoreCache.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'CoreCache',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'CoreCache',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof CoreCache.prototype[Symbol.toStringTag],\n 'string',\n `typeof CoreCache.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the lookup static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'lookup');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CoreCache.lookup,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'lookup')`,\n );\n\n assert(typeof CoreCache.lookup, 'function', `typeof CoreCache.lookup`);\n\n actual = Reflect.getOwnPropertyDescriptor(CoreCache.lookup, 'length');\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.lookup, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(CoreCache.lookup, 'name');\n expected = {\n value: 'lookup',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.lookup, 'name')`,\n );\n }\n\n // Check the insert static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'insert');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CoreCache.insert,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'insert')`,\n );\n\n assert(typeof CoreCache.insert, 'function', `typeof CoreCache.insert`);\n\n actual = Reflect.getOwnPropertyDescriptor(CoreCache.insert, 'length');\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.insert, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(CoreCache.insert, 'name');\n expected = {\n value: 'insert',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.insert, 'name')`,\n );\n }\n\n // Check the transactionLookup static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CoreCache, 'transactionLookup');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CoreCache.transactionLookup,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache, 'transactionLookup')`,\n );\n\n assert(\n typeof CoreCache.transactionLookup,\n 'function',\n `typeof CoreCache.transactionLookup`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.transactionLookup,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.transactionLookup, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CoreCache.transactionLookup,\n 'name',\n );\n expected = {\n value: 'transactionLookup',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CoreCache.transactionLookup, 'name')`,\n );\n }\n });\n\n // CoreCache constructor\n {\n routes.set('/core-cache/constructor/called-as-regular-function', () => {\n assertThrows(() => {\n CoreCache();\n }, TypeError);\n });\n routes.set('/core-cache/constructor/throws', () => {\n assertThrows(() => new CoreCache(), TypeError);\n });\n }\n\n // CoreCache lookup static method\n // static lookup(key: string): CoreCacheEntry | null;\n {\n routes.set('/core-cache/lookup/called-as-constructor', () => {\n assertThrows(() => {\n new CoreCache.lookup('1');\n }, TypeError);\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/core-cache/lookup/key-parameter-calls-7.1.17-ToString', () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n CoreCache.lookup(key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n CoreCache.lookup(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n });\n routes.set('/core-cache/lookup/key-parameter-not-supplied', () => {\n assertThrows(\n () => {\n CoreCache.lookup();\n },\n TypeError,\n `CoreCache.lookup: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/core-cache/lookup/key-parameter-empty-string', () => {\n assertThrows(\n () => {\n CoreCache.lookup('');\n },\n Error,\n `CoreCache.lookup: key can not be an empty string`,\n );\n });\n routes.set('/core-cache/lookup/key-parameter-8135-character-string', () => {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n CoreCache.lookup(key);\n });\n });\n routes.set('/core-cache/lookup/key-parameter-8136-character-string', () => {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n CoreCache.lookup(key);\n },\n Error,\n `CoreCache.lookup: key is too long, the maximum allowed length is 8135.`,\n );\n });\n routes.set('/core-cache/lookup/key-does-not-exist-returns-null', () => {\n let result = CoreCache.lookup(Math.random());\n assert(result, null, `CoreCache.lookup(Math.random()) === null`);\n });\n routes.set('/core-cache/lookup/key-exists', () => {\n let key = 'c'.repeat(8135);\n let writer = CoreCache.insert(key, {\n maxAge: 1000,\n });\n writer.append('meow');\n writer.close();\n let result = CoreCache.lookup(key);\n assert(\n result instanceof CacheEntry,\n true,\n `CoreCache.lookup('cat') instanceof CacheEntry`,\n );\n });\n\n routes.set('/core-cache/lookup/options-parameter-none', () => {\n ensureLion();\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.lookup('lion');\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.lookup('lion', {headers:...}) instanceof CacheEntry`,\n );\n });\n routes.set('/core-cache/lookup/options-parameter-wrong-type', () => {\n ensureLion();\n assertThrows(() => {\n CoreCache.lookup('lion', '');\n });\n });\n routes.set(\n '/core-cache/lookup/options-parameter-headers-field-wrong-type',\n () => {\n ensureLion();\n assertThrows(() => {\n CoreCache.lookup('lion', { headers: '' });\n });\n },\n );\n routes.set(\n '/core-cache/lookup/options-parameter-headers-field-undefined',\n () => {\n ensureLion();\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.lookup('lion', { headers: undefined });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.lookup('lion', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/lookup/options-parameter-headers-field-valid-sequence',\n () => {\n ensureLion();\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.lookup('lion', {\n headers: [\n ['user-agent', 'Aki 1.0'],\n ['Accept-Encoding', 'br'],\n ],\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.lookup('lion', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/lookup/options-parameter-headers-field-valid-record',\n () => {\n ensureLion();\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.lookup('lion', {\n headers: {\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n },\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.lookup('lion', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/lookup/options-parameter-headers-field-valid-Headers-instance',\n () => {\n ensureLion();\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.lookup('lion', {\n headers: new Headers({\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n }),\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.lookup('lion', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n }\n\n // static insert(key: string, options: InsertOptions): FastlyBody;\n {\n routes.set('/core-cache/insert/called-as-constructor', () => {\n assertThrows(() => {\n new CoreCache.insert('1', { maxAge: 1 });\n }, TypeError);\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/core-cache/insert/key-parameter-calls-7.1.17-ToString', () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n CoreCache.insert(key, { maxAge: 1 });\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n CoreCache.insert(Symbol(), { maxAge: 1 });\n },\n TypeError,\n `can't convert symbol to string`,\n );\n });\n routes.set('/core-cache/insert/key-parameter-not-supplied', () => {\n assertThrows(\n () => {\n CoreCache.insert();\n },\n TypeError,\n `CoreCache.insert: At least 2 arguments required, but only 0 passed`,\n );\n });\n routes.set('/core-cache/insert/key-parameter-empty-string', () => {\n assertThrows(\n () => {\n CoreCache.insert('', { maxAge: 1 });\n },\n Error,\n `CoreCache.insert: key can not be an empty string`,\n );\n });\n routes.set('/core-cache/insert/key-parameter-8135-character-string', () => {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n CoreCache.insert(key, { maxAge: 1 });\n });\n });\n routes.set('/core-cache/insert/key-parameter-8136-character-string', () => {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n CoreCache.insert(key, { maxAge: 1 });\n },\n Error,\n `CoreCache.insert: key is too long, the maximum allowed length is 8135.`,\n );\n });\n routes.set('/core-cache/insert/options-parameter-wrong-type', () => {\n assertThrows(() => {\n CoreCache.insert('cat', '');\n });\n });\n routes.set(\n '/core-cache/insert/options-parameter-headers-field-wrong-type',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', { headers: '', maxAge: 1 });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-headers-field-undefined',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', { headers: undefined, maxAge: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {headers:undefined}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-headers-field-valid-sequence',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', {\n headers: [\n ['user-agent', 'Aki 1.0'],\n ['Accept-Encoding', 'br'],\n ],\n maxAge: 1,\n });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {headers:undefined}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-headers-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', {\n headers: {\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n },\n maxAge: 1,\n });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {headers:undefined}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-headers-field-valid-Headers-instance',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', {\n headers: new Headers({\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n }),\n maxAge: 1,\n });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {headers:undefined}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-maxAge-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', { maxAge: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {maxAge: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set('/core-cache/insert/options-parameter-maxAge-field-NaN', () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: NaN,\n });\n });\n });\n routes.set(\n '/core-cache/insert/options-parameter-maxAge-field-postitive-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-maxAge-field-negative-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-maxAge-field-negative-number',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: -1,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-initialAge-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', { maxAge: 1, initialAge: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {maxAge: 1,initialAge: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-initialAge-field-NaN',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n initialAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-initialAge-field-postitive-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n initialAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-initialAge-field-negative-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n initialAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-initialAge-field-negative-number',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n initialAge: -1,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-staleWhileRevalidate-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', {\n maxAge: 1,\n staleWhileRevalidate: 1,\n });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {maxAge: 1,staleWhileRevalidate: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-staleWhileRevalidate-field-NaN',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n staleWhileRevalidate: NaN,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-staleWhileRevalidate-field-postitive-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n staleWhileRevalidate: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-staleWhileRevalidate-field-negative-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n staleWhileRevalidate: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-staleWhileRevalidate-field-negative-number',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n staleWhileRevalidate: -1,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-length-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n body = CoreCache.insert('cat', { maxAge: 1, length: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `CoreCache.insert('cat', {maxAge: 1,length: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set('/core-cache/insert/options-parameter-length-field-NaN', () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n length: NaN,\n });\n });\n });\n routes.set(\n '/core-cache/insert/options-parameter-length-field-postitive-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n length: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-length-field-negative-infinity',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n length: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-length-field-negative-number',\n () => {\n assertThrows(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n length: -1,\n });\n });\n },\n );\n routes.set('/core-cache/insert/options-parameter-sensitive-field', () => {\n assertDoesNotThrow(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n sensitive: true,\n });\n });\n });\n routes.set('/core-cache/insert/options-parameter-vary-field', () => {\n assertDoesNotThrow(() => {\n CoreCache.insert('cat', {\n maxAge: 1,\n vary: ['animal', 'mineral', 'vegetable'],\n });\n });\n });\n routes.set(\n '/core-cache/insert/options-parameter-userMetadata-field/arraybuffer/empty',\n async () => {\n await assertResolves(async () => {\n let key =\n '/core-cache/insert/options-parameter-userMetadata-field/arraybuffer/empty' +\n Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n userMetadata: new ArrayBuffer(0),\n });\n writer.append('hello');\n writer.close();\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-userMetadata-field/arraybuffer/not-empty',\n async () => {\n await assertResolves(async () => {\n let key =\n '/core-cache/insert/options-parameter-userMetadata-field/arraybuffer/not-empty' +\n Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n userMetadata: Uint8Array.from([104, 101, 108, 108, 111]).buffer,\n });\n writer.append('hello');\n writer.close();\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-userMetadata-field/URLSearchParams',\n async () => {\n await assertResolves(async () => {\n let key =\n '/core-cache/insert/options-parameter-userMetadata-field/URLSearchParams' +\n Math.random();\n let userMetadata = new URLSearchParams();\n userMetadata.set('hello', 'world');\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n userMetadata,\n });\n writer.append('hello');\n writer.close();\n });\n },\n );\n routes.set(\n '/core-cache/insert/options-parameter-userMetadata-field/string',\n async () => {\n await assertResolves(async () => {\n let key =\n '/core-cache/insert/options-parameter-userMetadata-field/string' +\n Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n userMetadata: 'hello',\n });\n writer.append('hello');\n writer.close();\n });\n },\n );\n // surrogateKeys?: Array,-- empty string? -- toString which throws -- wrong types?\n }\n\n //static transactionLookup(key: string, options?: LookupOptions): CacheEntry | null;\n {\n routes.set('/core-cache/transactionLookup/called-as-constructor', () => {\n assertThrows(() => {\n new CoreCache.transactionLookup('1');\n }, TypeError);\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/core-cache/transactionLookup/key-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n CoreCache.transactionLookup(key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n CoreCache.transactionLookup(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/key-parameter-not-supplied',\n () => {\n assertThrows(\n () => {\n CoreCache.transactionLookup();\n },\n TypeError,\n `CoreCache.transactionLookup: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/key-parameter-empty-string',\n () => {\n assertThrows(\n () => {\n CoreCache.transactionLookup('');\n },\n Error,\n `CoreCache.transactionLookup: key can not be an empty string`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/key-parameter-8135-character-string',\n () => {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n CoreCache.transactionLookup(key);\n });\n },\n );\n routes.set(\n '/core-cache/transactionLookup/key-parameter-8136-character-string',\n () => {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n CoreCache.transactionLookup(key);\n },\n Error,\n `CoreCache.transactionLookup: key is too long, the maximum allowed length is 8135.`,\n );\n },\n );\n routes.set('/core-cache/transactionLookup/key-does-not-exist', () => {\n let result = CoreCache.transactionLookup(Math.random());\n assert(\n result instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup(Math.random()) instanceof CacheEntry`,\n );\n });\n routes.set('/core-cache/transactionLookup/key-exists', () => {\n let writer = CoreCache.insert('cat', {\n maxAge: 10_000,\n });\n writer.append('meow');\n writer.close();\n let result = CoreCache.transactionLookup('cat');\n assert(\n result instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup('cat') instanceof CacheEntry`,\n );\n });\n\n routes.set(\n '/core-cache/transactionLookup/options-parameter-wrong-type',\n () => {\n assertThrows(() => {\n CoreCache.transactionLookup('cat', '');\n });\n },\n );\n routes.set(\n '/core-cache/transactionLookup/options-parameter-headers-field-wrong-type',\n () => {\n assertThrows(() => {\n CoreCache.transactionLookup('cat', { headers: '' });\n });\n },\n );\n routes.set(\n '/core-cache/transactionLookup/options-parameter-headers-field-undefined',\n () => {\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup('cat', { headers: undefined });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup('cat', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/options-parameter-headers-field-valid-sequence',\n () => {\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup('cat', {\n headers: [\n ['user-agent', 'Aki 1.0'],\n ['Accept-Encoding', 'br'],\n ],\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup('cat', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/options-parameter-headers-field-valid-record',\n () => {\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup('cat', {\n headers: {\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n },\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup('cat', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/core-cache/transactionLookup/options-parameter-headers-field-valid-Headers-instance',\n () => {\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup('cat', {\n headers: new Headers({\n 'user-agent': 'Aki 1.0',\n 'Accept-Encoding': 'br',\n }),\n });\n });\n assert(\n entry instanceof CacheEntry,\n true,\n `CoreCache.transactionLookup('cat', {headers:...}) instanceof CacheEntry`,\n );\n },\n );\n }\n}\n\n// CacheEntry\n{\n routes.set('/cache-entry/interface', () => {\n let actual = Reflect.ownKeys(CacheEntry);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(CacheEntry)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry, 'prototype');\n expected = {\n value: CacheEntry.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry, 'name');\n expected = {\n value: 'CacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(CacheEntry.prototype);\n expected = [\n 'constructor',\n 'close',\n 'state',\n 'userMetadata',\n 'body',\n 'length',\n 'maxAge',\n 'staleWhileRevalidate',\n 'age',\n 'hits',\n Symbol.toStringTag,\n ];\n assert(actual, expected, `Reflect.ownKeys(CacheEntry.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: CacheEntry.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'constructor')`,\n );\n\n assert(\n typeof CacheEntry.prototype.constructor,\n 'function',\n `typeof CacheEntry.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'CacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'CacheEntry',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof CacheEntry.prototype[Symbol.toStringTag],\n 'string',\n `typeof CacheEntry.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the close method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'close');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.close,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'close')`,\n );\n\n assert(\n typeof CacheEntry.prototype.close,\n 'function',\n `typeof CacheEntry.prototype.close`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.close,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.close, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.close,\n 'name',\n );\n expected = {\n value: 'close',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.close, 'name')`,\n );\n }\n\n // Check the state method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'state');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.state,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'state')`,\n );\n\n assert(\n typeof CacheEntry.prototype.state,\n 'function',\n `typeof CacheEntry.prototype.state`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.state,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.state, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.state,\n 'name',\n );\n expected = {\n value: 'state',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.state, 'name')`,\n );\n }\n\n // Check the userMetadata method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype,\n 'userMetadata',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.userMetadata,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'userMetadata')`,\n );\n\n assert(\n typeof CacheEntry.prototype.userMetadata,\n 'function',\n `typeof CacheEntry.prototype.userMetadata`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.userMetadata,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.userMetadata, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.userMetadata,\n 'name',\n );\n expected = {\n value: 'userMetadata',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.userMetadata, 'name')`,\n );\n }\n\n // Check the body method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'body');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.body,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'body')`,\n );\n\n assert(\n typeof CacheEntry.prototype.body,\n 'function',\n `typeof CacheEntry.prototype.body`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.body,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.body, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.body,\n 'name',\n );\n expected = {\n value: 'body',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.body, 'name')`,\n );\n }\n\n // Check the length method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'length');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.length,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'length')`,\n );\n\n assert(\n typeof CacheEntry.prototype.length,\n 'function',\n `typeof CacheEntry.prototype.length`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.length,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.length, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.length,\n 'name',\n );\n expected = {\n value: 'length',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.length, 'name')`,\n );\n }\n\n // Check the maxAge method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'maxAge');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.maxAge,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'maxAge')`,\n );\n\n assert(\n typeof CacheEntry.prototype.maxAge,\n 'function',\n `typeof CacheEntry.prototype.maxAge`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.maxAge,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.maxAge, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.maxAge,\n 'name',\n );\n expected = {\n value: 'maxAge',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.maxAge, 'name')`,\n );\n }\n\n // Check the staleWhileRevalidate method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype,\n 'staleWhileRevalidate',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.staleWhileRevalidate,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'staleWhileRevalidate')`,\n );\n\n assert(\n typeof CacheEntry.prototype.staleWhileRevalidate,\n 'function',\n `typeof CacheEntry.prototype.staleWhileRevalidate`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.staleWhileRevalidate,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.staleWhileRevalidate, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.staleWhileRevalidate,\n 'name',\n );\n expected = {\n value: 'staleWhileRevalidate',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.staleWhileRevalidate, 'name')`,\n );\n }\n\n // Check the age method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'age');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.age,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'age')`,\n );\n\n assert(\n typeof CacheEntry.prototype.age,\n 'function',\n `typeof CacheEntry.prototype.age`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.age,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.age, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.age,\n 'name',\n );\n expected = {\n value: 'age',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.age, 'name')`,\n );\n }\n\n // Check the hits method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'hits');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: CacheEntry.prototype.hits,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype, 'hits')`,\n );\n\n assert(\n typeof CacheEntry.prototype.hits,\n 'function',\n `typeof CacheEntry.prototype.hits`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.hits,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.hits, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n CacheEntry.prototype.hits,\n 'name',\n );\n expected = {\n value: 'hits',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(CacheEntry.prototype.hits, 'name')`,\n );\n }\n });\n\n // CacheEntry constructor\n {\n routes.set('/cache-entry/constructor/called-as-regular-function', () => {\n assertThrows(() => {\n CacheEntry();\n }, TypeError);\n });\n routes.set('/cache-entry/constructor/throws', () => {\n assertThrows(() => new CacheEntry(), TypeError);\n });\n }\n\n // close(): void;\n {\n routes.set('/cache-entry/close/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.close();\n }, TypeError);\n });\n routes.set('/cache-entry/close/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.close.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/close/called-on-instance', () => {\n let key = '/cache-entry/close/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).close();\n assert(result, undefined, `CoreCache.lookup(key).close()`);\n });\n }\n\n // state(): CacheState;\n {\n routes.set('/cache-entry/state/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.state();\n }, TypeError);\n });\n routes.set('/cache-entry/state/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.state.call(undefined);\n }, Error);\n });\n\n routes.set('/cache-entry/state/called-on-instance', () => {\n let key = '/cache-entry/state/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let entry = CoreCache.lookup(key);\n let result = entry.state();\n assert(\n result instanceof CacheState,\n true,\n `CoreCache.lookup(key).state() instanceof CacheState`,\n );\n });\n }\n\n // userMetadata(): ArrayBuffer;\n {\n routes.set('/cache-entry/userMetadata/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.userMetadata();\n }, TypeError);\n });\n routes.set('/cache-entry/userMetadata/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.userMetadata.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/userMetadata/called-on-instance', () => {\n let key = '/cache-entry/userMetadata/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).userMetadata();\n assert(\n result instanceof ArrayBuffer,\n true,\n `CoreCache.lookup(key).userMetadata() instanceof ArrayBuffer`,\n );\n assert(\n result.byteLength,\n 0,\n `CoreCache.lookup(key).userMetadata().byteLength`,\n );\n });\n routes.set('/cache-entry/userMetadata/basic', () => {\n let key = '/cache-entry/userMetadata/basic' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n userMetadata: 'hello world',\n });\n writer.append('hello');\n writer.close();\n let entry = CoreCache.lookup(key);\n assert(\n entry instanceof CacheEntry,\n true,\n 'CoreCache.lookup(key) instanceof CacheEntry',\n );\n let metadata = entry.userMetadata();\n assert(\n metadata instanceof ArrayBuffer,\n true,\n `CoreCache.lookup(key).userMetadata() instanceof ArrayBuffer`,\n );\n assert(\n metadata.byteLength,\n 11,\n `CoreCache.lookup(key).userMetadata().byteLength`,\n );\n let result = new TextDecoder().decode(metadata);\n assert(\n result,\n 'hello world',\n `new TextDecoder().decode(CoreCache.lookup(key).userMetadata()) === 'hello world'`,\n );\n });\n }\n\n // body(options?: CacheBodyOptions): ReadableStream;\n {\n routes.set('/cache-entry/body/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.body();\n }, TypeError);\n });\n routes.set('/cache-entry/body/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.body.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/body/called-on-instance', async () => {\n let key = '/cache-entry/body/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).body();\n assert(\n result instanceof ReadableStream,\n true,\n `CoreCache.lookup(key).body() instanceof ReadableStream`,\n );\n\n result = await streamToString(result);\n assert(\n result,\n 'hello',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n });\n routes.set('/cache-entry/body/options-start-negative', async () => {\n let key = '/cache-entry/body/options-start-negative' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ start: -1 });\n });\n });\n routes.set('/cache-entry/body/options-start-NaN', async () => {\n let key = '/cache-entry/body/options-start-NaN' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ start: NaN });\n });\n });\n routes.set('/cache-entry/body/options-start-Infinity', async () => {\n let key = '/cache-entry/body/options-start-Infinity' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ start: Infinity });\n });\n });\n routes.set('/cache-entry/body/options-start-valid', async () => {\n let key = '/cache-entry/body/options-start-valid' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).body({ start: 1 });\n assert(\n result instanceof ReadableStream,\n true,\n `CoreCache.lookup(key).body() instanceof ReadableStream`,\n );\n\n result = await streamToString(result);\n assert(\n result,\n 'ello',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n });\n routes.set('/cache-entry/body/options-start-longer-than-body', async () => {\n let key =\n '/cache-entry/body/options-start-longer-than-body' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).body({ start: 1000 });\n assert(\n result instanceof ReadableStream,\n true,\n `CoreCache.lookup(key).body() instanceof ReadableStream`,\n );\n\n result = await streamToString(result);\n assert(\n result,\n 'hello',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n });\n routes.set('/cache-entry/body/options-end-negative', async () => {\n let key = '/cache-entry/body/options-end-negative' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ end: -1 });\n });\n });\n routes.set('/cache-entry/body/options-end-NaN', async () => {\n let key = '/cache-entry/body/options-end-NaN' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ end: NaN });\n });\n });\n routes.set('/cache-entry/body/options-end-Infinity', async () => {\n let key = '/cache-entry/body/options-end-Infinity' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n assertThrows(() => {\n CoreCache.lookup(key).body({ end: Infinity });\n });\n });\n routes.set('/cache-entry/body/options-end-valid', async () => {\n let key = '/cache-entry/body/options-end-valid' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).body({ start: 1, end: 1 });\n assert(\n result instanceof ReadableStream,\n true,\n `CoreCache.lookup(key).body() instanceof ReadableStream`,\n );\n\n result = await streamToString(result);\n console.log({ result });\n assert(result, 'e', `await streamToString(CoreCache.lookup(key).body())`);\n });\n routes.set('/cache-entry/body/options-end-zero', async () => {\n let key = '/cache-entry/body/options-end-zero' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).body({ start: 1, end: 0 });\n assert(\n result instanceof ReadableStream,\n true,\n `CoreCache.lookup(key).body() instanceof ReadableStream`,\n );\n\n result = await streamToString(result);\n console.log({ result });\n assert(\n result,\n 'hello',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n });\n }\n\n // length(): number;\n {\n routes.set('/cache-entry/length/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.length();\n }, TypeError);\n });\n routes.set('/cache-entry/length/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.length.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/length/called-on-instance', () => {\n let key = '/cache-entry/length/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).length();\n assert(result, 5, `CoreCache.lookup(key).length()`);\n });\n // TODO pass in an entry with unknown length and then call length and check it is null?\n /// The size in bytes of the cached item, if known.\n ///\n /// The length of the cached item may be unknown if the item is currently being streamed into\n /// the cache without a fixed length.\n }\n\n // maxAge(): number;\n {\n routes.set('/cache-entry/maxAge/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.maxAge();\n }, TypeError);\n });\n routes.set('/cache-entry/maxAge/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.maxAge.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/maxAge/called-on-instance', async () => {\n let key = '/cache-entry/maxAge/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).maxAge();\n assert(result, 60_000, `CoreCache.lookup(key).maxAge()`);\n });\n }\n\n // staleWhileRevalidate(): number;\n {\n routes.set(\n '/cache-entry/staleWhileRevalidate/called-as-constructor',\n () => {\n assertThrows(() => {\n new CacheEntry.prototype.staleWhileRevalidate();\n }, TypeError);\n },\n );\n routes.set('/cache-entry/staleWhileRevalidate/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.staleWhileRevalidate.call(undefined);\n }, Error);\n });\n routes.set(\n '/cache-entry/staleWhileRevalidate/called-on-instance',\n async () => {\n let key =\n '/cache-entry/staleWhileRevalidate/called-on-instance' +\n Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).staleWhileRevalidate();\n assert(\n typeof result,\n 'number',\n `typeof CoreCache.lookup(key).staleWhileRevalidate()`,\n );\n assert(\n result >= 0,\n true,\n `CoreCache.lookup(key).staleWhileRevalidate() >= 0`,\n );\n },\n );\n }\n\n // age(): number;\n {\n routes.set('/cache-entry/age/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.age();\n }, TypeError);\n });\n routes.set('/cache-entry/age/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.age.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/age/called-on-instance', async () => {\n let key = '/cache-entry/age/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).age();\n assert(typeof result, 'number', `typeof CoreCache.lookup(key).age()`);\n assert(result >= 0, true, `CoreCache.lookup(key).age() >= 0`);\n await sleep(1000);\n result = CoreCache.lookup(key).age();\n assert(\n result >= 1_000,\n true,\n `CoreCache.lookup(key).age() >= 1_000 (${result})`,\n );\n });\n }\n\n // hits(): number;\n {\n routes.set('/cache-entry/hits/called-as-constructor', () => {\n assertThrows(() => {\n new CacheEntry.prototype.hits();\n }, TypeError);\n });\n routes.set('/cache-entry/hits/called-unbound', () => {\n assertThrows(() => {\n CacheEntry.prototype.hits.call(undefined);\n }, Error);\n });\n routes.set('/cache-entry/hits/called-on-instance', () => {\n let key = '/cache-entry/hits/called-on-instance' + Math.random();\n let writer = CoreCache.insert(key, {\n maxAge: 60 * 1000,\n });\n writer.append('hello');\n writer.close();\n let result = CoreCache.lookup(key).hits();\n assert(result, 1, `CoreCache.lookup(key).hits()`);\n result = CoreCache.lookup(key).hits();\n assert(result, 2, `CoreCache.lookup(key).hits()`);\n });\n }\n}\n\n// TransactionCacheEntry\n{\n routes.set('/transaction-cache-entry/interface', () => {\n let actual = Reflect.ownKeys(TransactionCacheEntry);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(TransactionCacheEntry)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry,\n 'prototype',\n );\n expected = {\n value: TransactionCacheEntry.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(TransactionCacheEntry, 'name');\n expected = {\n value: 'TransactionCacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(TransactionCacheEntry.prototype);\n expected = [\n 'constructor',\n 'insert',\n 'insertAndStreamBack',\n 'update',\n 'cancel',\n Symbol.toStringTag,\n ];\n assert(\n actual,\n expected,\n `Reflect.ownKeys(TransactionCacheEntry.prototype)`,\n );\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: TransactionCacheEntry.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, 'constructor')`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype.constructor,\n 'function',\n `typeof TransactionCacheEntry.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'TransactionCacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'TransactionCacheEntry',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype[Symbol.toStringTag],\n 'string',\n `typeof TransactionCacheEntry.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the insert method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n 'insert',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: TransactionCacheEntry.prototype.insert,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, 'insert')`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype.insert,\n 'function',\n `typeof TransactionCacheEntry.prototype.insert`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.insert,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.insert, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.insert,\n 'name',\n );\n expected = {\n value: 'insert',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.insert, 'name')`,\n );\n }\n\n // Check the insertAndStreamBack method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n 'insertAndStreamBack',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: TransactionCacheEntry.prototype.insertAndStreamBack,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, 'insertAndStreamBack')`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype.insertAndStreamBack,\n 'function',\n `typeof TransactionCacheEntry.prototype.insertAndStreamBack`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.insertAndStreamBack,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.insertAndStreamBack, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.insertAndStreamBack,\n 'name',\n );\n expected = {\n value: 'insertAndStreamBack',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.insertAndStreamBack, 'name')`,\n );\n }\n\n // Check the update method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n 'update',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: TransactionCacheEntry.prototype.update,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, 'update')`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype.update,\n 'function',\n `typeof TransactionCacheEntry.prototype.update`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.update,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.update, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.update,\n 'name',\n );\n expected = {\n value: 'update',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.update, 'name')`,\n );\n }\n\n // Check the cancel method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype,\n 'cancel',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: TransactionCacheEntry.prototype.cancel,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype, 'cancel')`,\n );\n\n assert(\n typeof TransactionCacheEntry.prototype.cancel,\n 'function',\n `typeof TransactionCacheEntry.prototype.cancel`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.cancel,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.cancel, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n TransactionCacheEntry.prototype.cancel,\n 'name',\n );\n expected = {\n value: 'cancel',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(TransactionCacheEntry.prototype.cancel, 'name')`,\n );\n }\n });\n\n // insert(options: TransactionInsertOptions): FastlyBody;\n {\n routes.set('/transaction-cache-entry/insert/called-as-constructor', () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n new entry.insert({ maxAge: 1 });\n }, TypeError);\n });\n routes.set(\n '/transaction-cache-entry/insert/entry-parameter-not-supplied',\n () => {\n let entry = CoreCache.transactionLookup('1');\n assert(\n entry instanceof TransactionCacheEntry,\n true,\n 'entry instanceof TransactionCacheEntry',\n );\n assertThrows(\n () => {\n entry.insert();\n },\n TypeError,\n `insert: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-maxAge-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n body = entry.insert({ maxAge: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `entry.insert({maxAge: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-maxAge-field-NaN',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-maxAge-field-postitive-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-maxAge-field-negative-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-maxAge-field-negative-number',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-initialAge-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n body = entry.insert({ maxAge: 1, initialAge: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `entry.insert({maxAge: 1,initialAge: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-initialAge-field-NaN',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n initialAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-initialAge-field-postitive-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n initialAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-initialAge-field-negative-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n initialAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-initialAge-field-negative-number',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n initialAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-staleWhileRevalidate-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n body = entry.insert({ maxAge: 1, staleWhileRevalidate: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `entry.insert({maxAge: 1,staleWhileRevalidate: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-staleWhileRevalidate-field-NaN',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n staleWhileRevalidate: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-staleWhileRevalidate-field-postitive-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n staleWhileRevalidate: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-staleWhileRevalidate-field-negative-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n staleWhileRevalidate: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-staleWhileRevalidate-field-negative-number',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n staleWhileRevalidate: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-length-field-valid-record',\n () => {\n let body;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n body = entry.insert({ maxAge: 1, length: 1 });\n });\n assert(\n body instanceof FastlyBody,\n true,\n `entry.insert({maxAge: 1,length: 1}) instanceof FastlyBody`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-length-field-NaN',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n length: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-length-field-postitive-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n length: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-length-field-negative-infinity',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n length: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-length-field-negative-number',\n () => {\n assertThrows(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n length: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-sensitive-field',\n () => {\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n sensitive: true,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insert/options-parameter-vary-field',\n () => {\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup('1');\n entry.insert({\n maxAge: 1,\n vary: ['animal', 'mineral', 'vegetable'],\n });\n });\n },\n );\n }\n\n // insertAndStreamBack(options: TransactionInsertOptions): [FastlyBody, CacheEntry];\n {\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/called-as-constructor',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n new entry.insertAndStreamBack({ maxAge: 1 });\n }, TypeError);\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/entry-parameter-not-supplied',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(\n () => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack();\n },\n TypeError,\n `insertAndStreamBack: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-maxAge-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let writer;\n let reader;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n [writer, reader] = entry.insertAndStreamBack({ maxAge: 1 });\n });\n assert(\n writer instanceof FastlyBody,\n true,\n `writer instanceof FastlyBody`,\n );\n assert(\n reader instanceof CacheEntry,\n true,\n `writer instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-maxAge-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-maxAge-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-maxAge-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-maxAge-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-initialAge-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let writer;\n let reader;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n [writer, reader] = entry.insertAndStreamBack({\n maxAge: 1,\n initialAge: 1,\n });\n });\n assert(\n writer instanceof FastlyBody,\n true,\n `writer instanceof FastlyBody`,\n );\n assert(\n reader instanceof CacheEntry,\n true,\n `writer instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-initialAge-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n initialAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-initialAge-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n initialAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-initialAge-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n initialAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-initialAge-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n initialAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-staleWhileRevalidate-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let writer, reader;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n [writer, reader] = entry.insertAndStreamBack({\n maxAge: 1,\n staleWhileRevalidate: 1,\n });\n });\n assert(\n writer instanceof FastlyBody,\n true,\n `writer instanceof FastlyBody`,\n );\n assert(\n reader instanceof CacheEntry,\n true,\n `writer instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-staleWhileRevalidate-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n staleWhileRevalidate: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-staleWhileRevalidate-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n staleWhileRevalidate: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-staleWhileRevalidate-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n staleWhileRevalidate: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-staleWhileRevalidate-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n staleWhileRevalidate: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-length-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let writer, reader;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n [writer, reader] = entry.insertAndStreamBack({\n maxAge: 1,\n length: 1,\n });\n });\n assert(\n writer instanceof FastlyBody,\n true,\n `writer instanceof FastlyBody`,\n );\n assert(\n reader instanceof CacheEntry,\n true,\n `writer instanceof CacheEntry`,\n );\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-length-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n length: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-length-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n length: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-length-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n length: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-length-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n length: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-sensitive-field',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n sensitive: true,\n });\n });\n },\n );\n\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/write-to-writer-and-read-from-reader',\n async (event) => {\n const path = new URL(event.request.url).pathname;\n let entry = CoreCache.transactionLookup(path);\n let [writer, reader] = entry.insertAndStreamBack({\n maxAge: 60 * 1000,\n sensitive: true,\n });\n writer.append('hello');\n writer.close();\n const actual = await new Response(reader.body()).text();\n assert(actual, 'hello', `actual === \"hello\"`);\n },\n );\n routes.set(\n '/transaction-cache-entry/insertAndStreamBack/options-parameter-vary-field',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.insertAndStreamBack({\n maxAge: 1,\n vary: ['animal', 'mineral', 'vegetable'],\n });\n });\n },\n );\n }\n\n // update(options: TransactionInsertOptions): void;\n {\n routes.set(\n '/transaction-cache-entry/update/called-as-constructor',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n new entry.update({ maxAge: 1 });\n }, TypeError);\n },\n );\n routes.set(\n '/transaction-cache-entry/update/entry-parameter-not-supplied',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(\n () => {\n let entry = CoreCache.transactionLookup(path);\n entry.update();\n },\n TypeError,\n `update: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n\n routes.set(\n '/transaction-cache-entry/update/options-parameter-maxAge-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let writer = CoreCache.insert(path, {\n maxAge: 0,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n let entry = CoreCache.transactionLookup(path);\n entry.update({ maxAge: 1 });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-maxAge-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-maxAge-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-maxAge-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-maxAge-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-initialAge-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let writer = CoreCache.insert(path, {\n maxAge: 0,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n let entry = CoreCache.transactionLookup(path);\n entry.update({ maxAge: 1, initialAge: 1 });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-initialAge-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n initialAge: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-initialAge-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n initialAge: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-initialAge-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n initialAge: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-initialAge-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n initialAge: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-staleWhileRevalidate-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let writer = CoreCache.insert(path, {\n maxAge: 0,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n let entry = CoreCache.transactionLookup(path);\n entry.update({ maxAge: 1, staleWhileRevalidate: 1 });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-staleWhileRevalidate-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n staleWhileRevalidate: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-staleWhileRevalidate-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n staleWhileRevalidate: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-staleWhileRevalidate-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n staleWhileRevalidate: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-staleWhileRevalidate-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n staleWhileRevalidate: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-length-field-valid-record',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let writer = CoreCache.insert(path, {\n maxAge: 0,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n let entry = CoreCache.transactionLookup(path);\n entry.update({ maxAge: 1, length: 1 });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-length-field-NaN',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n length: NaN,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-length-field-postitive-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n length: Number.POSITIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-length-field-negative-infinity',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n length: Number.NEGATIVE_INFINITY,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-length-field-negative-number',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1,\n length: -1,\n });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/write-to-writer-and-read-from-reader',\n async (event) => {\n const path = new URL(event.request.url).pathname;\n let entry = CoreCache.transactionLookup(path);\n let writer = entry.insert({\n maxAge: 1,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 60 * 1000,\n });\n await sleep(1000);\n entry = CoreCache.transactionLookup(path);\n assert(entry.maxAge(), 60 * 1000, `entry2.maxAge() === 60 * 1000`);\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-vary-field',\n async (event) => {\n const path = new URL(event.request.url).pathname;\n let entry = CoreCache.transactionLookup(path);\n let writer = entry.insert({\n maxAge: 1,\n staleWhileRevalidate: 60 * 1000,\n vary: ['animal', 'mineral', 'vegetable'],\n });\n writer.append('meow');\n writer.close();\n await sleep(1000);\n entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1000,\n vary: ['animal'],\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/update/options-parameter-userMetadata-field',\n async (event) => {\n const path = new URL(event.request.url).pathname;\n let entry = CoreCache.transactionLookup(path);\n let writer = entry.insert({\n maxAge: 1,\n staleWhileRevalidate: 60 * 1000,\n });\n writer.append('meow');\n writer.close();\n await sleep(1000);\n entry = CoreCache.transactionLookup(path);\n entry.update({\n maxAge: 1000,\n userMetadata: 'hello',\n });\n },\n );\n // TODO: tests for options parameter fields\n // surrogateKeys?: Array,-- empty string? -- toString which throws -- wrong types?\n }\n\n // cancel(): void;\n {\n routes.set(\n '/transaction-cache-entry/cancel/called-as-constructor',\n (event) => {\n const path = new URL(event.request.url).pathname;\n assertThrows(() => {\n let entry = CoreCache.transactionLookup(path);\n new entry.cancel();\n }, TypeError);\n },\n );\n routes.set('/transaction-cache-entry/cancel/called-once', (event) => {\n const path = new URL(event.request.url).pathname;\n assertDoesNotThrow(() => {\n let entry = CoreCache.transactionLookup(path);\n entry.cancel();\n });\n });\n routes.set(\n '/transaction-cache-entry/cancel/makes-entry-cancelled',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup(path);\n entry.cancel();\n });\n assertThrows(() => {\n entry.insert({ maxAge: 1 });\n });\n },\n );\n routes.set(\n '/transaction-cache-entry/cancel/called-twice-throws',\n (event) => {\n const path = new URL(event.request.url).pathname;\n let entry;\n assertDoesNotThrow(() => {\n entry = CoreCache.transactionLookup(path);\n entry.cancel();\n });\n assertThrows(() => {\n entry.cancel();\n });\n },\n );\n }\n}\n\n{\n routes.set(\n '/core-cache/transaction-lookup-transaction-insert-vary-works',\n async () => {\n const key = `/core-cache/vary-works-${Date.now()}`;\n const animal = 'animal';\n let entry = CoreCache.transactionLookup(key, {\n headers: {\n [animal]: 'cat',\n },\n });\n assert(entry.state().found(), false, `entry.state().found() === false`);\n let writer = entry.insert({\n maxAge: 60_000 * 60,\n vary: [animal],\n headers: {\n [animal]: 'cat',\n },\n });\n\n writer.append('cat');\n writer.close();\n entry.close();\n await sleep(1_000);\n\n entry = CoreCache.transactionLookup(key, {\n headers: {\n [animal]: 'cat',\n },\n });\n assert(entry.state().found(), true, `entry.state().found() === true`);\n\n assert(\n await streamToString(entry.body()),\n 'cat',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n entry.close();\n\n entry = CoreCache.transactionLookup(key, {\n headers: {\n [animal]: 'dog',\n },\n });\n assert(entry.state().found(), false, `entry.state().found() == false`);\n\n writer = entry.insert({\n maxAge: 60_000 * 60,\n vary: [animal],\n headers: {\n [animal]: 'dog',\n },\n });\n\n writer.append('dog');\n writer.close();\n entry.close();\n await sleep(1_000);\n\n entry = CoreCache.transactionLookup(key, {\n headers: {\n [animal]: 'dog',\n },\n });\n assert(entry.state().found(), true, `entry.state().found() === true`);\n\n assert(\n await streamToString(entry.body()),\n 'dog',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n entry.close();\n },\n );\n\n routes.set('/core-cache/lookup-insert-vary-works', async () => {\n const key = `/core-cache/vary-works-${Date.now()}`;\n const animal = 'animal';\n let entry = CoreCache.lookup(key, {\n headers: {\n [animal]: 'cat',\n },\n });\n assert(entry, null, `entry == null`);\n let writer = CoreCache.insert(key, {\n maxAge: 60_000 * 60,\n vary: [animal],\n headers: {\n [animal]: 'cat',\n },\n });\n\n writer.append('cat');\n writer.close();\n await sleep(1_000);\n\n entry = CoreCache.lookup(key, {\n headers: {\n [animal]: 'cat',\n },\n });\n assert(entry.state().found(), true, `entry.state().found() === true`);\n\n assert(\n await streamToString(entry.body()),\n 'cat',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n entry.close();\n\n entry = CoreCache.lookup(key, {\n headers: {\n [animal]: 'dog',\n },\n });\n assert(entry, null, `entry == null`);\n\n writer = CoreCache.insert(key, {\n maxAge: 60_000 * 60,\n vary: [animal],\n headers: {\n [animal]: 'dog',\n },\n });\n\n writer.append('dog');\n writer.close();\n await sleep(1_000);\n\n entry = CoreCache.lookup(key, {\n headers: {\n [animal]: 'dog',\n },\n });\n assert(entry.state().found(), true, `entry.state().found() === true`);\n\n assert(\n await streamToString(entry.body()),\n 'dog',\n `await streamToString(CoreCache.lookup(key).body())`,\n );\n });\n}\n", "/// \n/* eslint-env serviceworker */\n\nimport {\n assert,\n assertDoesNotThrow,\n assertThrows,\n assertRejects,\n iteratableToStream,\n streamToString,\n assertResolves,\n} from './assertions.js';\nimport { SimpleCache, SimpleCacheEntry } from 'fastly:cache';\nimport { routes, isRunningLocally } from './routes.js';\n\nroutes.set('/simple-cache/interface', () => {\n let actual = Reflect.ownKeys(SimpleCache);\n let expected = [\n 'prototype',\n 'purge',\n 'get',\n 'getOrSet',\n 'set',\n 'length',\n 'name',\n ];\n assert(actual, expected, `Reflect.ownKeys(SimpleCache)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'prototype');\n expected = {\n value: SimpleCache.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'name');\n expected = {\n value: 'SimpleCache',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(SimpleCache.prototype);\n expected = ['constructor', Symbol.toStringTag];\n assert(actual, expected, `Reflect.ownKeys(SimpleCache.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCache.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: SimpleCache.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.prototype, 'constructor')`,\n );\n\n assert(\n typeof SimpleCache.prototype.constructor,\n 'function',\n `typeof SimpleCache.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCache.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCache.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'SimpleCache',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCache.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'SimpleCache',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof SimpleCache.prototype[Symbol.toStringTag],\n 'string',\n `typeof SimpleCache.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the get static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'get');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCache.get,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'get')`,\n );\n\n assert(typeof SimpleCache.get, 'function', `typeof SimpleCache.get`);\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.get, 'length');\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.get, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.get, 'name');\n expected = {\n value: 'get',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.get, 'name')`,\n );\n }\n\n // Check the set static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'set');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCache.set,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'set')`,\n );\n\n assert(typeof SimpleCache.set, 'function', `typeof SimpleCache.set`);\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.set, 'length');\n expected = {\n value: 3,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.set, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.set, 'name');\n expected = {\n value: 'set',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.set, 'name')`,\n );\n }\n\n // Check the purge static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'purge');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCache.purge,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'purge')`,\n );\n\n assert(typeof SimpleCache.purge, 'function', `typeof SimpleCache.purge`);\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.purge, 'length');\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.purge, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.purge, 'name');\n expected = {\n value: 'purge',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.purge, 'name')`,\n );\n }\n\n // Check the getOrSet static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache, 'getOrSet');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCache.getOrSet,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache, 'getOrSet')`,\n );\n\n assert(\n typeof SimpleCache.getOrSet,\n 'function',\n `typeof SimpleCache.getOrSet`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.getOrSet, 'length');\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.getOrSet, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCache.getOrSet, 'name');\n expected = {\n value: 'getOrSet',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCache.getOrSet, 'name')`,\n );\n }\n});\n\n// SimpleCache constructor\n{\n routes.set('/simple-store/constructor/called-as-regular-function', () => {\n assertThrows(() => {\n SimpleCache();\n }, TypeError);\n });\n routes.set('/simple-cache/constructor/throws', () => {\n assertThrows(() => new SimpleCache(), TypeError);\n });\n}\n\n// SimpleCache purge static method\n// static purge(key: string, options: PurgeOptions): undefined;\n{\n routes.set('/simple-cache/purge/called-as-constructor', () => {\n if (!isRunningLocally()) {\n assertThrows(() => {\n new SimpleCache.purge('1', { scope: 'global' });\n }, TypeError);\n }\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/simple-cache/purge/key-parameter-calls-7.1.17-ToString', () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n SimpleCache.purge(key, { scope: 'global' });\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n SimpleCache.purge(Symbol(), { scope: 'global' });\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n });\n routes.set('/simple-cache/purge/key-parameter-not-supplied', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.purge();\n },\n TypeError,\n `SimpleCache.purge: At least 2 arguments required, but only 0 passed`,\n );\n }\n });\n routes.set('/simple-cache/purge/key-parameter-empty-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.purge('', { scope: 'global' });\n },\n Error,\n `SimpleCache.purge: key can not be an empty string`,\n );\n }\n });\n routes.set('/simple-cache/purge/key-parameter-8135-character-string', () => {\n if (!isRunningLocally()) {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n SimpleCache.purge(key, { scope: 'global' });\n });\n }\n });\n routes.set('/simple-cache/purge/key-parameter-8136-character-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n SimpleCache.purge(key, { scope: 'global' });\n },\n Error,\n `SimpleCache.purge: key is too long, the maximum allowed length is 8135.`,\n );\n }\n });\n routes.set('/simple-cache/purge/options-parameter', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n const key = 'a';\n SimpleCache.purge(key, 'hello');\n },\n Error,\n `SimpleCache.purge: options parameter is not an object.`,\n );\n assertThrows(\n () => {\n const key = 'a';\n SimpleCache.purge(key, { scope: Symbol() });\n },\n Error,\n `can't convert symbol to string`,\n );\n assertThrows(\n () => {\n const key = 'a';\n SimpleCache.purge(key, { scope: '' });\n },\n Error,\n `SimpleCache.purge: scope field of options parameter must be either 'pop', or 'global'.`,\n );\n assertDoesNotThrow(() => {\n const key = 'a';\n SimpleCache.purge(key, { scope: 'pop' });\n });\n assertDoesNotThrow(() => {\n const key = 'a';\n SimpleCache.purge(key, { scope: 'global' });\n });\n }\n });\n routes.set('/simple-cache/purge/returns-undefined', () => {\n if (!isRunningLocally()) {\n assert(\n SimpleCache.purge('meow', { scope: 'global' }),\n undefined,\n \"SimpleCache.purge('meow', {scope'global'})\",\n );\n }\n });\n}\n\n// SimpleCache set static method\n// static set(key: string, value: BodyInit, ttl: number): undefined;\n{\n routes.set('/simple-cache/set/called-as-constructor', () => {\n if (!isRunningLocally()) {\n assertThrows(() => {\n new SimpleCache.set('1', 'meow', 1);\n }, TypeError);\n }\n });\n // Ensure we correctly coerce the key parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/simple-cache/set/key-parameter-calls-7.1.17-ToString', () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n SimpleCache.set(key, 'meow', 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n SimpleCache.set(Symbol(), 'meow', 1);\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n });\n // Ensure we correctly coerce the tll parameter to a number as according to\n // https://tc39.es/ecma262/#sec-tonumber\n routes.set('/simple-cache/set/tll-parameter-7.1.4-ToNumber', () => {\n if (!isRunningLocally()) {\n let sentinel;\n let requestedType;\n const test = () => {\n sentinel = Symbol('sentinel');\n const ttl = {\n [Symbol.toPrimitive](type) {\n requestedType = type;\n throw sentinel;\n },\n };\n SimpleCache.set('1', 'meow', ttl);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n assert(requestedType, 'number', 'requestedType === \"number\"');\n }\n assertThrows(\n () => SimpleCache.set('1', 'meow', Symbol()),\n TypeError,\n `can't convert symbol to number`,\n );\n }\n });\n routes.set('/simple-cache/set/no-parameters-supplied', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.set();\n },\n TypeError,\n `SimpleCache.set: At least 3 arguments required, but only 0 passed`,\n );\n }\n });\n routes.set('/simple-cache/set/key-parameter-empty-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.set('', 'meow', 1);\n },\n Error,\n `SimpleCache.set: key can not be an empty string`,\n );\n }\n });\n routes.set('/simple-cache/set/key-parameter-8135-character-string', () => {\n if (!isRunningLocally()) {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n SimpleCache.set(key, 'meow', 1);\n });\n }\n });\n routes.set('/simple-cache/set/key-parameter-8136-character-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n SimpleCache.set(key, 'meow', 1);\n },\n Error,\n `SimpleCache.set: key is too long, the maximum allowed length is 8135.`,\n );\n }\n });\n routes.set('/simple-cache/set/ttl-parameter-negative-number', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.set('cat', 'meow', -1);\n },\n Error,\n `SimpleCache.set: TTL parameter is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/set/ttl-parameter-NaN', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.set('cat', 'meow', NaN);\n },\n Error,\n `SimpleCache.set: TTL parameter is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/set/ttl-parameter-Infinity', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.set('cat', 'meow', Number.POSITIVE_INFINITY);\n },\n Error,\n `SimpleCache.set: TTL parameter is an invalid value, only positive numbers can be used for TTL values.`,\n );\n assertThrows(\n () => {\n SimpleCache.set('cat', 'meow', Number.NEGATIVE_INFINITY);\n },\n Error,\n `SimpleCache.set: TTL parameter is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/set/value-parameter-as-undefined', () => {\n if (!isRunningLocally()) {\n assert(\n SimpleCache.set('meow', undefined, 1),\n undefined,\n 'SimpleCache.set(\"meow\", undefined, 1) === undefined',\n );\n }\n });\n // - ReadableStream\n routes.set(\n '/simple-cache/set/value-parameter-readablestream-missing-length-parameter',\n () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/set/value-parameter-readablestream-negative-length-parameter',\n () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1, -1);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/set/value-parameter-readablestream-nan-length-parameter',\n () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1, NaN);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/set/value-parameter-readablestream-negative-infinity-length-parameter',\n () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1, Number.NEGATIVE_INFINITY);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/set/value-parameter-readablestream-positive-infinity-length-parameter',\n () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1, Number.POSITIVE_INFINITY);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n // Ensure we correctly coerce the tll parameter to a number as according to\n // https://tc39.es/ecma262/#sec-tonumber\n routes.set('/simple-cache/set/length-parameter-7.1.4-ToNumber', async () => {\n if (!isRunningLocally()) {\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n let sentinel;\n let requestedType;\n const test = () => {\n sentinel = Symbol('sentinel');\n const length = {\n [Symbol.toPrimitive](type) {\n requestedType = type;\n throw sentinel;\n },\n };\n SimpleCache.set('1', res.body, 1, length);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n assert(requestedType, 'number', 'requestedType === \"number\"');\n }\n assertThrows(\n () => SimpleCache.set('1', res.body, 1, Symbol()),\n TypeError,\n `can't convert symbol to number`,\n );\n }\n });\n routes.set('/simple-cache/set/value-parameter-readablestream-empty', () => {\n if (!isRunningLocally()) {\n // TODO: remove this when streams are supported\n assertThrows(\n () => {\n const stream = iteratableToStream([]);\n SimpleCache.set('meow', stream, 1, 0);\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n });\n routes.set('/simple-cache/set/value-parameter-readablestream-locked', () => {\n if (!isRunningLocally()) {\n const stream = iteratableToStream([]);\n // getReader() causes the stream to become locked\n stream.getReader();\n assertThrows(\n () => {\n SimpleCache.set('meow', stream, 1, 0);\n },\n TypeError,\n `Can't use a ReadableStream that's locked or has ever been read from or canceled`,\n );\n }\n });\n routes.set('/simple-cache/set/value-parameter-readablestream', async () => {\n if (!isRunningLocally()) {\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n let result = SimpleCache.set(\n 'readablestream',\n res.body,\n 100,\n res.headers.get('content-length'),\n );\n assert(\n result,\n undefined,\n `SimpleCache.set('readablestream', res.body, 100)`,\n );\n }\n });\n\n // - URLSearchParams\n routes.set('/simple-cache/set/value-parameter-URLSearchParams', () => {\n if (!isRunningLocally()) {\n const items = [\n new URLSearchParams(),\n new URLSearchParams({ a: 'b', c: 'd' }),\n ];\n for (const searchParams of items) {\n let result = SimpleCache.set('meow', searchParams, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", searchParams, 1) === undefiend`,\n );\n }\n }\n });\n // - USV strings\n routes.set('/simple-cache/set/value-parameter-strings', () => {\n if (!isRunningLocally()) {\n const strings = [\n // empty\n '',\n // lone surrogate\n '\\uD800',\n // surrogate pair\n '\uD840\uDE13',\n String('carrot'),\n ];\n for (const string of strings) {\n let result = SimpleCache.set('meow', string, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", string, 1) === undefined`,\n );\n }\n }\n });\n\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/simple-cache/set/value-parameter-calls-7.1.17-ToString', () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const value = {\n toString() {\n throw sentinel;\n },\n };\n SimpleCache.set('meow', value, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n SimpleCache.set('meow', Symbol(), 1);\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n });\n\n // - buffer source\n routes.set('/simple-cache/set/value-parameter-buffer', () => {\n if (!isRunningLocally()) {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = SimpleCache.set('meow', typedArray.buffer, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", typedArray.buffer, 1) === undefined`,\n );\n }\n }\n });\n routes.set('/simple-cache/set/value-parameter-arraybuffer', () => {\n if (!isRunningLocally()) {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = SimpleCache.set('meow', typedArray.buffer, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", typedArray.buffer, 1) === undefined`,\n );\n }\n }\n });\n routes.set('/simple-cache/set/value-parameter-typed-arrays', () => {\n if (!isRunningLocally()) {\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n let result = SimpleCache.set('meow', typedArray, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", typedArray, 1) === undefined`,\n );\n }\n }\n });\n routes.set('/simple-cache/set/value-parameter-dataview', () => {\n if (!isRunningLocally()) {\n const typedArrayConstructors = [\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n const view = new DataView(typedArray.buffer);\n let result = SimpleCache.set('meow', view, 1);\n assert(\n result,\n undefined,\n `SimpleCache.set(\"meow\", view, 1) === undefined`,\n );\n }\n }\n });\n routes.set('/simple-cache/set/returns-undefined', () => {\n if (!isRunningLocally()) {\n assert(\n SimpleCache.set('1', 'meow', 1),\n undefined,\n \"SimpleCache.set('1', 'meow', 1) === undefined\",\n );\n }\n });\n}\n\n// SimpleCache get static method\n// static get(key: string): SimpleCacheEntry | null;\n{\n routes.set('/simple-cache/get/called-as-constructor', () => {\n if (!isRunningLocally()) {\n assertThrows(() => {\n new SimpleCache.get('1');\n }, TypeError);\n }\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/simple-cache/get/key-parameter-calls-7.1.17-ToString', () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const key = {\n toString() {\n throw sentinel;\n },\n };\n SimpleCache.get(key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n SimpleCache.get(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n });\n routes.set('/simple-cache/get/key-parameter-not-supplied', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.get();\n },\n TypeError,\n `SimpleCache.get: At least 1 argument required, but only 0 passed`,\n );\n }\n });\n routes.set('/simple-cache/get/key-parameter-empty-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n SimpleCache.get('');\n },\n Error,\n `SimpleCache.get: key can not be an empty string`,\n );\n }\n });\n routes.set('/simple-cache/get/key-parameter-8135-character-string', () => {\n if (!isRunningLocally()) {\n assertDoesNotThrow(() => {\n const key = 'a'.repeat(8135);\n SimpleCache.get(key);\n });\n }\n });\n routes.set('/simple-cache/get/key-parameter-8136-character-string', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n const key = 'a'.repeat(8136);\n SimpleCache.get(key);\n },\n Error,\n `SimpleCache.get: key is too long, the maximum allowed length is 8135.`,\n );\n }\n });\n routes.set('/simple-cache/get/key-does-not-exist-returns-null', () => {\n if (!isRunningLocally()) {\n let result = SimpleCache.get(Math.random());\n assert(result, null, `SimpleCache.get(Math.random()) === null`);\n }\n });\n routes.set('/simple-cache/get/key-exists', () => {\n if (!isRunningLocally()) {\n SimpleCache.set('cat', 'meow', 100);\n let result = SimpleCache.get('cat');\n assert(\n result instanceof SimpleCacheEntry,\n true,\n `SimpleCache.get('cat') instanceof SimpleCacheEntry`,\n );\n }\n });\n}\n\n// SimpleCacheEntry\n{\n routes.set('/simple-cache-entry/interface', async () => {\n return simpleCacheEntryInterfaceTests();\n });\n routes.set('/simple-cache-entry/text/valid', async () => {\n if (!isRunningLocally()) {\n let key = `entry-text-valid`;\n SimpleCache.set(key, 'hello', 100);\n let entry = SimpleCache.get(key);\n let result = entry.text();\n assert(\n result instanceof Promise,\n true,\n `entry.text() instanceof Promise`,\n );\n result = await result;\n assert(result, 'hello', `await entry.text()`);\n }\n });\n routes.set('/simple-cache-entry/json/valid', async () => {\n if (!isRunningLocally()) {\n let key = `entry-json-valid`;\n const obj = { a: 1, b: 2, c: 3 };\n SimpleCache.set(key, JSON.stringify(obj), 100);\n let entry = SimpleCache.get(key);\n let result = entry.json();\n assert(\n result instanceof Promise,\n true,\n `entry.json() instanceof Promise`,\n );\n result = await result;\n assert(result, obj, `await entry.json()`);\n }\n });\n routes.set('/simple-cache-entry/json/invalid', async () => {\n if (!isRunningLocally()) {\n let key = `entry-json-invalid`;\n SimpleCache.set(key, \"132abc;['-=9\", 100);\n let entry = SimpleCache.get(key);\n await assertRejects(\n () => entry.json(),\n SyntaxError,\n `JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 4 of the JSON data`,\n );\n }\n });\n routes.set('/simple-cache-entry/arrayBuffer/valid', async () => {\n if (!isRunningLocally()) {\n let key = `entry-arraybuffer-valid`;\n SimpleCache.set(key, new Int8Array([0, 1, 2, 3]), 100);\n let entry = SimpleCache.get(key);\n let result = entry.arrayBuffer();\n assert(\n result instanceof Promise,\n true,\n `entry.arrayBuffer() instanceof Promise`,\n );\n result = await result;\n assert(\n result instanceof ArrayBuffer,\n true,\n `(await entry.arrayBuffer()) instanceof ArrayBuffer`,\n );\n }\n });\n routes.set('/simple-cache-entry/body', async () => {\n if (!isRunningLocally()) {\n let key = `entry-body`;\n SimpleCache.set(key, 'body body body', 100);\n let entry = SimpleCache.get(key);\n let result = entry.body;\n assert(\n result instanceof ReadableStream,\n true,\n `entry.body instanceof ReadableStream`,\n );\n let text = await streamToString(result);\n assert(text, 'body body body', `entry.body contents as string`);\n }\n });\n routes.set('/simple-cache-entry/bodyUsed', async () => {\n if (!isRunningLocally()) {\n let key = `entry-bodyUsed`;\n SimpleCache.set(key, 'body body body', 100);\n let entry = SimpleCache.get(key);\n assert(entry.bodyUsed, false, `entry.bodyUsed`);\n await entry.text();\n assert(entry.bodyUsed, true, `entry.bodyUsed`);\n }\n });\n routes.set('/simple-cache-entry/readablestream', async () => {\n if (!isRunningLocally()) {\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n let key = `readablestream`;\n SimpleCache.set(key, res.body, 100, res.headers.get('content-length'));\n let entry = SimpleCache.get(key);\n assert(\n await entry.text(),\n 'Compute SDK Test Backend',\n `await entry.text()`,\n );\n }\n });\n}\nasync function simpleCacheEntryInterfaceTests() {\n let actual = Reflect.ownKeys(SimpleCacheEntry);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(SimpleCacheEntry)`);\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'prototype');\n expected = {\n value: SimpleCacheEntry.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'prototype')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'name');\n expected = {\n value: 'SimpleCacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry, 'name')`,\n );\n\n actual = Reflect.ownKeys(SimpleCacheEntry.prototype);\n expected = [\n 'constructor',\n 'body',\n 'bodyUsed',\n 'arrayBuffer',\n 'json',\n 'text',\n Symbol.toStringTag,\n ];\n assert(actual, expected, `Reflect.ownKeys(SimpleCacheEntry.prototype)`);\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: SimpleCacheEntry.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'constructor')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'text');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCacheEntry.prototype.text,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'text')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'json');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCacheEntry.prototype.json,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'json')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype,\n 'arrayBuffer',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: SimpleCacheEntry.prototype.arrayBuffer,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'arrayBuffer')`,\n );\n actual = Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body');\n assert(\n actual.enumerable,\n true,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body').enumerable`,\n );\n assert(\n actual.configurable,\n true,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body').configurable`,\n );\n assert(\n 'set' in actual,\n true,\n `'set' in Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body')`,\n );\n assert(\n actual.set,\n undefined,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body').set`,\n );\n assert(\n typeof actual.get,\n 'function',\n `typeof Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'body').get`,\n );\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype,\n 'bodyUsed',\n );\n assert(\n actual.enumerable,\n true,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'bodyUsed').enumerable`,\n );\n assert(\n actual.configurable,\n true,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'bodyUsed').configurable`,\n );\n assert(\n 'set' in actual,\n true,\n `'set' in Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'bodyUsed')`,\n );\n assert(\n actual.set,\n undefined,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'bodyUsed').set`,\n );\n assert(\n typeof actual.get,\n 'function',\n `typeof Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype, 'bodyUsed').get`,\n );\n\n assert(\n typeof SimpleCacheEntry.prototype.constructor,\n 'function',\n `typeof SimpleCacheEntry.prototype.constructor`,\n );\n assert(\n typeof SimpleCacheEntry.prototype.text,\n 'function',\n `typeof SimpleCacheEntry.prototype.text`,\n );\n assert(\n typeof SimpleCacheEntry.prototype.json,\n 'function',\n `typeof SimpleCacheEntry.prototype.json`,\n );\n assert(\n typeof SimpleCacheEntry.prototype.arrayBuffer,\n 'function',\n `typeof SimpleCacheEntry.prototype.arrayBuffer`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'SimpleCacheEntry',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.constructor, 'name')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.text,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.text, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.text,\n 'name',\n );\n expected = {\n value: 'text',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.text, 'name')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.json,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.json, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.json,\n 'name',\n );\n expected = {\n value: 'json',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.json, 'name')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.arrayBuffer,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.arrayBuffer, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n SimpleCacheEntry.prototype.arrayBuffer,\n 'name',\n );\n expected = {\n value: 'arrayBuffer',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(SimpleCacheEntry.prototype.arrayBuffer, 'name')`,\n );\n}\n\n// SimpleCache getOrSet static method\n// static getOrSet(key: string, set: () => Promise<{value: BodyInit, ttl: number}>): Promise;\n// static getOrSet(key: string, set: () => Promise<{value: ReadableStream, ttl: number, length: number}>): Promise;\n{\n routes.set('/simple-cache/getOrSet/rejection-rejects-outer', async () => {\n if (!isRunningLocally()) {\n let key = String(Math.random());\n SimpleCache.get(key);\n assertRejects(\n () =>\n SimpleCache.getOrSet(key, async () => {\n throw RangeError('inner rejection');\n }),\n RangeError,\n 'inner rejection',\n );\n }\n });\n\n routes.set('/simple-cache/getOrSet/called-as-constructor', () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/called-as-constructor';\n assertThrows(() => {\n new SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n }, TypeError);\n }\n });\n routes.set('/simple-cache/getOrSet/no-parameters-supplied', async () => {\n if (!isRunningLocally()) {\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet();\n },\n TypeError,\n `SimpleCache.getOrSet: At least 2 arguments required, but only 0 passed`,\n );\n }\n });\n // Ensure we correctly coerce the key parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/simple-cache/getOrSet/key-parameter-calls-7.1.17-ToString',\n async () => {\n if (!isRunningLocally()) {\n let sentinel = { sentinel: 'sentinel' };\n const test = async () => {\n const key = {\n toString() {\n throw sentinel;\n },\n };\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(Symbol(), async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n },\n );\n\n // TODO: second parameter not a function\n\n routes.set('/simple-cache/getOrSet/key-parameter-empty-string', async () => {\n if (!isRunningLocally()) {\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet('', async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: key can not be an empty string`,\n );\n }\n });\n routes.set(\n '/simple-cache/getOrSet/key-parameter-8135-character-string',\n async () => {\n if (!isRunningLocally()) {\n await assertDoesNotThrow(async () => {\n const key = 'a'.repeat(8135);\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n });\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/key-parameter-8136-character-string',\n async () => {\n if (!isRunningLocally()) {\n await assertRejects(\n async () => {\n const key = 'a'.repeat(8136);\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: key is too long, the maximum allowed length is 8135.`,\n );\n }\n },\n );\n // Ensure we correctly coerce the ttl field to a number as according to\n // https://tc39.es/ecma262/#sec-tonumber\n routes.set('/simple-cache/getOrSet/ttl-field-7.1.4-ToNumber', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/ttl-field-7.1.4-ToNumber';\n let sentinel = { sentinel: 'sentinel' };\n let requestedType;\n const test = async () => {\n const ttl = {\n [Symbol.toPrimitive](type) {\n requestedType = type;\n throw sentinel;\n },\n };\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl,\n };\n });\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n assert(requestedType, 'number', 'requestedType === \"number\"');\n }\n await assertRejects(\n () =>\n SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: Symbol(),\n };\n }),\n TypeError,\n `can't convert symbol to number`,\n );\n }\n });\n routes.set('/simple-cache/getOrSet/ttl-field-negative-number', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/ttl-field-negative-number';\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: -1,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: TTL field is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/getOrSet/ttl-field-NaN', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/ttl-field-NaN';\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: NaN,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: TTL field is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/getOrSet/ttl-field-Infinity', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/ttl-field-Infinity';\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: Number.POSITIVE_INFINITY,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: TTL field is an invalid value, only positive numbers can be used for TTL values.`,\n );\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: Number.NEGATIVE_INFINITY,\n };\n });\n },\n Error,\n `SimpleCache.getOrSet: TTL field is an invalid value, only positive numbers can be used for TTL values.`,\n );\n }\n });\n routes.set('/simple-cache/getOrSet/value-field-as-undefined', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-as-undefined';\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key, async () => {\n return { value: undefined, ttl: 1 };\n });\n });\n }\n });\n // - ReadableStream\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-missing-length-field',\n async () => {\n if (!isRunningLocally()) {\n let key =\n '/simple-cache/getOrSet/value-field-readablestream-missing-length-field';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return { value: stream, ttl: 1 };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-negative-length-field',\n async () => {\n if (!isRunningLocally()) {\n let key =\n '/simple-cache/getOrSet/value-field-readablestream-negative-length-field';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return { value: stream, ttl: 1, length: -1 };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-nan-length-field',\n async () => {\n if (!isRunningLocally()) {\n let key =\n '/simple-cache/getOrSet/value-field-readablestream-nan-length-field';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return { value: stream, ttl: 1, length: NaN };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-negative-infinity-length-field',\n async () => {\n if (!isRunningLocally()) {\n let key =\n '/simple-cache/getOrSet/value-field-readablestream-negative-infinity-length-field';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: stream,\n ttl: 1,\n length: Number.NEGATIVE_INFINITY,\n };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-positive-infinity-length-field',\n async () => {\n if (!isRunningLocally()) {\n let key =\n '/simple-cache/getOrSet/value-field-readablestream-positive-infinity-length-field';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: stream,\n ttl: 1,\n length: Number.POSITIVE_INFINITY,\n };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n // Ensure we correctly coerce the length field to a number as according to\n // https://tc39.es/ecma262/#sec-tonumber\n routes.set('/simple-cache/getOrSet/length-field-7.1.4-ToNumber', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/length-field-7.1.4-ToNumber';\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n let sentinel = { sentinel: 'sentinel' };\n let requestedType;\n const test = async () => {\n const length = {\n [Symbol.toPrimitive](type) {\n requestedType = type;\n throw sentinel;\n },\n };\n await SimpleCache.getOrSet(key, async () => {\n return { value: res.body, ttl: 1, length };\n });\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n assert(requestedType, 'number', 'requestedType === \"number\"');\n }\n await assertRejects(\n async () =>\n await SimpleCache.getOrSet(key, async () => {\n return { value: res.body, ttl: 1, length: Symbol() };\n }),\n TypeError,\n `can't convert symbol to number`,\n );\n }\n });\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-empty',\n async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-readablestream-empty';\n // TODO: remove this when streams are supported\n await assertRejects(\n async () => {\n const stream = iteratableToStream([]);\n await SimpleCache.getOrSet(key, async () => {\n return { value: stream, ttl: 1, length: 0 };\n });\n },\n TypeError,\n `Content-provided streams are not yet supported for streaming into SimpleCache`,\n );\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/value-field-readablestream-locked',\n async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-readablestream-locked';\n const stream = iteratableToStream([]);\n // getReader() causes the stream to become locked\n stream.getReader();\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return { value: stream, ttl: 1, length: 0 };\n });\n },\n TypeError,\n `Can't use a ReadableStream that's locked or has ever been read from or canceled`,\n );\n }\n },\n );\n routes.set('/simple-cache/getOrSet/value-field-readablestream', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-readablestream';\n const res = await fetch(\n 'https://compute-sdk-test-backend.edgecompute.app/',\n {\n backend: 'TheOrigin',\n },\n );\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: res.body,\n ttl: 100,\n length: res.headers.get('content-length'),\n };\n });\n });\n }\n });\n\n // - URLSearchParams\n routes.set('/simple-cache/getOrSet/value-field-URLSearchParams', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-URLSearchParams';\n const items = [\n new URLSearchParams(),\n new URLSearchParams({ a: 'b', c: 'd' }),\n ];\n for (const searchParams of items) {\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key, async () => {\n return { value: searchParams, ttl: 1 };\n });\n });\n }\n }\n });\n // - USV strings\n routes.set('/simple-cache/getOrSet/value-field-strings', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-strings';\n const strings = [\n // empty\n '',\n // lone surrogate\n '\\uD800',\n // surrogate pair\n '\uD840\uDE13',\n String('carrot'),\n ];\n for (const string of strings) {\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key, async () => {\n return { value: string, ttl: 1 };\n });\n });\n }\n }\n });\n\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/simple-cache/getOrSet/value-field-calls-7.1.17-ToString',\n async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-calls-7.1.17-ToString';\n let sentinel = { sentinel: 'sentinel' };\n const test = async () => {\n const value = {\n toString() {\n throw sentinel;\n },\n };\n await SimpleCache.getOrSet(key, async () => {\n return { value, ttl: 1 };\n });\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n await assertRejects(\n async () => {\n await SimpleCache.getOrSet(key, async () => {\n return { value: Symbol(), ttl: 1 };\n });\n },\n TypeError,\n `can't convert symbol to string`,\n );\n }\n },\n );\n\n // - buffer source\n routes.set('/simple-cache/getOrSet/value-field-buffer', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-buffer';\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key + constructor.name, async () => {\n return { value: typedArray.buffer, ttl: 1 };\n });\n });\n }\n }\n });\n\n routes.set('/simple-cache/getOrSet/value-field-typed-arrays', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-typed-arrays';\n const typedArrayConstructors = [\n Int8Array,\n Int16Array,\n Int32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n Uint8Array,\n Uint8ClampedArray,\n Uint16Array,\n Uint32Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key + constructor.name, async () => {\n return { value: typedArray, ttl: 1 };\n });\n });\n }\n }\n });\n routes.set('/simple-cache/getOrSet/value-field-dataview', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/value-field-dataview';\n const typedArrayConstructors = [\n Int8Array,\n Uint8Array,\n Uint8ClampedArray,\n Int16Array,\n Uint16Array,\n Int32Array,\n Uint32Array,\n Float32Array,\n Float64Array,\n BigInt64Array,\n BigUint64Array,\n ];\n for (const constructor of typedArrayConstructors) {\n const typedArray = new constructor(8);\n const view = new DataView(typedArray.buffer);\n await assertResolves(async () => {\n await SimpleCache.getOrSet(key + constructor.name, async () => {\n return { value: view, ttl: 1 };\n });\n });\n }\n }\n });\n routes.set('/simple-cache/getOrSet/returns-SimpleCacheEntry', async () => {\n if (!isRunningLocally()) {\n let key = '/simple-cache/getOrSet/returns-SimpleCacheEntry';\n let result = await SimpleCache.getOrSet(key, async () => {\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n assert(\n result instanceof SimpleCacheEntry,\n true,\n 'result instanceof SimpleCacheEntry',\n );\n }\n });\n routes.set(\n '/simple-cache/getOrSet/executes-the-set-method-when-key-not-in-cache',\n async () => {\n if (!isRunningLocally()) {\n let called = false;\n await SimpleCache.getOrSet(Math.random(), async () => {\n called = true;\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n assert(called, true, 'called === true');\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/does-not-execute-the-set-method-when-key-is-in-cache',\n async () => {\n if (!isRunningLocally()) {\n let key = Math.random();\n SimpleCache.set(key, 'meow', 100);\n let called = false;\n await SimpleCache.getOrSet(key, async () => {\n called = true;\n return {\n value: 'meow',\n ttl: 10,\n };\n });\n assert(called, false, 'called === false');\n }\n },\n );\n routes.set(\n '/simple-cache/getOrSet/does-not-freeze-when-called-after-a-get',\n async () => {\n if (!isRunningLocally()) {\n let key = String(Math.random());\n SimpleCache.get(key);\n await SimpleCache.getOrSet(key, async () => {\n return {\n value: key,\n ttl: 10,\n };\n });\n }\n },\n );\n}\n", "import { strictEqual } from './assertions.js';\nimport { routes, isRunningLocally } from './routes.js';\n\nroutes.set('/client/tlsJA3MD5', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsJA3MD5, null);\n } else {\n strictEqual(\n typeof event.client.tlsJA3MD5,\n 'string',\n 'typeof event.client.tlsJA3MD5',\n );\n strictEqual(\n event.client.tlsJA3MD5.length,\n 32,\n 'event.client.tlsJA3MD5.length',\n );\n }\n});\nroutes.set('/client/tlsClientHello', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsClientHello, null);\n } else {\n strictEqual(\n event.client.tlsClientHello instanceof ArrayBuffer,\n true,\n 'event.client.tlsClientHello instanceof ArrayBuffer',\n );\n strictEqual(\n typeof event.client.tlsClientHello.byteLength,\n 'number',\n 'typeof event.client.tlsClientHello.byteLength',\n );\n }\n});\n\nroutes.set('/client/tlsClientCertificate', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsClientCertificate, null);\n } else {\n strictEqual(\n event.client.tlsClientCertificate instanceof ArrayBuffer,\n true,\n 'event.client.tlsClientCertificate instanceof ArrayBuffer',\n );\n strictEqual(\n event.client.tlsClientCertificate.byteLength,\n 0,\n 'event.client.tlsClientCertificate.byteLength',\n );\n }\n});\n\nroutes.set('/client/tlsCipherOpensslName', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsCipherOpensslName, null);\n } else {\n strictEqual(\n typeof event.client.tlsCipherOpensslName,\n 'string',\n 'typeof event.client.tlsCipherOpensslName',\n );\n }\n});\n\nroutes.set('/client/tlsProtocol', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsProtocol, null);\n } else {\n strictEqual(\n typeof event.client.tlsProtocol,\n 'string',\n 'typeof event.client.tlsProtocol',\n );\n }\n});\n\nroutes.set('/client/tlsJA4', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.tlsJA4, null);\n } else {\n strictEqual(\n typeof event.client.tlsJA4,\n 'string',\n 'typeof event.client.tlsJA4',\n );\n }\n});\n\nroutes.set('/client/h2Fingerprint', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.h2Fingerprint, null);\n } else {\n // h2Fingerprint may be null for HTTP/1.1 connections\n const fp = event.client.h2Fingerprint;\n strictEqual(\n fp === null || typeof fp === 'string',\n true,\n 'event.client.h2Fingerprint is null or string',\n );\n }\n});\n\nroutes.set('/client/ohFingerprint', (event) => {\n if (isRunningLocally()) {\n strictEqual(event.client.ohFingerprint, null);\n } else {\n strictEqual(\n typeof event.client.ohFingerprint,\n 'string',\n 'typeof event.client.ohFingerprint',\n );\n }\n});\n", "export const { purgeSurrogateKey, vCpuTime } = globalThis.fastly;", "import { pass, ok, strictEqual, assertThrows } from './assertions.js';\nimport { routes } from './routes.js';\nimport { purgeSurrogateKey, vCpuTime } from 'fastly:compute';\n\nroutes.set('/compute/get-vcpu-ms', () => {\n const cpuTime = vCpuTime();\n strictEqual(typeof cpuTime, 'number');\n // We can't assert > 0; this only claims millisecond resolution,\n // and we hopefully spent less than 500us starting.\n ok(cpuTime >= 0, 'cpuTime >= 0');\n ok(cpuTime < 3000, 'cputime < 3000');\n const arr = new Array(100_000).fill(1);\n for (let j = 1; j < 100; j++) {\n for (let i = 1; i < 100_000; i++) {\n arr[i] = (arr[i] + arr[i - 1] + i) / 3;\n }\n }\n const cpuTime2 = vCpuTime();\n ok(cpuTime2 > cpuTime, 'cpuTime2 > cpuTime');\n ok(cpuTime2 - cpuTime > 1, 'cpuTime2 - cpuTime > 1');\n return pass('ok');\n});\n\nroutes.set('/compute/purge-surrogate-key-invalid', () => {\n assertThrows(\n () => {\n purgeSurrogateKey();\n },\n TypeError,\n 'purgeSurrogateKey: At least 1 argument required, but only 0 passed',\n );\n return pass('ok');\n});\n\nroutes.set('/compute/purge-surrogate-key-hard', () => {\n purgeSurrogateKey('test');\n return pass('ok');\n});\n\nroutes.set('/compute/purge-surrogate-key-soft', () => {\n purgeSurrogateKey('test', true);\n return pass('ok');\n});\n", "export const ConfigStore = globalThis.ConfigStore;", "/// \n\n/* eslint-env serviceworker */\nimport { assert } from './assertions.js';\nimport { ConfigStore } from 'fastly:config-store';\nimport { routes } from './routes.js';\nimport { env } from 'fastly:env';\n\nconst CONFIG_STORE_NAME = env('CONFIG_STORE_NAME');\n\nroutes.set('/config-store', () => {\n let config = new ConfigStore(CONFIG_STORE_NAME);\n let twitterValue = config.get('twitter');\n assert(\n twitterValue,\n 'https://twitter.com/fastly',\n `config.get(\"twitter\") === \"https://twitter.com/fastly\"`,\n );\n});\n", "/// \n/* eslint-env serviceworker, shared-node-browser, browser */\n\nimport {\n assert,\n assertThrows,\n assertRejects,\n assertResolves,\n} from './assertions.js';\nimport { routes } from './routes.js';\n\n// From https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1\nconst publicRsaJsonWebKeyData = {\n alg: 'RS256',\n e: 'AQAB',\n ext: true,\n key_ops: ['verify'],\n kty: 'RSA',\n n: '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw',\n};\n\n// From https://www.rfc-editor.org/rfc/rfc7517#appendix-A.1\nconst publicEcdsaJsonWebKeyData = {\n kty: 'EC',\n crv: 'P-256',\n x: 'MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4',\n y: '4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM',\n kid: '1',\n ext: true,\n key_ops: ['verify'],\n};\n\n// From https://www.rfc-editor.org/rfc/rfc7517#appendix-A.2\nconst privateEcdsaJsonWebKeyData = {\n kty: 'EC',\n crv: 'P-256',\n x: 'MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4',\n y: '4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM',\n d: '870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE',\n use: 'sig',\n kid: '1',\n ext: true,\n key_ops: ['sign'],\n};\n\n// From https://www.rfc-editor.org/rfc/rfc7517#appendix-A.2\nconst privateRsaJsonWebKeyData = {\n alg: 'RS256',\n d: 'X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q',\n dp: 'G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0',\n dq: 's9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk',\n e: 'AQAB',\n ext: true,\n key_ops: ['sign'],\n kty: 'RSA',\n n: '0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw',\n p: '83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs',\n q: '3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk',\n qi: 'GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU',\n};\n\nconst rsaJsonWebKeyAlgorithm = {\n name: 'RSASSA-PKCS1-v1_5',\n hash: { name: 'SHA-256' },\n};\n\nconst ecdsaJsonWebKeyAlgorithm = {\n name: 'ECDSA',\n namedCurve: 'P-256',\n hash: { name: 'SHA-256' },\n};\n\nroutes.set('/crypto', async () => {\n assert(typeof crypto, 'object', `typeof crypto`);\n assert(crypto instanceof Crypto, true, `crypto instanceof Crypto`);\n});\n\nroutes.set('/crypto.subtle', async () => {\n assert(typeof crypto.subtle, 'object', `typeof crypto.subtle`);\n assert(\n crypto.subtle instanceof SubtleCrypto,\n true,\n `crypto.subtle instanceof SubtleCrypto`,\n );\n});\n\n// importKey\n{\n routes.set('/crypto.subtle.importKey', async () => {\n assert(\n typeof crypto.subtle.importKey,\n 'function',\n `typeof crypto.subtle.importKey`,\n );\n assert(\n crypto.subtle.importKey,\n SubtleCrypto.prototype.importKey,\n `crypto.subtle.importKey === SubtleCrypto.prototype.importKey`,\n );\n });\n routes.set('/crypto.subtle.importKey/length', async () => {\n assert(\n crypto.subtle.importKey.length,\n 5,\n `crypto.subtle.importKey.length === 5`,\n );\n });\n routes.set('/crypto.subtle.importKey/called-as-constructor', async () => {\n assertThrows(\n () => {\n new crypto.subtle.importKey();\n },\n TypeError,\n 'crypto.subtle.importKey is not a constructor',\n );\n });\n routes.set('/crypto.subtle.importKey/called-with-wrong-this', async () => {\n await assertRejects(async () => {\n await crypto.subtle.importKey.call(\n undefined,\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, TypeError);\n });\n routes.set('/crypto.subtle.importKey/called-with-no-arguments', async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.importKey();\n },\n TypeError,\n 'SubtleCrypto.importKey: At least 5 arguments required, but only 0 passed',\n );\n });\n\n // first-parameter\n {\n routes.set(\n '/crypto.subtle.importKey/first-parameter-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const test = async () => {\n const format = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n format,\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/first-parameter-non-existant-format',\n async () => {\n await assertRejects(async () => {\n await crypto.subtle.importKey(\n 'jake',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n }\n\n // second-parameter\n {\n routes.set(\n '/crypto.subtle.importKey/second-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n await crypto.subtle.importKey(\n 'jwk',\n Symbol(),\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n // jwk public key\n {\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-missing-e-field',\n async () => {\n await assertRejects(async () => {\n delete publicRsaJsonWebKeyData.e;\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, DOMException);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-e-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n publicRsaJsonWebKeyData.e = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-invalid-e-field',\n async () => {\n await assertRejects(\n async () => {\n publicRsaJsonWebKeyData.e = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK member 'e' could not be base64url decoded or contained padding\",\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-missing-kty-field',\n async () => {\n await assertRejects(async () => {\n delete publicRsaJsonWebKeyData.kty;\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-invalid-kty-field',\n async () => {\n await assertRejects(async () => {\n publicRsaJsonWebKeyData.kty = 'jake';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-missing-key_ops-field',\n async () => {\n await assertResolves(async () => {\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n delete publicRsaJsonWebKeyData.key_ops;\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n });\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-non-sequence-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n publicRsaJsonWebKeyData.key_ops = 'jake';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-empty-key_ops-field',\n async () => {\n await assertResolves(async () => {\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n publicRsaJsonWebKeyData.key_ops = [];\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n });\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-duplicated-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n publicRsaJsonWebKeyData.key_ops = ['sign', 'sign'];\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-invalid-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n publicRsaJsonWebKeyData.key_ops = ['sign', 'jake'];\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-key_ops-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const key_ops = Array.from(publicRsaJsonWebKeyData.key_ops);\n const test = async () => {\n sentinel = Symbol();\n const op = {\n toString() {\n throw sentinel;\n },\n };\n publicRsaJsonWebKeyData.key_ops = ['sign', op];\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-missing-n-field',\n async () => {\n await assertRejects(\n async () => {\n delete publicRsaJsonWebKeyData.n;\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n 'Data provided to an operation does not meet requirements',\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-n-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n publicRsaJsonWebKeyData.n = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/rsa-jwk-public/second-parameter-invalid-n-field',\n async () => {\n await assertRejects(\n async () => {\n publicRsaJsonWebKeyData.n = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK member 'n' could not be base64url decoded or contained padding\",\n );\n },\n );\n }\n // jwk private key\n // TODO\n // raw HMAC secret keys\n // TODO\n // raw Elliptic Curve public keys\n {\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-missing-x-field',\n async () => {\n await assertRejects(\n async () => {\n delete publicEcdsaJsonWebKeyData.x;\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n },\n DOMException,\n 'Data provided to an operation does not meet requirements',\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-x-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n publicEcdsaJsonWebKeyData.x = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-invalid-x-field',\n async () => {\n await assertRejects(\n async () => {\n publicEcdsaJsonWebKeyData.x = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK member 'x' could not be base64url decoded or contained padding\",\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-missing-y-field',\n async () => {\n await assertRejects(\n async () => {\n delete publicEcdsaJsonWebKeyData.y;\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n },\n DOMException,\n 'Data provided to an operation does not meet requirements',\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-y-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n publicEcdsaJsonWebKeyData.y = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-invalid-y-field',\n async () => {\n await assertRejects(\n async () => {\n publicEcdsaJsonWebKeyData.y = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK member 'y' could not be base64url decoded or contained padding\",\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-missing-kty-field',\n async () => {\n await assertRejects(async () => {\n delete publicEcdsaJsonWebKeyData.kty;\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-invalid-kty-field',\n async () => {\n await assertRejects(async () => {\n publicEcdsaJsonWebKeyData.kty = 'jake';\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-missing-key_ops-field',\n async () => {\n await assertResolves(async () => {\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n delete publicEcdsaJsonWebKeyData.key_ops;\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n });\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-non-sequence-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n publicEcdsaJsonWebKeyData.key_ops = 'jake';\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-empty-key_ops-field',\n async () => {\n await assertResolves(async () => {\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n publicEcdsaJsonWebKeyData.key_ops = [];\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n });\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-duplicated-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n publicEcdsaJsonWebKeyData.key_ops = ['sign', 'sign'];\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-invalid-key_ops-field',\n async () => {\n await assertRejects(async () => {\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n publicEcdsaJsonWebKeyData.key_ops = ['sign', 'jake'];\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n }, Error);\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-public/second-parameter-key_ops-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const key_ops = Array.from(publicEcdsaJsonWebKeyData.key_ops);\n const test = async () => {\n sentinel = Symbol();\n const op = {\n toString() {\n throw sentinel;\n },\n };\n publicEcdsaJsonWebKeyData.key_ops = ['sign', op];\n await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-private/second-parameter-d-field-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n privateEcdsaJsonWebKeyData.d = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n privateEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n privateEcdsaJsonWebKeyData.ext,\n privateEcdsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n console.log(\n thrownError,\n typeof thrownError,\n Object.keys(thrownError),\n );\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/ecdsa-jwk-private/second-parameter-invalid-d-field',\n async () => {\n await assertRejects(\n async () => {\n privateEcdsaJsonWebKeyData.d = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n privateEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n privateEcdsaJsonWebKeyData.ext,\n privateEcdsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK member 'd' could not be base64url decoded or contained padding\",\n );\n },\n );\n }\n // pkcs8 Elliptic Curve private keys\n // TODO\n // pkcs8 RSA private keys\n // raw AES\n }\n // third-parameter\n {\n routes.set(\n '/crypto.subtle.importKey/third-parameter-undefined',\n async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n undefined,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n 'Algorithm: Unrecognized name',\n );\n },\n );\n routes.set(\n '/crypto.subtle.importKey/third-parameter-name-field-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const test = async () => {\n rsaJsonWebKeyAlgorithm.name = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/third-parameter-invalid-name-field',\n async () => {\n await assertRejects(async () => {\n rsaJsonWebKeyAlgorithm.name = '`~!@#@#$Q%^%&^*';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.importKey/third-parameter-hash-name-field-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const test = async () => {\n rsaJsonWebKeyAlgorithm.hash.name = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.importKey/third-parameter-hash-algorithm-does-not-match-json-web-key-hash-algorithm',\n async () => {\n await assertRejects(\n async () => {\n rsaJsonWebKeyAlgorithm.hash.name = 'SHA-1';\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n },\n Error,\n \"The JWK 'alg' member was inconsistent with that specified by the Web Crypto call\",\n );\n },\n );\n }\n\n // fifth-parameter\n {\n routes.set(\n '/crypto.subtle.importKey/fifth-parameter-undefined',\n async () => {\n await assertRejects(async () => {\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n undefined,\n );\n }, Error);\n },\n );\n routes.set('/crypto.subtle.importKey/fifth-parameter-invalid', async () => {\n await assertRejects(async () => {\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n ['jake'],\n );\n }, Error);\n });\n routes.set(\n '/crypto.subtle.importKey/fifth-parameter-duplicate-operations',\n async () => {\n await assertResolves(async () => {\n const key_ops = publicRsaJsonWebKeyData.key_ops.concat(\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n key_ops,\n );\n });\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/fifth-parameter-operations-do-not-match-json-web-key-operations',\n async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n ['sign'],\n );\n },\n Error,\n \"The JWK 'key_ops' member was inconsistent with that specified by the Web Crypto call. The JWK usage must be a superset of those requested\",\n );\n },\n );\n\n routes.set(\n '/crypto.subtle.importKey/fifth-parameter-operation-fields-calls-7.1.17-ToString',\n async () => {\n let sentinel = Symbol('sentinel');\n const test = async () => {\n sentinel = Symbol();\n const op = {\n toString() {\n throw sentinel;\n },\n };\n await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n ['sign', op],\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n }\n\n // happy paths\n {\n routes.set('/crypto.subtle.importKey/JWK-RS256-Public', async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await assert(key instanceof CryptoKey, true, `key instanceof CryptoKey`);\n await assert(\n key.algorithm,\n {\n name: 'RSASSA-PKCS1-v1_5',\n hash: {\n name: 'SHA-256',\n },\n modulusLength: 2048,\n publicExponent: new Uint8Array([1, 0, 1]),\n },\n `key.algorithm`,\n );\n await assert(key.extractable, true, `key.extractable === true`);\n await assert(key.type, 'public', `key.type === \"public\"`);\n await assert(key.usages, ['verify'], `key.usages deep equals [\"verify\"]`);\n });\n\n routes.set('/crypto.subtle.importKey/JWK-EC256-Public', async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n await assert(key instanceof CryptoKey, true, `key instanceof CryptoKey`);\n await assert(\n key.algorithm,\n {\n name: 'ECDSA',\n namedCurve: 'P-256',\n },\n `key.algorithm`,\n );\n await assert(key.extractable, true, `key.extractable === true`);\n await assert(key.type, 'public', `key.type === \"public\"`);\n await assert(key.usages, ['verify'], `key.usages deep equals [\"verify\"]`);\n });\n\n routes.set('/crypto.subtle.importKey/HMAC', async () => {\n const keyUint8Array = new Uint8Array([1, 0, 1]);\n\n for (const algorithm of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n keyUint8Array,\n { name: 'HMAC', hash: algorithm },\n false,\n ['sign', 'verify'],\n );\n await assert(\n key instanceof CryptoKey,\n true,\n `key instanceof CryptoKey`,\n );\n await assert(\n key.algorithm,\n {\n name: 'HMAC',\n hash: { name: algorithm },\n length: 24,\n },\n `key.algorithm`,\n );\n await assert(key.extractable, false, `key.extractable`);\n await assert(key.type, 'secret', `key.type`);\n await assert(key.usages, ['sign', 'verify'], `key.usages`);\n }\n });\n routes.set('/crypto.subtle.importKey/JWK-HS256-Public', async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n {\n kty: 'oct',\n k: 'Y0zt37HgOx-BY7SQjYVmrqhPkO44Ii2Jcb9yydUDPfE',\n alg: 'HS256',\n ext: true,\n },\n {\n name: 'HMAC',\n hash: { name: 'SHA-256' },\n },\n false,\n ['sign', 'verify'],\n );\n await assert(key instanceof CryptoKey, true, `key instanceof CryptoKey`);\n await assert(\n key.algorithm,\n {\n name: 'HMAC',\n hash: { name: 'SHA-256' },\n length: 256,\n },\n `key.algorithm`,\n );\n await assert(key.extractable, false, `key.extractable`);\n await assert(key.type, 'secret', `key.type`);\n await assert(key.usages, ['sign', 'verify'], `key.usages`);\n });\n }\n}\n\n// digest\n{\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n routes.set('/crypto.subtle.digest', async () => {\n assert(\n typeof crypto.subtle.digest,\n 'function',\n `typeof crypto.subtle.digest`,\n );\n assert(\n crypto.subtle.digest,\n SubtleCrypto.prototype.digest,\n `crypto.subtle.digest === SubtleCrypto.prototype.digest`,\n );\n });\n routes.set('/crypto.subtle.digest/length', async () => {\n assert(crypto.subtle.digest.length, 2, `crypto.subtle.digest.length === 2`);\n });\n routes.set('/crypto.subtle.digest/called-as-constructor', async () => {\n assertThrows(\n () => {\n new crypto.subtle.digest();\n },\n TypeError,\n 'crypto.subtle.digest is not a constructor',\n );\n });\n routes.set('/crypto.subtle.digest/called-with-wrong-this', async () => {\n await assertRejects(async () => {\n await crypto.subtle.digest.call(undefined);\n }, TypeError);\n });\n routes.set('/crypto.subtle.digest/called-with-no-arguments', async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.digest();\n },\n TypeError,\n 'SubtleCrypto.digest: At least 2 arguments required, but only 0 passed',\n );\n });\n\n // first-parameter\n {\n routes.set(\n '/crypto.subtle.digest/first-parameter-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const test = async () => {\n await crypto.subtle.digest(\n {\n name: {\n toString() {\n throw sentinel;\n },\n },\n },\n data,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.digest/first-parameter-non-existant-format',\n async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.digest('jake', data);\n },\n Error,\n 'Algorithm: Unrecognized name',\n );\n },\n );\n }\n // second-parameter\n {\n routes.set('/crypto.subtle.digest/second-parameter-undefined', async () => {\n await assertRejects(async () => {\n await crypto.subtle.digest('sha-1', undefined);\n }, Error);\n });\n }\n // happy paths\n {\n // \"MD5\"\n routes.set('/crypto.subtle.digest/md5', async () => {\n const result = new Uint8Array(\n await crypto.subtle.digest('md5', new Uint8Array()),\n );\n const expected = new Uint8Array([\n 212, 29, 140, 217, 143, 0, 178, 4, 233, 128, 9, 152, 236, 248, 66, 126,\n ]);\n assert(result, expected, 'result deep equals expected');\n });\n // \"SHA-1\"\n routes.set('/crypto.subtle.digest/sha-1', async () => {\n const result = new Uint8Array(\n await crypto.subtle.digest('sha-1', new Uint8Array()),\n );\n const expected = new Uint8Array([\n 218, 57, 163, 238, 94, 107, 75, 13, 50, 85, 191, 239, 149, 96, 24, 144,\n 175, 216, 7, 9,\n ]);\n assert(result, expected, 'result deep equals expected');\n });\n // \"SHA-256\"\n routes.set('/crypto.subtle.digest/sha-256', async () => {\n const result = new Uint8Array(\n await crypto.subtle.digest('sha-256', new Uint8Array()),\n );\n const expected = new Uint8Array([\n 227, 176, 196, 66, 152, 252, 28, 20, 154, 251, 244, 200, 153, 111, 185,\n 36, 39, 174, 65, 228, 100, 155, 147, 76, 164, 149, 153, 27, 120, 82,\n 184, 85,\n ]);\n assert(result, expected, 'result deep equals expected');\n });\n // \"SHA-384\"\n routes.set('/crypto.subtle.digest/sha-384', async () => {\n const result = new Uint8Array(\n await crypto.subtle.digest('sha-384', new Uint8Array()),\n );\n const expected = new Uint8Array([\n 56, 176, 96, 167, 81, 172, 150, 56, 76, 217, 50, 126, 177, 177, 227,\n 106, 33, 253, 183, 17, 20, 190, 7, 67, 76, 12, 199, 191, 99, 246, 225,\n 218, 39, 78, 222, 191, 231, 111, 101, 251, 213, 26, 210, 241, 72, 152,\n 185, 91,\n ]);\n assert(result, expected, 'result deep equals expected');\n });\n // \"SHA-512\"\n routes.set('/crypto.subtle.digest/sha-512', async () => {\n const result = new Uint8Array(\n await crypto.subtle.digest('sha-512', new Uint8Array()),\n );\n const expected = new Uint8Array([\n 207, 131, 225, 53, 126, 239, 184, 189, 241, 84, 40, 80, 214, 109, 128,\n 7, 214, 32, 228, 5, 11, 87, 21, 220, 131, 244, 169, 33, 211, 108, 233,\n 206, 71, 208, 209, 60, 93, 133, 242, 176, 255, 131, 24, 210, 135, 126,\n 236, 47, 99, 185, 49, 189, 71, 65, 122, 129, 165, 56, 50, 122, 249, 39,\n 218, 62,\n ]);\n assert(result, expected, 'result deep equals expected');\n });\n }\n}\n\n// sign\n{\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n routes.set('/crypto.subtle.sign', async () => {\n assert(typeof crypto.subtle.sign, 'function', `typeof crypto.subtle.sign`);\n assert(\n crypto.subtle.sign,\n SubtleCrypto.prototype.sign,\n `crypto.subtle.sign === SubtleCrypto.prototype.sign`,\n );\n });\n routes.set('/crypto.subtle.sign/length', async () => {\n assert(crypto.subtle.sign.length, 3, `crypto.subtle.sign.length === 3`);\n });\n routes.set('/crypto.subtle.sign/called-as-constructor', async () => {\n assertThrows(\n () => {\n new crypto.subtle.sign();\n },\n TypeError,\n 'crypto.subtle.sign is not a constructor',\n );\n });\n routes.set('/crypto.subtle.sign/called-with-wrong-this', async () => {\n await assertRejects(async () => {\n await crypto.subtle.sign.call(\n undefined,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData,\n data,\n );\n }, TypeError);\n });\n routes.set('/crypto.subtle.sign/called-with-no-arguments', async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.sign();\n },\n TypeError,\n 'SubtleCrypto.sign: At least 3 arguments required, but only 0 passed',\n );\n });\n // first-parameter\n {\n routes.set(\n '/crypto.subtle.sign/first-parameter-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const key = await crypto.subtle.importKey(\n 'jwk',\n privateRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n privateRsaJsonWebKeyData.ext,\n privateRsaJsonWebKeyData.key_ops,\n );\n const test = async () => {\n await crypto.subtle.sign(\n {\n name: {\n toString() {\n throw sentinel;\n },\n },\n },\n key,\n data,\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.sign/first-parameter-non-existant-algorithm',\n async () => {\n await assertRejects(\n async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n privateRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n privateRsaJsonWebKeyData.ext,\n privateRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.sign('jake', key, data);\n },\n Error,\n 'Algorithm: Unrecognized name',\n );\n },\n );\n }\n // second-parameter\n {\n routes.set(\n '/crypto.subtle.sign/second-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n await crypto.subtle.sign(rsaJsonWebKeyAlgorithm, 'jake', data);\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.sign/second-parameter-invalid-usages',\n async () => {\n await assertRejects(\n async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.sign(rsaJsonWebKeyAlgorithm, key, data);\n },\n Error,\n \"CryptoKey doesn't support signing\",\n );\n },\n );\n }\n // third-parameter\n {\n routes.set(\n '/crypto.subtle.sign/third-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.sign(rsaJsonWebKeyAlgorithm, key, undefined);\n }, Error);\n },\n );\n }\n // happy-path\n {\n routes.set('/crypto.subtle.sign/happy-path-jwk', async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n privateRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n privateRsaJsonWebKeyData.ext,\n privateRsaJsonWebKeyData.key_ops,\n );\n const signature = new Uint8Array(\n await crypto.subtle.sign(rsaJsonWebKeyAlgorithm, key, data),\n );\n const expected = new Uint8Array([\n 70, 96, 33, 185, 93, 42, 67, 49, 243, 70, 88, 68, 194, 148, 53, 249,\n 255, 192, 232, 132, 161, 194, 41, 244, 174, 211, 218, 203, 7, 238, 71,\n 182, 101, 49, 139, 222, 165, 70, 222, 105, 82, 156, 184, 44, 100, 108,\n 121, 237, 250, 119, 66, 228, 156, 243, 71, 105, 62, 246, 22, 2, 160,\n 116, 71, 147, 202, 168, 24, 92, 224, 41, 148, 161, 124, 80, 212, 169,\n 212, 64, 29, 189, 2, 171, 174, 188, 159, 89, 93, 122, 219, 166, 105, 92,\n 107, 173, 103, 238, 145, 226, 94, 139, 71, 124, 17, 233, 49, 138, 89,\n 246, 3, 82, 238, 154, 169, 188, 66, 198, 32, 23, 230, 90, 164, 140, 51,\n 47, 221, 149, 161, 14, 254, 169, 224, 223, 119, 94, 27, 63, 199, 93, 65,\n 53, 24, 151, 146, 242, 239, 41, 108, 136, 31, 99, 42, 213, 128, 244,\n 140, 238, 157, 107, 117, 241, 219, 137, 97, 39, 109, 185, 176, 97, 193,\n 60, 117, 244, 106, 62, 193, 188, 87, 199, 37, 70, 137, 37, 231, 110,\n 228, 228, 139, 53, 240, 56, 92, 102, 220, 176, 127, 248, 24, 217, 208,\n 29, 209, 216, 29, 251, 100, 252, 243, 183, 195, 96, 126, 102, 136, 48,\n 39, 186, 45, 202, 10, 187, 22, 52, 183, 190, 149, 153, 32, 12, 90, 66,\n 49, 122, 190, 154, 167, 9, 12, 32, 77, 177, 222, 54, 211, 233, 219, 205,\n 133, 0, 113, 77, 158, 1, 125, 5, 15, 195,\n ]);\n assert(signature, expected, 'signature deep equals expected');\n });\n routes.set('/crypto.subtle.sign/happy-path-hmac', async () => {\n const encoder = new TextEncoder();\n const messageUint8Array = encoder.encode('aki');\n const keyUint8Array = new Uint8Array([1, 0, 1]);\n const results = {\n 'SHA-1': new Uint8Array([\n 222, 61, 81, 133, 232, 89, 130, 225, 248, 25, 220, 34, 245, 103, 89,\n 127, 136, 77, 146, 166,\n ]),\n 'SHA-256': new Uint8Array([\n 92, 237, 16, 210, 91, 89, 194, 36, 95, 98, 27, 175, 64, 25, 15, 160,\n 152, 178, 145, 235, 62, 92, 23, 202, 125, 228, 8, 25, 148, 26, 215,\n 242,\n ]),\n 'SHA-384': new Uint8Array([\n 238, 20, 74, 173, 238, 236, 161, 229, 250, 167, 72, 210, 188, 239,\n 233, 39, 233, 166, 114, 241, 140, 229, 201, 129, 243, 173, 74, 198,\n 223, 145, 228, 96, 253, 91, 166, 111, 244, 23, 141, 62, 112, 156, 90,\n 166, 214, 69, 185, 48,\n ]),\n 'SHA-512': new Uint8Array([\n 211, 127, 139, 149, 23, 225, 84, 230, 82, 249, 109, 254, 168, 236,\n 217, 112, 174, 52, 231, 62, 167, 197, 33, 11, 181, 21, 162, 236, 214,\n 132, 43, 161, 92, 112, 230, 182, 140, 69, 169, 229, 87, 98, 57, 81,\n 140, 134, 219, 253, 139, 169, 85, 181, 195, 195, 166, 241, 219, 33, 9,\n 56, 67, 213, 51, 224,\n ]),\n };\n\n for (const algorithm of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n keyUint8Array,\n { name: 'HMAC', hash: algorithm },\n false,\n ['sign', 'verify'],\n );\n // Sign the message with HMAC and the CryptoKey\n const signature = new Uint8Array(\n await globalThis.crypto.subtle.sign('HMAC', key, messageUint8Array),\n );\n const expected = results[algorithm];\n assert(\n signature,\n expected,\n `${algorithm} signature deep equals expected`,\n );\n }\n });\n }\n}\n\n// verify\n{\n routes.set('/crypto.subtle.verify', async () => {\n assert(\n typeof crypto.subtle.verify,\n 'function',\n `typeof crypto.subtle.verify`,\n );\n assert(\n crypto.subtle.verify,\n SubtleCrypto.prototype.verify,\n `crypto.subtle.verify === SubtleCrypto.prototype.verify`,\n );\n });\n routes.set('/crypto.subtle.verify/length', async () => {\n assert(crypto.subtle.verify.length, 4, `crypto.subtle.verify.length === 4`);\n });\n routes.set('/crypto.subtle.verify/called-as-constructor', async () => {\n assertThrows(\n () => {\n new crypto.subtle.verify();\n },\n TypeError,\n 'crypto.subtle.verify is not a constructor',\n );\n });\n routes.set('/crypto.subtle.verify/called-with-wrong-this', async () => {\n await assertRejects(async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify.call(\n undefined,\n rsaJsonWebKeyAlgorithm,\n key,\n new Uint8Array(),\n new Uint8Array(),\n );\n }, TypeError);\n });\n routes.set('/crypto.subtle.verify/called-with-no-arguments', async () => {\n await assertRejects(\n async () => {\n await crypto.subtle.verify();\n },\n TypeError,\n 'SubtleCrypto.verify: At least 4 arguments required, but only 0 passed',\n );\n });\n // first-parameter\n {\n routes.set(\n '/crypto.subtle.verify/first-parameter-calls-7.1.17-ToString',\n async () => {\n const sentinel = Symbol('sentinel');\n const test = async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify(\n {\n name: {\n toString() {\n throw sentinel;\n },\n },\n },\n key,\n new Uint8Array(),\n new Uint8Array(),\n );\n };\n await assertRejects(test);\n try {\n await test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n },\n );\n routes.set(\n '/crypto.subtle.verify/first-parameter-non-existant-algorithm',\n async () => {\n await assertRejects(\n async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify(\n 'jake',\n key,\n new Uint8Array(),\n new Uint8Array(),\n );\n },\n Error,\n 'Algorithm: Unrecognized name',\n );\n },\n );\n }\n // second-parameter\n {\n routes.set(\n '/crypto.subtle.verify/second-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n 'jake',\n new Uint8Array(),\n new Uint8Array(),\n );\n }, Error);\n },\n );\n routes.set(\n '/crypto.subtle.verify/second-parameter-invalid-usages',\n async () => {\n await assertRejects(\n async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n privateRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n privateRsaJsonWebKeyData.ext,\n privateRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n key,\n new Uint8Array(),\n new Uint8Array(),\n );\n },\n Error,\n \"CryptoKey doesn't support verification\",\n );\n },\n );\n }\n // third-parameter\n {\n routes.set(\n '/crypto.subtle.verify/third-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n key,\n undefined,\n new Uint8Array(),\n );\n }, Error);\n },\n );\n }\n // fourth-parameter\n {\n routes.set(\n '/crypto.subtle.verify/fourth-parameter-invalid-format',\n async () => {\n await assertRejects(async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n key,\n new Uint8Array(),\n undefined,\n );\n }, Error);\n },\n );\n }\n // incorrect-signature\n {\n routes.set('/crypto.subtle.verify/incorrect-signature-jwk', async () => {\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n const signature = new Uint8Array();\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n const result = await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n key,\n signature,\n data,\n );\n assert(result, false, 'result === false');\n });\n routes.set('/crypto.subtle.verify/incorrect-signature-hmac', async () => {\n const keyUint8Array = new Uint8Array([1, 0, 1]);\n const signature = new Uint8Array();\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n\n for (const algorithm of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n keyUint8Array,\n { name: 'HMAC', hash: algorithm },\n false,\n ['sign', 'verify'],\n );\n const result = await crypto.subtle.verify('HMAC', key, signature, data);\n assert(result, false, 'result');\n }\n });\n }\n // correct-signature\n {\n routes.set('/crypto.subtle.verify/correct-signature-jwk-rsa', async () => {\n const pkey = await crypto.subtle.importKey(\n 'jwk',\n privateRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n privateRsaJsonWebKeyData.ext,\n privateRsaJsonWebKeyData.key_ops,\n );\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicRsaJsonWebKeyData,\n rsaJsonWebKeyAlgorithm,\n publicRsaJsonWebKeyData.ext,\n publicRsaJsonWebKeyData.key_ops,\n );\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n const signature = await crypto.subtle.sign(\n rsaJsonWebKeyAlgorithm,\n pkey,\n data,\n );\n const result = await crypto.subtle.verify(\n rsaJsonWebKeyAlgorithm,\n key,\n signature,\n data,\n );\n assert(result, true, 'result === true');\n });\n routes.set(\n '/crypto.subtle.verify/correct-signature-jwk-ecdsa',\n async () => {\n const pkey = await crypto.subtle.importKey(\n 'jwk',\n privateEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n privateEcdsaJsonWebKeyData.ext,\n privateEcdsaJsonWebKeyData.key_ops,\n );\n const key = await crypto.subtle.importKey(\n 'jwk',\n publicEcdsaJsonWebKeyData,\n ecdsaJsonWebKeyAlgorithm,\n publicEcdsaJsonWebKeyData.ext,\n publicEcdsaJsonWebKeyData.key_ops,\n );\n const enc = new TextEncoder();\n const data = enc.encode('hello world');\n const signature = await crypto.subtle.sign(\n ecdsaJsonWebKeyAlgorithm,\n pkey,\n data,\n );\n const result = await crypto.subtle.verify(\n ecdsaJsonWebKeyAlgorithm,\n key,\n signature,\n data,\n );\n assert(result, true, 'result === true');\n },\n );\n routes.set('/crypto.subtle.verify/correct-signature-hmac', async () => {\n const results = {\n 'SHA-1': new Uint8Array([\n 222, 61, 81, 133, 232, 89, 130, 225, 248, 25, 220, 34, 245, 103, 89,\n 127, 136, 77, 146, 166,\n ]),\n 'SHA-256': new Uint8Array([\n 92, 237, 16, 210, 91, 89, 194, 36, 95, 98, 27, 175, 64, 25, 15, 160,\n 152, 178, 145, 235, 62, 92, 23, 202, 125, 228, 8, 25, 148, 26, 215,\n 242,\n ]),\n 'SHA-384': new Uint8Array([\n 238, 20, 74, 173, 238, 236, 161, 229, 250, 167, 72, 210, 188, 239,\n 233, 39, 233, 166, 114, 241, 140, 229, 201, 129, 243, 173, 74, 198,\n 223, 145, 228, 96, 253, 91, 166, 111, 244, 23, 141, 62, 112, 156, 90,\n 166, 214, 69, 185, 48,\n ]),\n 'SHA-512': new Uint8Array([\n 211, 127, 139, 149, 23, 225, 84, 230, 82, 249, 109, 254, 168, 236,\n 217, 112, 174, 52, 231, 62, 167, 197, 33, 11, 181, 21, 162, 236, 214,\n 132, 43, 161, 92, 112, 230, 182, 140, 69, 169, 229, 87, 98, 57, 81,\n 140, 134, 219, 253, 139, 169, 85, 181, 195, 195, 166, 241, 219, 33, 9,\n 56, 67, 213, 51, 224,\n ]),\n };\n const encoder = new TextEncoder();\n const messageUint8Array = encoder.encode('aki');\n const keyUint8Array = new Uint8Array([1, 0, 1]);\n\n for (const algorithm of ['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']) {\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n keyUint8Array,\n { name: 'HMAC', hash: algorithm },\n false,\n ['sign', 'verify'],\n );\n // Sign the message with HMAC and the CryptoKey\n // const signature = new Uint8Array(await globalThis.crypto.subtle.sign(\"HMAC\", key, messageUint8Array));\n const signature = results[algorithm];\n const result = await crypto.subtle.verify(\n 'HMAC',\n key,\n signature,\n messageUint8Array,\n );\n assert(result, true, 'result');\n }\n });\n }\n}\n", "export const Device = globalThis.Device;", "/// \n/* eslint-env serviceworker */\n\nimport { assert, assertThrows } from './assertions.js';\nimport { Device } from 'fastly:device';\nimport { routes } from './routes.js';\n\nroutes.set('/device/interface', () => {\n let actual = Reflect.ownKeys(Device);\n let expected = ['prototype', 'lookup', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(Device)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Device, 'prototype');\n expected = {\n value: Device.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Device, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Device, 'name');\n expected = {\n value: 'Device',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(Device.prototype);\n expected = [\n 'constructor',\n 'name',\n 'brand',\n 'model',\n 'hardwareType',\n 'isDesktop',\n 'isGameConsole',\n 'isMediaPlayer',\n 'isMobile',\n 'isSmartTV',\n 'isTablet',\n 'isTouchscreen',\n 'toJSON',\n Symbol.toStringTag,\n ];\n assert(actual, expected, `Reflect.ownKeys(Device.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Device.prototype, 'constructor');\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: Device.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.prototype, 'constructor')`,\n );\n\n assert(\n typeof Device.prototype.constructor,\n 'function',\n `typeof Device.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Device.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Device.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'Device',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n Device.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'Device',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof Device.prototype[Symbol.toStringTag],\n 'string',\n `typeof Device.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the lookup static method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(Device, 'lookup');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: Device.lookup,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device, 'lookup')`,\n );\n\n assert(typeof Device.lookup, 'function', `typeof Device.lookup`);\n\n actual = Reflect.getOwnPropertyDescriptor(Device.lookup, 'length');\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.lookup, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Device.lookup, 'name');\n expected = {\n value: 'lookup',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Device.lookup, 'name')`,\n );\n }\n\n for (let property of [\n 'name',\n 'brand',\n 'model',\n 'hardwareType',\n 'isDesktop',\n 'isGameConsole',\n 'isMediaPlayer',\n 'isMobile',\n 'isSmartTV',\n 'isTablet',\n 'isTouchscreen',\n ]) {\n const descriptors = Reflect.getOwnPropertyDescriptor(\n Device.prototype,\n property,\n );\n expected = { enumerable: true, configurable: true };\n assert(\n descriptors.enumerable,\n true,\n `Reflect.getOwnPropertyDescriptor(Device, '${property}').enumerable`,\n );\n assert(\n descriptors.configurable,\n true,\n `Reflect.getOwnPropertyDescriptor(Device, '${property}').configurable`,\n );\n assert(\n descriptors.value,\n undefined,\n `Reflect.getOwnPropertyDescriptor(Device, '${property}').value`,\n );\n assert(\n descriptors.set,\n undefined,\n `Reflect.getOwnPropertyDescriptor(Device, '${property}').set`,\n );\n assert(\n typeof descriptors.get,\n 'function',\n `typeof Reflect.getOwnPropertyDescriptor(Device, '${property}').get`,\n );\n }\n});\n\n// Device constructor\n{\n routes.set('/device/constructor/called-as-regular-function', () => {\n assertThrows(() => {\n Device();\n }, TypeError);\n });\n routes.set('/device/constructor/throws', () => {\n assertThrows(() => new Device(), TypeError);\n });\n}\n\n// Device lookup static method\n// static lookup(useragent: string): DeviceEntry | null;\n{\n routes.set('/device/lookup/called-as-constructor', () => {\n assertThrows(() => {\n new Device.lookup('1');\n }, TypeError);\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/device/lookup/useragent-parameter-calls-7.1.17-ToString', () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const useragent = {\n toString() {\n throw sentinel;\n },\n };\n Device.lookup(useragent);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n Device.lookup(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n });\n routes.set('/device/lookup/useragent-parameter-not-supplied', () => {\n assertThrows(\n () => {\n Device.lookup();\n },\n TypeError,\n `Device.lookup: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/device/lookup/useragent-parameter-empty-string', () => {\n assertThrows(\n () => {\n Device.lookup('');\n },\n Error,\n `Device.lookup: useragent parameter can not be an empty string`,\n );\n });\n routes.set('/device/lookup/useragent-does-not-exist-returns-null', () => {\n let result = Device.lookup(Math.random());\n assert(result, null, `Device.lookup(Math.random()) === null`);\n });\n routes.set('/device/lookup/useragent-exists-all-fields-identified', () => {\n let useragent =\n 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 FBAN/FBIOS;FBAV/8.0.0.28.18;FBBV/1665515;FBDV/iPhone4,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/7.0.4;FBSS/2; FBCR/Telekom.de;FBID/phone;FBLC/de_DE;FBOP/5';\n let device = Device.lookup(useragent);\n\n assert(\n device instanceof Device,\n true,\n `Device.lookup(useragent) instanceof DeviceEntry`,\n );\n\n assert(device.name, 'iPhone', `device.name`);\n assert(device.brand, 'Apple', `device.brand`);\n assert(device.model, 'iPhone4,1', `device.model`);\n assert(device.hardwareType, 'Mobile Phone', `device.hardwareType`);\n assert(device.isDesktop, false, `device.isDesktop`);\n assert(device.isGameConsole, false, `device.isGameConsole`);\n assert(device.isMediaPlayer, false, `device.isMediaPlayer`);\n assert(device.isMobile, true, `device.isMobile`);\n assert(device.isSmartTV, false, `device.isSmartTV`);\n assert(device.isTablet, false, `device.isTablet`);\n assert(device.isTouchscreen, true, `device.isTouchscreen`);\n });\n routes.set(\n '/device/lookup/useragent-exists-all-fields-identified-tojson',\n () => {\n let useragent =\n 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0 FBAN/FBIOS;FBAV/8.0.0.28.18;FBBV/1665515;FBDV/iPhone4,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/7.0.4;FBSS/2; FBCR/Telekom.de;FBID/phone;FBLC/de_DE;FBOP/5';\n let device = Device.lookup(useragent);\n device = device.toJSON();\n\n assert(device.brand, 'Apple', `device.brand`);\n assert(device.model, 'iPhone4,1', `device.model`);\n assert(device.hardwareType, 'Mobile Phone', `device.hardwareType`);\n assert(device.isDesktop, false, `device.isDesktop`);\n assert(device.isGameConsole, false, `device.isGameConsole`);\n assert(device.isMediaPlayer, false, `device.isMediaPlayer`);\n assert(device.isMobile, true, `device.isMobile`);\n assert(device.isSmartTV, false, `device.isSmartTV`);\n assert(device.isTablet, false, `device.isTablet`);\n assert(device.isTouchscreen, true, `device.isTouchscreen`);\n },\n );\n routes.set('/device/lookup/useragent-exists-some-fields-identified', () => {\n let useragent =\n 'ghosts-app/1.0.2.1 (ASUSTeK COMPUTER INC.; X550CC; Windows 8 (X86); en)';\n let device = Device.lookup(useragent);\n\n assert(\n device instanceof Device,\n true,\n `Device.lookup(useragent) instanceof DeviceEntry`,\n );\n assert(device.name, 'Asus TeK', `device.name`);\n assert(device.brand, 'Asus', `device.brand`);\n assert(device.model, 'TeK', `device.model`);\n assert(device.hardwareType, null, `device.hardwareType`);\n assert(device.isDesktop, false, `device.isDesktop`);\n assert(device.isGameConsole, null, `device.isGameConsole`);\n assert(device.isMediaPlayer, null, `device.isMediaPlayer`);\n assert(device.isMobile, null, `device.isMobile`);\n assert(device.isSmartTV, null, `device.isSmartTV`);\n assert(device.isTablet, null, `device.isTablet`);\n assert(device.isTouchscreen, null, `device.isTouchscreen`);\n assert(\n JSON.stringify(device),\n '{\"name\":\"Asus TeK\",\"brand\":\"Asus\",\"model\":\"TeK\",\"hardwareType\":null,\"isDesktop\":false,\"isGameConsole\":null,\"isMediaPlayer\":null,\"isMobile\":null,\"isSmartTV\":null,\"isTablet\":null,\"isTouchscreen\":null}',\n `JSON.stringify(device)`,\n );\n });\n}\n", "export const Dictionary = globalThis.Dictionary;", "/* eslint-env serviceworker */\n\nimport { Dictionary } from 'fastly:dictionary';\nimport { routes } from './routes.js';\nimport { assertThrows, assert, assertResolves } from './assertions.js';\nimport { env } from 'fastly:env';\n\nconst DICTIONARY_NAME = env('DICTIONARY_NAME');\n\n// Dictionary\n{\n routes.set('/dictionary/exposed-as-global', () => {\n assert(typeof Dictionary, 'function', `typeof Dictionary`);\n });\n routes.set('/dictionary/interface', dictionaryInterfaceTests);\n // Dictionary constructor\n {\n routes.set('/dictionary/constructor/called-as-regular-function', () => {\n assertThrows(\n () => {\n Dictionary();\n },\n TypeError,\n `calling a builtin Dictionary constructor without new is forbidden`,\n );\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/dictionary/constructor/parameter-calls-7.1.17-ToString',\n () => {\n let sentinel = Symbol();\n const test = () => {\n const name = {\n toString() {\n throw sentinel;\n },\n };\n new Dictionary(name);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => new Dictionary(Symbol()),\n TypeError,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set('/dictionary/constructor/empty-parameter', () => {\n assertThrows(\n () => {\n new Dictionary();\n },\n TypeError,\n `Dictionary constructor: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/dictionary/constructor/found', () => {\n const store = createValidDictionary();\n assert(store instanceof Dictionary, true, `store instanceof Dictionary`);\n });\n routes.set('/dictionary/constructor/invalid-name', () => {\n // control Characters (\\\\u0000-\\\\u001F) are not allowed\n const invalidNames = ['1', '-', ' ', '\u00C4'];\n for (const name of invalidNames) {\n assertThrows(\n () => {\n new Dictionary(name);\n },\n TypeError,\n `Dictionary constructor: name must start with an ascii alpabetical character`,\n );\n }\n assertThrows(\n () => {\n new Dictionary('a\u00C4');\n },\n TypeError,\n `Dictionary constructor: name can contain only ascii alphanumeric characters, underscores, and ascii whitespace`,\n );\n\n // must be less than 256 characters\n assertThrows(\n () => {\n new Dictionary('a'.repeat(256));\n },\n TypeError,\n `Dictionary constructor: name can not be more than 255 characters`,\n );\n\n // empty string not allowed\n assertThrows(\n () => {\n new Dictionary('');\n },\n TypeError,\n `Dictionary constructor: name can not be an empty string`,\n );\n });\n }\n\n // Dictionary get method\n {\n routes.set('/dictionary/get/called-as-constructor', () => {\n assertThrows(() => {\n new Dictionary.prototype.get('1');\n }, TypeError);\n });\n routes.set('/dictionary/get/called-unbound', () => {\n assertThrows(() => {\n Dictionary.prototype.get.call(undefined, '1');\n }, TypeError);\n });\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/dictionary/get/key-parameter-calls-7.1.17-ToString', () => {\n let sentinel = Symbol();\n const test = () => {\n const key = {\n toString() {\n throw sentinel;\n },\n };\n const store = createValidDictionary();\n store.get(key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n const store = createValidDictionary();\n store.get(Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n });\n routes.set('/dictionary/get/key-parameter-not-supplied', () => {\n assertThrows(\n () => {\n const store = createValidDictionary();\n store.get();\n },\n TypeError,\n `get: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/dictionary/get/key-parameter-empty-string', () => {\n assertThrows(\n () => {\n const store = createValidDictionary();\n store.get('');\n },\n TypeError,\n `Dictionary key can not be an empty string`,\n );\n });\n routes.set('/dictionary/get/key-parameter-255-character-string', () => {\n assertResolves(() => {\n const store = createValidDictionary();\n const key = 'a'.repeat(255);\n store.get(key);\n });\n });\n routes.set('/dictionary/get/key-parameter-256-character-string', () => {\n assertThrows(\n () => {\n const store = createValidDictionary();\n const key = 'a'.repeat(256);\n store.get(key);\n },\n TypeError,\n `Dictionary key can not be more than 255 characters`,\n );\n });\n routes.set('/dictionary/get/key-does-not-exist-returns-null', () => {\n let store = createValidDictionary();\n let result = store.get(Math.random());\n assert(result, null, `store.get(Math.random())`);\n });\n routes.set('/dictionary/get/key-exists', () => {\n let store = createValidDictionary();\n let result = store.get('twitter');\n assert(\n result,\n 'https://twitter.com/fastly',\n `store.get('twitter') === \"https://twitter.com/fastly\"`,\n );\n });\n }\n}\n\nfunction dictionaryInterfaceTests() {\n let actual = Reflect.ownKeys(Dictionary);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(Dictionary)`);\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary, 'prototype');\n expected = {\n value: Dictionary.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary, 'prototype')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary, 'length');\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary, 'name');\n expected = {\n value: 'Dictionary',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary, 'name')`,\n );\n\n actual = Reflect.ownKeys(Dictionary.prototype);\n expected = ['constructor', 'get'];\n assert(actual, expected, `Reflect.ownKeys(Dictionary.prototype)`);\n\n actual = Reflect.getOwnPropertyDescriptor(\n Dictionary.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: Dictionary.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype, 'constructor')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary.prototype, 'get');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: Dictionary.prototype.get,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype, 'get')`,\n );\n\n assert(\n typeof Dictionary.prototype.constructor,\n 'function',\n `typeof Dictionary.prototype.constructor`,\n );\n assert(\n typeof Dictionary.prototype.get,\n 'function',\n `typeof Dictionary.prototype.get`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Dictionary.prototype.constructor,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Dictionary.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'Dictionary',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype.constructor, 'name')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary.prototype.get, 'length');\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype.get, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(Dictionary.prototype.get, 'name');\n expected = {\n value: 'get',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Dictionary.prototype.get, 'name')`,\n );\n}\n\nfunction createValidDictionary() {\n return new Dictionary(DICTIONARY_NAME);\n}\n", "import { pass, ok, strictEqual, assertThrows } from './assertions.js';\nimport { routes } from './routes.js';\n\nroutes.set('/early-hints/manual-response', (event) => {\n event.respondWith(\n new Response(null, {\n status: 103,\n headers: { link: '; rel=preload; as=style' },\n }),\n );\n event.respondWith(new Response('ok'));\n});\n\nroutes.set('/early-hints/send-early-hints', (event) => {\n event.sendEarlyHints({ link: '; rel=preload; as=style' });\n event.respondWith(new Response('ok'));\n});\n\nroutes.set('/early-hints/send-early-hints-multiple-headers', (event) => {\n event.sendEarlyHints([\n ['link', '; rel=preload; as=style'],\n ['link', '; rel=preload; as=style'],\n ]);\n event.respondWith(new Response('ok'));\n});\n", "\nexport const RateCounter = globalThis.RateCounter;\nexport const PenaltyBox = globalThis.PenaltyBox;\nexport const EdgeRateLimiter = globalThis.EdgeRateLimiter;\n", "/// \n/* eslint-env serviceworker */\n\nimport { assert, assertThrows } from './assertions.js';\nimport {\n RateCounter,\n PenaltyBox,\n EdgeRateLimiter,\n} from 'fastly:edge-rate-limiter';\nimport { routes, isRunningLocally } from './routes.js';\nimport { env } from 'fastly:env';\n\nconst FASTLY_SERVICE_NAME = env('FASTLY_SERVICE_NAME');\nconst PENALTY_BOX_NAME = `pb${FASTLY_SERVICE_NAME}`;\nconst RATE_COUNTER_NAME = `rc${FASTLY_SERVICE_NAME}`;\n\n// RateCounter\n{\n routes.set('/rate-counter/interface', () => {\n let actual = Reflect.ownKeys(RateCounter);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(RateCounter)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(RateCounter, 'prototype');\n expected = {\n value: RateCounter.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(RateCounter, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(RateCounter, 'name');\n expected = {\n value: 'RateCounter',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(RateCounter.prototype);\n expected = [\n 'constructor',\n 'increment',\n 'lookupRate',\n 'lookupCount',\n Symbol.toStringTag,\n ];\n assert(actual, expected, `Reflect.ownKeys(RateCounter.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: RateCounter.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype, 'constructor')`,\n );\n\n assert(\n typeof RateCounter.prototype.constructor,\n 'function',\n `typeof RateCounter.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'RateCounter',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'RateCounter',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof RateCounter.prototype[Symbol.toStringTag],\n 'string',\n `typeof RateCounter.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the increment method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype,\n 'increment',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: RateCounter.prototype.increment,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype, 'increment')`,\n );\n\n assert(\n typeof RateCounter.prototype.increment,\n 'function',\n `typeof RateCounter.prototype.increment`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.increment,\n 'length',\n );\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.increment, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.increment,\n 'name',\n );\n expected = {\n value: 'increment',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.increment, 'name')`,\n );\n }\n\n // Check the lookupRate method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype,\n 'lookupRate',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: RateCounter.prototype.lookupRate,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype, 'lookupRate')`,\n );\n\n assert(\n typeof RateCounter.prototype.lookupRate,\n 'function',\n `typeof RateCounter.prototype.lookupRate`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.lookupRate,\n 'length',\n );\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.lookupRate, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.lookupRate,\n 'name',\n );\n expected = {\n value: 'lookupRate',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.lookupRate, 'name')`,\n );\n }\n\n // Check the lookupCount method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype,\n 'lookupCount',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: RateCounter.prototype.lookupCount,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype, 'lookupCount')`,\n );\n\n assert(\n typeof RateCounter.prototype.lookupCount,\n 'function',\n `typeof RateCounter.prototype.lookupCount`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.lookupCount,\n 'length',\n );\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.lookupCount, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n RateCounter.prototype.lookupCount,\n 'name',\n );\n expected = {\n value: 'lookupCount',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(RateCounter.prototype.lookupCount, 'name')`,\n );\n }\n });\n\n // RateCounter constructor\n {\n routes.set('/rate-counter/constructor/called-as-regular-function', () => {\n assertThrows(\n () => {\n RateCounter();\n },\n Error,\n `calling a builtin RateCounter constructor without new is forbidden`,\n );\n });\n routes.set(\n '/rate-counter/constructor/called-as-constructor-no-arguments',\n () => {\n assertThrows(\n () => new RateCounter(),\n Error,\n `RateCounter constructor: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/rate-counter/constructor/name-parameter-calls-7.1.17-ToString',\n () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const name = {\n toString() {\n throw sentinel;\n },\n };\n new RateCounter(name);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n new RateCounter(Symbol());\n },\n Error,\n `can't convert symbol to string`,\n );\n }\n },\n );\n routes.set('/rate-counter/constructor/happy-path', () => {\n assert(\n new RateCounter(RATE_COUNTER_NAME) instanceof RateCounter,\n true,\n `new RateCounter(\"rc\") instanceof RateCounter`,\n );\n });\n }\n\n // RateCounter increment method\n // increment(entry: string, delta: number): void;\n {\n routes.set('/rate-counter/increment/called-as-constructor', () => {\n assertThrows(() => {\n new RateCounter.prototype.increment('entry', 1);\n }, Error);\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/rate-counter/increment/entry-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment(entry, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment(Symbol(), 1);\n },\n Error,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set('/rate-counter/increment/entry-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment();\n },\n Error,\n `increment: At least 2 arguments required, but only 0 passed`,\n );\n });\n routes.set('/rate-counter/increment/delta-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment('entry');\n },\n Error,\n `increment: At least 2 arguments required, but only 1 passed`,\n );\n });\n routes.set('/rate-counter/increment/delta-parameter-negative', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment('entry', -1);\n },\n Error,\n `increment: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/rate-counter/increment/delta-parameter-infinity', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment('entry', Infinity);\n },\n Error,\n `increment: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/rate-counter/increment/delta-parameter-NaN', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.increment('entry', NaN);\n },\n Error,\n `increment: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/rate-counter/increment/returns-undefined', () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n assert(rc.increment('meow', 1), undefined, \"rc.increment('meow', 1)\");\n });\n }\n\n // RateCounter lookupRate method\n // lookupRate(entry: string, window: [1, 10, 60]): number;\n {\n routes.set('/rate-counter/lookupRate/called-as-constructor', () => {\n assertThrows(() => {\n new RateCounter.prototype.lookupRate('entry', 1);\n }, Error);\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/rate-counter/lookupRate/entry-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate(entry, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate(Symbol(), 1);\n },\n Error,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set('/rate-counter/lookupRate/entry-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate();\n },\n Error,\n `lookupRate: At least 2 arguments required, but only 0 passed`,\n );\n });\n routes.set('/rate-counter/lookupRate/window-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate('entry');\n },\n Error,\n `lookupRate: At least 2 arguments required, but only 1 passed`,\n );\n });\n routes.set('/rate-counter/lookupRate/window-parameter-negative', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate('entry', -1);\n },\n Error,\n `lookupRate: window parameter must be either: 1, 10, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupRate/window-parameter-infinity', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate('entry', Infinity);\n },\n Error,\n `lookupRate: window parameter must be either: 1, 10, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupRate/window-parameter-NaN', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupRate('entry', NaN);\n },\n Error,\n `lookupRate: window parameter must be either: 1, 10, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupRate/returns-number', () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n assert(\n typeof rc.lookupRate('meow', 1),\n 'number',\n `typeof rc.lookupRate('meow', 1)`,\n );\n });\n }\n\n // RateCounter lookupCount method\n // lookupCount(entry: string, duration: [10, 20, 30, 40, 50, 60]): number;\n {\n routes.set('/rate-counter/lookupCount/called-as-constructor', () => {\n assertThrows(() => {\n new RateCounter.prototype.lookupCount('entry', 1);\n }, Error);\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/rate-counter/lookupCount/entry-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount(entry, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount(Symbol(), 1);\n },\n Error,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set('/rate-counter/lookupCount/entry-parameter-not-supplied', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount();\n },\n Error,\n `lookupCount: At least 2 arguments required, but only 0 passed`,\n );\n }\n });\n routes.set(\n '/rate-counter/lookupCount/duration-parameter-not-supplied',\n () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount('entry');\n },\n Error,\n `lookupCount: At least 2 arguments required, but only 1 passed`,\n );\n }\n },\n );\n routes.set('/rate-counter/lookupCount/duration-parameter-negative', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount('entry', -1);\n },\n Error,\n `lookupCount: duration parameter must be either: 10, 20, 30, 40, 50, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupCount/duration-parameter-infinity', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount('entry', Infinity);\n },\n Error,\n `lookupCount: duration parameter must be either: 10, 20, 30, 40, 50, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupCount/duration-parameter-NaN', () => {\n if (!isRunningLocally()) {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n rc.lookupCount('entry', NaN);\n },\n Error,\n `lookupCount: duration parameter must be either: 10, 20, 30, 40, 50, or 60`,\n );\n }\n });\n routes.set('/rate-counter/lookupCount/returns-number', () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n assert(\n typeof rc.lookupCount('meow', 10),\n 'number',\n `typeof rc.lookupCount('meow', 1)`,\n );\n });\n }\n}\n\n// PenaltyBox\n{\n routes.set('/penalty-box/interface', () => {\n let actual = Reflect.ownKeys(PenaltyBox);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(PenaltyBox)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(PenaltyBox, 'prototype');\n expected = {\n value: PenaltyBox.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(PenaltyBox, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(PenaltyBox, 'name');\n expected = {\n value: 'PenaltyBox',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(PenaltyBox.prototype);\n expected = ['constructor', 'add', 'has', Symbol.toStringTag];\n assert(actual, expected, `Reflect.ownKeys(PenaltyBox.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: PenaltyBox.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, 'constructor')`,\n );\n\n assert(\n typeof PenaltyBox.prototype.constructor,\n 'function',\n `typeof PenaltyBox.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'PenaltyBox',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'PenaltyBox',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof PenaltyBox.prototype[Symbol.toStringTag],\n 'string',\n `typeof PenaltyBox.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the add method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, 'add');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: PenaltyBox.prototype.add,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, 'add')`,\n );\n\n assert(\n typeof PenaltyBox.prototype.add,\n 'function',\n `typeof PenaltyBox.prototype.add`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.add,\n 'length',\n );\n expected = {\n value: 2,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.add, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.add,\n 'name',\n );\n expected = {\n value: 'add',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.add, 'name')`,\n );\n }\n\n // Check the has method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, 'has');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: PenaltyBox.prototype.has,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype, 'has')`,\n );\n\n assert(\n typeof PenaltyBox.prototype.has,\n 'function',\n `typeof PenaltyBox.prototype.has`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.has,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.has, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n PenaltyBox.prototype.has,\n 'name',\n );\n expected = {\n value: 'has',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(PenaltyBox.prototype.has, 'name')`,\n );\n }\n });\n\n // PenaltyBox constructor\n {\n routes.set('/penalty-box/constructor/called-as-regular-function', () => {\n assertThrows(\n () => {\n PenaltyBox();\n },\n Error,\n `calling a builtin PenaltyBox constructor without new is forbidden`,\n );\n });\n routes.set(\n '/penalty-box/constructor/called-as-constructor-no-arguments',\n () => {\n assertThrows(\n () => new PenaltyBox(),\n Error,\n `PenaltyBox constructor: At least 1 argument required, but only 0 passed`,\n );\n },\n );\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/penalty-box/constructor/name-parameter-calls-7.1.17-ToString',\n () => {\n if (!isRunningLocally()) {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const name = {\n toString() {\n throw sentinel;\n },\n };\n new PenaltyBox(name);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n new PenaltyBox(Symbol());\n },\n Error,\n `can't convert symbol to string`,\n );\n }\n },\n );\n routes.set('/penalty-box/constructor/happy-path', () => {\n assert(\n new PenaltyBox(RATE_COUNTER_NAME) instanceof PenaltyBox,\n true,\n `new PenaltyBox(\"rc\") instanceof PenaltyBox`,\n );\n });\n }\n\n // PenaltyBox has method\n // has(entry: string): boolean;\n {\n routes.set('/penalty-box/has/called-as-constructor', () => {\n assertThrows(() => {\n new PenaltyBox.prototype.has('entry');\n }, Error);\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/penalty-box/has/entry-parameter-calls-7.1.17-ToString', () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.has(entry);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.has(Symbol());\n },\n Error,\n `can't convert symbol to string`,\n );\n });\n routes.set('/penalty-box/has/entry-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.has();\n },\n Error,\n `has: At least 1 argument required, but only 0 passed`,\n );\n });\n routes.set('/penalty-box/has/returns-boolean', () => {\n let pb = new PenaltyBox(`pb-`);\n assert(pb.has('meow'), false, \"pb.has('meow')\");\n });\n }\n\n // PenaltyBox add method\n // add(entry: string, timeToLive: number): void;\n {\n routes.set('/penalty-box/add/called-as-constructor', () => {\n assertThrows(() => {\n new PenaltyBox.prototype.add('entry', 1);\n }, Error);\n });\n // Ensure we correctly coepbe the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set('/penalty-box/add/entry-parameter-calls-7.1.17-ToString', () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add(entry, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add(Symbol(), 1);\n },\n Error,\n `can't convert symbol to string`,\n );\n });\n routes.set('/penalty-box/add/entry-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add();\n },\n Error,\n `add: At least 2 arguments required, but only 0 passed`,\n );\n });\n routes.set('/penalty-box/add/timeToLive-parameter-not-supplied', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add('entry');\n },\n Error,\n `add: At least 2 arguments required, but only 1 passed`,\n );\n });\n routes.set('/penalty-box/add/timeToLive-parameter-negative', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add('entry', -1);\n },\n Error,\n `add: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n });\n routes.set('/penalty-box/add/timeToLive-parameter-infinity', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add('entry', Infinity);\n },\n Error,\n `add: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n });\n routes.set('/penalty-box/add/timeToLive-parameter-NaN', () => {\n assertThrows(\n () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n pb.add('entry', NaN);\n },\n Error,\n `add: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n });\n routes.set('/penalty-box/add/returns-undefined', () => {\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n assert(pb.add('meow', 1), undefined, `pb.add('meow', 1)`);\n });\n }\n}\n\n// EdgeRateLimiter\n{\n routes.set('/edge-rate-limiter/interface', () => {\n let actual = Reflect.ownKeys(EdgeRateLimiter);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(EdgeRateLimiter)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'prototype');\n expected = {\n value: EdgeRateLimiter.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'name');\n expected = {\n value: 'EdgeRateLimiter',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(EdgeRateLimiter.prototype);\n expected = ['constructor', 'checkRate', Symbol.toStringTag];\n assert(actual, expected, `Reflect.ownKeys(EdgeRateLimiter.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: EdgeRateLimiter.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype, 'constructor')`,\n );\n\n assert(\n typeof EdgeRateLimiter.prototype.constructor,\n 'function',\n `typeof EdgeRateLimiter.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'EdgeRateLimiter',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype,\n Symbol.toStringTag,\n );\n expected = {\n writable: false,\n enumerable: false,\n configurable: true,\n value: 'EdgeRateLimiter',\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof EdgeRateLimiter.prototype[Symbol.toStringTag],\n 'string',\n `typeof EdgeRateLimiter.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the checkRate method has correct descriptors, length and name\n {\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype,\n 'checkRate',\n );\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: EdgeRateLimiter.prototype.checkRate,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype, 'checkRate')`,\n );\n\n assert(\n typeof EdgeRateLimiter.prototype.checkRate,\n 'function',\n `typeof EdgeRateLimiter.prototype.checkRate`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype.checkRate,\n 'length',\n );\n expected = {\n value: 5,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype.checkRate, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n EdgeRateLimiter.prototype.checkRate,\n 'name',\n );\n expected = {\n value: 'checkRate',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(EdgeRateLimiter.prototype.checkRate, 'name')`,\n );\n }\n });\n\n // EdgeRateLimiter constructor\n {\n routes.set(\n '/edge-rate-limiter/constructor/called-as-regular-function',\n () => {\n assertThrows(\n () => {\n EdgeRateLimiter();\n },\n Error,\n `calling a builtin EdgeRateLimiter constructor without new is forbidden`,\n );\n },\n );\n routes.set(\n '/edge-rate-limiter/constructor/called-as-constructor-no-arguments',\n () => {\n assertThrows(\n () => new EdgeRateLimiter(),\n Error,\n `EdgeRateLimiter constructor: At least 2 arguments required, but only 0 passed`,\n );\n },\n );\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/edge-rate-limiter/constructor/rate-counter-not-instance-of-rateCounter',\n () => {\n assertThrows(\n () => {\n new EdgeRateLimiter(true, true);\n },\n Error,\n `EdgeRateLimiter constructor: rateCounter parameter must be an instance of RateCounter`,\n );\n },\n );\n routes.set(\n '/edge-rate-limiter/constructor/penalty-box-not-instance-of-penaltyBox',\n () => {\n assertThrows(\n () => {\n new EdgeRateLimiter(new RateCounter(RATE_COUNTER_NAME), true);\n },\n Error,\n `EdgeRateLimiter constructor: penaltyBox parameter must be an instance of PenaltyBox`,\n );\n },\n );\n routes.set('/edge-rate-limiter/constructor/happy-path', () => {\n assert(\n new EdgeRateLimiter(\n new RateCounter(RATE_COUNTER_NAME),\n new PenaltyBox(PENALTY_BOX_NAME),\n ) instanceof EdgeRateLimiter,\n true,\n `new EdgeRateLimiter(new RateCounter(\"rc\"), new PenaltyBox(PENALTY_BOX_NAME)) instanceof EdgeRateLimiter`,\n );\n });\n }\n\n // EdgeRateLimiter checkRate method\n // checkRate(entry: string, delta: number, window: [1, 10, 60], limit: number, timeToLive: number): boolean;\n {\n routes.set('/edge-rate-limiter/checkRate/called-as-constructor', () => {\n assertThrows(() => {\n new EdgeRateLimiter.prototype.checkRate('entry');\n }, Error);\n });\n // Ensure we correctly coerce the parameter to a string as according to\n // https://tc39.es/ecma262/#sec-tostring\n routes.set(\n '/edge-rate-limiter/checkRate/entry-parameter-calls-7.1.17-ToString',\n () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol('sentinel');\n const entry = {\n toString() {\n throw sentinel;\n },\n };\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate(entry, 1, 1, 1, 1);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n console.log({ thrownError });\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate(Symbol(), 1, 1, 1, 1);\n },\n Error,\n `can't convert symbol to string`,\n );\n },\n );\n routes.set(\n '/edge-rate-limiter/checkRate/entry-parameter-not-supplied',\n () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate();\n },\n Error,\n `checkRate: At least 5 arguments required, but only 0 passed`,\n );\n },\n );\n routes.set('/edge-rate-limiter/checkRate/delta-parameter-negative', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', -1, 1, 1, 1);\n },\n Error,\n `checkRate: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/delta-parameter-infinity', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', Infinity, 1, 1, 1);\n },\n Error,\n `checkRate: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/delta-parameter-NaN', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', NaN, 1, 1, 1);\n },\n Error,\n `checkRate: delta parameter is an invalid value, only positive numbers can be used for delta values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/window-parameter-negative', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, -1, 1, 1);\n },\n Error,\n `checkRate: window parameter must be either: 1, 10, or 60`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/window-parameter-infinity', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, Infinity, 1, 1);\n },\n Error,\n `checkRate: window parameter must be either: 1, 10, or 60`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/window-parameter-NaN', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, NaN, 1, 1);\n },\n Error,\n `checkRate: window parameter must be either: 1, 10, or 60`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/limit-parameter-negative', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, -1, 1);\n },\n Error,\n `checkRate: limit parameter is an invalid value, only positive numbers can be used for limit values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/limit-parameter-infinity', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, Infinity, 1);\n },\n Error,\n `checkRate: limit parameter is an invalid value, only positive numbers can be used for limit values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/limit-parameter-NaN', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, NaN, 1);\n },\n Error,\n `checkRate: limit parameter is an invalid value, only positive numbers can be used for limit values.`,\n );\n });\n routes.set(\n '/edge-rate-limiter/checkRate/timeToLive-parameter-negative',\n () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, 1, -1);\n },\n Error,\n `checkRate: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n },\n );\n routes.set(\n '/edge-rate-limiter/checkRate/timeToLive-parameter-infinity',\n () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, 1, Infinity);\n },\n Error,\n `checkRate: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n },\n );\n routes.set('/edge-rate-limiter/checkRate/timeToLive-parameter-NaN', () => {\n assertThrows(\n () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n erl.checkRate('entry', 1, 1, 1, NaN);\n },\n Error,\n `checkRate: timeToLive parameter is an invalid value, only numbers from 1 to 60 can be used for timeToLive values.`,\n );\n });\n routes.set('/edge-rate-limiter/checkRate/returns-boolean', () => {\n let rc = new RateCounter(RATE_COUNTER_NAME);\n let pb = new PenaltyBox(PENALTY_BOX_NAME);\n let erl = new EdgeRateLimiter(rc, pb);\n assert(\n erl.checkRate('woof', 1, 10, 100, 5),\n false,\n \"erl.checkRate('meow', 1, 10, 100, 5)\",\n );\n });\n }\n}\n", "/* eslint-env serviceworker */\nimport { env } from 'fastly:env';\nimport { routes, isRunningLocally } from './routes.js';\nimport { strictEqual } from './assertions.js';\n\n// hostname didn't exist at initialization, so can still be captured at runtime\nconst wizerHostname = env('FASTLY_HOSTNAME');\nconst wizerLocal = env('LOCAL_TEST');\n\nroutes.set('/env', () => {\n strictEqual(wizerHostname, undefined);\n\n if (isRunningLocally()) {\n strictEqual(\n env('FASTLY_HOSTNAME'),\n 'localhost',\n `env(\"FASTLY_HOSTNAME\") === \"localhost\"`,\n );\n } else {\n strictEqual(env('FASTLY_HOSTNAME'), undefined);\n }\n\n strictEqual(wizerLocal, 'local val');\n\n // at runtime these remain captured from Wizer time, even if we didn't call env\n strictEqual(env('LOCAL_TEST'), 'local val');\n strictEqual(env('TEST'), 'foo');\n});\n", "export const createFanoutHandoff = globalThis.fastly.createFanoutHandoff;", "import { assert, assertDoesNotThrow, assertThrows } from './assertions.js';\nimport { routes } from './routes.js';\nimport { createFanoutHandoff } from 'fastly:fanout';\n\nroutes.set('/createFanoutHandoff', () => {\n assert(typeof createFanoutHandoff, 'function', 'typeof createFanoutHandoff');\n\n assert(\n createFanoutHandoff.name,\n 'createFanoutHandoff',\n 'createFanoutHandoff.name',\n );\n\n assert(createFanoutHandoff.length, 2, 'createFanoutHandoff.length');\n\n assertDoesNotThrow(() => createFanoutHandoff(new Request('.'), 'hello'));\n\n assertThrows(() => createFanoutHandoff());\n\n assertThrows(() => createFanoutHandoff(1, ''));\n\n let result = createFanoutHandoff(new Request('.'), 'hello');\n assert(result instanceof Response, true, 'result instanceof Response');\n\n assertThrows(\n () => new createFanoutHandoff(new Request('.'), 'hello'),\n TypeError,\n );\n\n assertDoesNotThrow(() => {\n createFanoutHandoff.call(undefined, new Request('.'), '1');\n });\n\n // https://tc39.es/ecma262/#sec-tostring\n let sentinel;\n const test = () => {\n sentinel = Symbol();\n const key = {\n toString() {\n throw sentinel;\n },\n };\n createFanoutHandoff(new Request('.'), key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n createFanoutHandoff(new Request('.'), Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n\n assertThrows(\n () => createFanoutHandoff(new Request('.')),\n TypeError,\n `createFanoutHandoff: At least 2 arguments required, but only 1 passed`,\n );\n\n assertThrows(\n () => createFanoutHandoff(new Request('.'), ''),\n Error,\n `createFanoutHandoff: Backend parameter can not be an empty string`,\n );\n});\n", "export const createWebsocketHandoff = globalThis.fastly.createWebsocketHandoff;", "import { assert, assertDoesNotThrow, assertThrows } from './assertions.js';\nimport { routes } from './routes.js';\nimport { createWebsocketHandoff } from 'fastly:websocket';\n\nroutes.set('/createWebsocketHandoff', () => {\n assert(\n typeof createWebsocketHandoff,\n 'function',\n 'typeof createWebsocketHandoff',\n );\n\n assert(\n createWebsocketHandoff.name,\n 'createWebsocketHandoff',\n 'createWebsocketHandoff.name',\n );\n\n assert(createWebsocketHandoff.length, 2, 'createWebsocketHandoff.length');\n\n assertDoesNotThrow(() => createWebsocketHandoff(new Request('.'), 'hello'));\n\n assertThrows(() => createWebsocketHandoff());\n\n assertThrows(() => createWebsocketHandoff(1, ''));\n\n let result = createWebsocketHandoff(new Request('.'), 'hello');\n assert(result instanceof Response, true, 'result instanceof Response');\n\n assertThrows(\n () => new createWebsocketHandoff(new Request('.'), 'hello'),\n TypeError,\n );\n\n assertDoesNotThrow(() => {\n createWebsocketHandoff.call(undefined, new Request('.'), '1');\n });\n\n // https://tc39.es/ecma262/#sec-tostring\n let sentinel;\n const test = () => {\n sentinel = Symbol();\n const key = {\n toString() {\n throw sentinel;\n },\n };\n createWebsocketHandoff(new Request('.'), key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n createWebsocketHandoff(new Request('.'), Symbol());\n },\n TypeError,\n `can't convert symbol to string`,\n );\n\n assertThrows(\n () => createWebsocketHandoff(new Request('.')),\n TypeError,\n `createWebsocketHandoff: At least 2 arguments required, but only 1 passed`,\n );\n\n assertThrows(\n () => createWebsocketHandoff(new Request('.'), ''),\n Error,\n `createWebsocketHandoff: Backend parameter can not be an empty string`,\n );\n});\n", "/// \n/* eslint-env serviceworker */\n\nimport { assert } from './assertions.js';\nimport { routes } from './routes.js';\nimport { sdkVersion } from 'fastly:experimental';\n\nroutes.set('/fastly/now', function () {\n assert(typeof fastly.now, 'function', 'typeof fastly.now');\n\n assert(fastly.now.name, 'now', 'fastly.now.name');\n\n assert(fastly.now.length, 0, 'fastly.now.length');\n\n assert(typeof fastly.now(), 'number', `typeof fastly.now()`);\n\n assert(fastly.now() > Date.now(), true, `fastly.now() > Date.now()`);\n});\n\nroutes.set('/fastly/version', function () {\n assert(typeof fastly.sdkVersion, 'string', 'typeof fastly.sdkVersion');\n\n assert(\n fastly.sdkVersion,\n sdkVersion,\n 'fastly.sdkVersion matches fastly:experimental#sdkVersion',\n );\n});\n", "\nexport const Backend = globalThis.Backend;\nexport const setDefaultDynamicBackendConfig = Object.getOwnPropertyDescriptor(globalThis.fastly, 'allowDynamicBackends').set;\nconst allowDynamicBackends = Object.getOwnPropertyDescriptor(globalThis.fastly, 'allowDynamicBackends').set;\nexport const setDefaultBackend = Object.getOwnPropertyDescriptor(globalThis.fastly, 'defaultBackend').set;\nexport function enforceExplicitBackends (defaultBackend) {\n allowDynamicBackends(false);\n if (defaultBackend) setDefaultBackend(defaultBackend);\n}\n", "/// \nimport { assertRejects } from './assertions.js';\nimport { routes } from './routes.js';\nimport { Backend } from 'fastly:backend';\nimport { allowDynamicBackends } from 'fastly:experimental';\n\nroutes.set('/fetch-errors', async () => {\n allowDynamicBackends(true);\n await assertRejects(\n async () => {\n await fetch('http://127.0.0.1');\n },\n DOMException,\n 'Connection refused',\n );\n\n await assertRejects(\n async () => {\n await fetch('https://fastly.com/', {\n backend: new Backend({\n name: 'b1',\n target: 'fastly.com:8080',\n }),\n });\n },\n DOMException,\n 'Connection refused',\n );\n\n await assertRejects(\n async () => {\n await fetch('https://fastly.com', {\n backend: new Backend({\n name: 'b3',\n target: 'fastly.com',\n useSSL: true,\n certificateHostname: 'google.com',\n }),\n });\n },\n DOMException,\n 'TLS certificate error',\n );\n});\n", "export const getGeolocationForIpAddress = globalThis.fastly.getGeolocationForIpAddress;", "/* eslint-env serviceworker */\n/* global fastly */\nimport { assert, assertThrows, strictEqual } from './assertions.js';\nimport { getGeolocationForIpAddress } from 'fastly:geolocation';\nimport { isRunningLocally, routes } from './routes.js';\n\nroutes.set('/fastly/getgeolocationforipaddress/interface', async function () {\n let actual = Reflect.getOwnPropertyDescriptor(\n fastly,\n 'getGeolocationForIpAddress',\n );\n let expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: fastly.getGeolocationForIpAddress,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(fastly, 'getGeolocationForIpAddress)`,\n );\n\n assert(\n typeof fastly.getGeolocationForIpAddress,\n 'function',\n `typeof fastly.getGeolocationForIpAddress`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n fastly.getGeolocationForIpAddress,\n 'length',\n );\n expected = {\n value: 1,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(fastly.getGeolocationForIpAddress, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n fastly.getGeolocationForIpAddress,\n 'name',\n );\n expected = {\n value: 'getGeolocationForIpAddress',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(fastly.getGeolocationForIpAddress, 'name')`,\n );\n});\n\nroutes.set(\n '/fastly/getgeolocationforipaddress/called-as-constructor',\n async () => {\n assertThrows(\n () => {\n new fastly.getGeolocationForIpAddress('1.2.3.4');\n },\n TypeError,\n `fastly.getGeolocationForIpAddress is not a constructor`,\n );\n },\n);\n// https://tc39.es/ecma262/#sec-tostring\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-calls-7.1.17-ToString',\n async () => {\n let sentinel;\n const test = () => {\n sentinel = Symbol();\n const key = {\n toString() {\n throw sentinel;\n },\n };\n fastly.getGeolocationForIpAddress(key);\n };\n assertThrows(test);\n try {\n test();\n } catch (thrownError) {\n assert(thrownError, sentinel, 'thrownError === sentinel');\n }\n assertThrows(\n () => {\n fastly.getGeolocationForIpAddress(Symbol());\n },\n Error,\n `can't convert symbol to string`,\n );\n },\n);\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-not-supplied',\n async () => {\n assertThrows(\n () => {\n fastly.getGeolocationForIpAddress();\n },\n TypeError,\n `fastly.getGeolocationForIpAddress: At least 1 argument required, but only 0 passed`,\n );\n },\n);\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-empty-string',\n async () => {\n assertThrows(\n () => {\n fastly.getGeolocationForIpAddress('');\n },\n Error,\n `Invalid address passed to fastly.getGeolocationForIpAddress`,\n );\n },\n);\n\nlet geoFields = [\n 'as_name',\n 'as_number',\n 'area_code',\n 'city',\n 'conn_speed',\n 'conn_type',\n 'continent',\n 'country_code',\n 'country_code3',\n 'country_name',\n 'gmt_offset',\n 'latitude',\n 'longitude',\n 'metro_code',\n 'postal_code',\n 'proxy_description',\n 'proxy_type',\n 'region',\n 'utc_offset',\n];\n\nroutes.set('/fastly/getgeolocationforipaddress/bad-ip', async () => {\n let geo = fastly.getGeolocationForIpAddress('0.0.0.0');\n if (isRunningLocally()) {\n strictEqual(\n geo,\n null,\n `fastly.getGeolocationForIpAddress('0.0.0.0') == null`,\n );\n } else {\n strictEqual(geo.as_name, '?');\n }\n assertThrows(() => {\n fastly.getGeolocationForIpAddress('999.999.999.999');\n }, Error);\n});\n\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-ipv4-string',\n async () => {\n let geo = fastly.getGeolocationForIpAddress('151.101.1.1');\n if (isRunningLocally()) {\n strictEqual(geo, null);\n } else {\n assert(\n Object.keys(geo),\n geoFields,\n `Object.keys(fastly.getGeolocationForIpAddress('151.101.1.1')) == geoFields`,\n );\n }\n },\n);\n\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-compressed-ipv6-string',\n async () => {\n if (isRunningLocally()) {\n let geo = fastly.getGeolocationForIpAddress('2607:f0d0:1002:51::4');\n assert(\n Object.keys(geo),\n geoFields,\n `Object.keys(fastly.getGeolocationForIpAddress('2607:f0d0:1002:51::4')) == geoFields`,\n );\n }\n },\n);\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-shortened-ipv6-string',\n async () => {\n if (isRunningLocally()) {\n let geo = fastly.getGeolocationForIpAddress(\n '2607:f0d0:1002:0051:0:0:0:0004',\n );\n assert(\n Object.keys(geo),\n geoFields,\n `Object.keys(fastly.getGeolocationForIpAddress('2607:f0d0:1002:0051:0:0:0:0004')) == geoFields`,\n );\n }\n },\n);\nroutes.set(\n '/fastly/getgeolocationforipaddress/parameter-expanded-ipv6-string',\n async () => {\n if (isRunningLocally()) {\n let geo = fastly.getGeolocationForIpAddress(\n '2607:f0d0:1002:0051:0000:0000:0000:0004',\n );\n assert(\n Object.keys(geo),\n geoFields,\n `Object.keys(fastly.getGeolocationForIpAddress('2607:f0d0:1002:0051:0000:0000:0000:0004')) == geoFields`,\n );\n }\n },\n);\n\nroutes.set('/fastly/getgeolocationforipaddress/called-unbound', async () => {\n if (isRunningLocally()) {\n let geo = fastly.getGeolocationForIpAddress.call(\n undefined,\n '2607:f0d0:1002:0051:0000:0000:0000:0004',\n );\n assert(\n Object.keys(geo),\n geoFields,\n `Object.keys(fastly.getGeolocationForIpAddress('2607:f0d0:1002:0051:0000:0000:0000:0004')) == geoFields`,\n );\n }\n});\n\nroutes.set('/fastly:geolocation', async () => {\n assert(\n getGeolocationForIpAddress,\n fastly.getGeolocationForIpAddress,\n 'getGeolocationForIpAddress === fastly.getGeolocationForIpAddress',\n );\n});\n", "/* eslint-env serviceworker */\n\nimport { routes } from './routes.js';\nimport { assert } from './assertions.js';\nimport { CacheOverride } from 'fastly:cache-override';\n\nroutes.set('/headers/construct', async () => {\n const headers = new Headers();\n headers.set('foo', 'bar');\n return new Response('check headers', { headers });\n});\n\nroutes.set('/headers/getsetcookie', async () => {\n let response = await fetch(\n 'https://http-me.glitch.me/meow?header=Set-Cookie:name1=value1',\n {\n backend: 'httpme',\n },\n );\n response.headers.append('Set-Cookie', 'name2=value2');\n console.log(\n 'response.headers.getSetCookie()',\n response.headers.getSetCookie(),\n );\n});\n\nroutes.set('/headers/from-response/set', async () => {\n const response = await fetch('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('pass'),\n });\n response.headers.set('cuStom', 'test');\n return response;\n});\n\nroutes.set('/headers/from-response/delete-invalid', async () => {\n const response = await fetch('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('pass'),\n });\n response.headers.delete('none');\n return response;\n});\n\nroutes.set('/headers/from-response/set-delete', async () => {\n const response = await fetch('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('pass'),\n });\n response.headers.set('custom', 'test');\n response.headers.delete('access-control-allow-origin');\n return response;\n});\n", "export const HTMLRewritingStream = globalThis.HTMLRewritingStream;", "/* eslint-env serviceworker */\n\nimport { routes } from './routes.js';\nimport { HTMLRewritingStream } from 'fastly:html-rewriter';\nimport {\n assert,\n assertThrows,\n assertRejects,\n strictEqual,\n} from './assertions.js';\n\nroutes.set('/html-rewriter/set-attribute', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestHello, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.setAttribute('class', 'a-rewritten-class');\n e.setAttribute('id', 'a-rewritten-id');\n e.setAttribute('custom-attr', 'custom-value');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/get-attribute', async () => {\n const toRewrite =\n 'TestHello, World!
';\n let classAttr, idAttr;\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n classAttr = e.getAttribute('class');\n idAttr = e.getAttribute('id');\n }),\n );\n await new Response(body, { headers: { 'Content-Type': 'text/html' } }).text();\n strictEqual(classAttr, 'a-class');\n strictEqual(idAttr, 'an-id');\n});\n\nroutes.set('/html-rewriter/remove-attribute', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestHello, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.removeAttribute('class');\n e.removeAttribute('id');\n e.removeAttribute('custom-attr');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/replace-with', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestGoodbye, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.replaceWith('Goodbye, World!
');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/replace-children', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestGoodbye, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.replaceChildren('Goodbye, World!');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/insert', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestBefore - Prefix - Hello, World! - Suffix
- After';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.before('Before - ');\n e.prepend('Prefix - ');\n e.append(' - Suffix');\n e.after(' - After');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/complex-selector', async () => {\n const toRewrite =\n \"TestHello, World!
Hello again, World!
\";\n const expected =\n \"TestHello, World!
Hello again, World!
\";\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('div.a-class > h1[id^=\"an\"]', (e) => {\n e.setAttribute('custom-attr', 'custom-value');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/no-match-rewritten-content', async () => {\n const toRewrite =\n 'Test';\n const expected =\n 'TestHello, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream()\n .onElement('div', (e) => {\n e.setAttribute('class', 'a-class');\n e.append('Hello, World!
');\n })\n .onElement('h1', (e) => {\n // should not be called, as h1 does not exist in original content\n e.setAttribute('custom-attr', 'custom-value');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/multiple-handlers', async () => {\n const toRewrite =\n \"TestHello, World!
Hello again, World!
\";\n const expected =\n 'TestHello, World!
Hello again, World!
';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream()\n .onElement('div.a-class', (e) => {\n e.setAttribute('custom-attr', 'custom-value');\n })\n .onElement('h1', (e) => {\n e.setAttribute('another-attr', 'another-value');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/invalid-selector', async () => {\n assertThrows(() => {\n new HTMLRewritingStream().onElement('div..a-class', (e) => {\n e.setAttribute('custom-attr', 'custom-value');\n });\n }, Error);\n});\n\nroutes.set('/html-rewriter/invalid-handler', async () => {\n assertThrows(() => {\n new HTMLRewritingStream().onElement(\n 'div.a-class',\n 'this is not a function',\n );\n }, Error);\n});\n\nroutes.set('/html-rewriter/throw-in-handler', async () => {\n const toRewrite =\n \"TestHello, World!
\";\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('div.a-class', (e) => {\n throw new Error('This is an error from the handler');\n }),\n );\n assertRejects(async () => {\n await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n }, Error);\n});\n\nroutes.set('/html-rewriter/invalid-html', async () => {\n const toRewrite = 'This is not HTML content';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('div.a-class', (e) => {\n e.setAttribute('custom-attr', 'custom-value');\n }),\n );\n assertRejects(async () => {\n await new Response(body, {\n headers: { 'Content-Type': 'text/plain' },\n }).text();\n }, Error);\n});\n\nroutes.set('/html-rewriter/insertion-order', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expected =\n 'TestFirst - Before - Prefix - Other Prefix - Hello, World! - Suffix - Other Suffix
- After - Last';\n let body = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('h1', (e) => {\n e.before('First - ');\n e.before('Before - ');\n // The insertion position is maintained, so prepends are inserted in reverse order\n e.prepend('Other Prefix - ');\n e.prepend('Prefix - ');\n e.append(' - Suffix');\n e.append(' - Other Suffix');\n // The insertion position is maintained, so appends are inserted in reverse order\n e.after(' - Last');\n e.after(' - After');\n }),\n );\n let text = await new Response(body, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(text, expected);\n});\n\nroutes.set('/html-rewriter/escape-html', async () => {\n const toRewrite =\n 'TestHello, World!
';\n const expectedNoEscape =\n 'TestHello, Beautiful World!
';\n const expectedEscape =\n 'TestHello, <strong>Beautiful</strong> World!
';\n let bodyNoEscape = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('em', (e) => {\n e.before('Beautiful ', { escapeHTML: false });\n }),\n );\n let textNoEscape = await new Response(bodyNoEscape, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(textNoEscape, expectedNoEscape);\n\n let bodyEscape = new Response(toRewrite, {\n headers: { 'Content-Type': 'text/html' },\n }).body.pipeThrough(\n new HTMLRewritingStream().onElement('em', (e) => {\n e.before('Beautiful ', { escapeHTML: true });\n }),\n );\n let textEscape = await new Response(bodyEscape, {\n headers: { 'Content-Type': 'text/html' },\n }).text();\n strictEqual(textEscape, expectedEscape);\n});\n", "import { routes } from './routes.js';\nimport { assert } from './assertions.js';\nimport { includeBytes } from 'fastly:experimental';\n\nlet message;\ntry {\n message = includeBytes('message.txt');\n} catch {}\n\nconst expected = [\n 104, 101, 108, 108, 111, 32, 105, 110, 99, 108, 117, 100, 101, 66, 121, 116,\n 101, 115, 10,\n];\n\nroutes.set('/includeBytes', () => {\n assert(Array.from(message), expected, `message === expected`);\n});\n", "export const { \n Region, Auto, Format, BWAlgorithm, Disable, Enable, Fit, Metadata, \n Optimize, Orient, Profile, ResizeFilter, CropMode, optionsToQueryString\n } = globalThis.fastly.imageOptimizer;", "/* eslint-env serviceworker */\n\nimport { routes } from './routes.js';\nimport {\n Region,\n Auto,\n BWAlgorithm,\n CropMode,\n Disable,\n Enable,\n Fit,\n Metadata,\n Optimize,\n Orient,\n Profile,\n ResizeFilter,\n optionsToQueryString,\n} from 'fastly:image-optimizer';\nimport { assert, assertThrows } from './assertions.js';\n\n// Enums\nroutes.set('/image-optimizer/options/region', () => {\n assert(optionsToQueryString({ region: Region.UsEast }), 'region=us_east');\n assert(optionsToQueryString({ region: Region.Asia }), 'region=asia');\n assertThrows(() => optionsToQueryString({ region: 'invalid' }), TypeError);\n assertThrows(() => optionsToQueryString({}), TypeError);\n});\nroutes.set('/image-optimizer/options/auto', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, auto: Auto.AVIF }),\n 'region=asia&auto=avif',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, auto: Auto.WEBP }),\n 'region=asia&auto=webp',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, auto: 'invalid' }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/bw', () => {\n assert(\n optionsToQueryString({\n region: Region.EuCentral,\n bw: BWAlgorithm.Threshold,\n }),\n 'region=eu_central&bw=threshold',\n );\n assert(\n optionsToQueryString({\n region: Region.EuCentral,\n bw: BWAlgorithm.Atkinson,\n }),\n 'region=eu_central&bw=atkinson',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.EuCentral, bw: 'invalid' }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/crop-mode', () => {\n const qs = optionsToQueryString({\n region: Region.UsWest,\n crop: {\n size: { absolute: { width: 100, height: 100 } },\n mode: CropMode.Smart,\n },\n });\n assert(qs.includes('smart'), true);\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.UsWest,\n crop: { size: { absolute: { width: 100, height: 100 } }, mode: 'bad' },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/disable', () => {\n assert(\n optionsToQueryString({\n region: Region.Australia,\n disable: Disable.Upscale,\n }),\n 'region=australia&disable=upscale',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, disable: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/enable', () => {\n assert(\n optionsToQueryString({ region: Region.Australia, enable: Enable.Upscale }),\n 'region=australia&enable=upscale',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, enable: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/fit', () => {\n assert(\n optionsToQueryString({ region: Region.Australia, fit: Fit.Crop }),\n 'region=australia&fit=crop',\n );\n assert(\n optionsToQueryString({ region: Region.Australia, fit: Fit.Cover }),\n 'region=australia&fit=cover',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, fit: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/metadata', () => {\n assert(\n optionsToQueryString({ region: Region.Australia, metadata: Metadata.C2PA }),\n 'region=australia&metadata=c2pa',\n );\n assert(\n optionsToQueryString({\n region: Region.Australia,\n metadata: Metadata.CopyrightAndC2PA,\n }),\n 'region=australia&metadata=copyright,c2pa',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, metadata: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/optimize', () => {\n assert(\n optionsToQueryString({ region: Region.Australia, optimize: Optimize.Low }),\n 'region=australia&optimize=low',\n );\n assert(\n optionsToQueryString({ region: Region.Australia, optimize: Optimize.High }),\n 'region=australia&optimize=high',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, optimize: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/orient', () => {\n assert(\n optionsToQueryString({ region: Region.Australia, orient: Orient.Default }),\n 'region=australia&orient=1',\n );\n assert(\n optionsToQueryString({\n region: Region.Australia,\n orient: Orient.FlipHorizontalOrientRight,\n }),\n 'region=australia&orient=7',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, orient: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/profile', () => {\n assert(\n optionsToQueryString({\n region: Region.Australia,\n profile: Profile.Baseline,\n }),\n 'region=australia&profile=baseline',\n );\n assert(\n optionsToQueryString({ region: Region.Australia, profile: Profile.Main }),\n 'region=australia&profile=main',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, profile: 'invalid' }),\n );\n});\nroutes.set('/image-optimizer/options/resizeFilter', () => {\n assert(\n optionsToQueryString({\n region: Region.Australia,\n resizeFilter: ResizeFilter.Bicubic,\n }),\n 'region=australia&resize-filter=bicubic',\n );\n assert(\n optionsToQueryString({\n region: Region.Australia,\n resizeFilter: ResizeFilter.Lanczos2,\n }),\n 'region=australia&resize-filter=lanczos2',\n );\n assertThrows(() =>\n optionsToQueryString({ region: Region.Australia, resizeFilter: 'invalid' }),\n );\n});\n\n// Other options\nroutes.set('/image-optimizer/options/bgColor', () => {\n // Hex strings\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: '123456',\n }),\n 'region=asia&bg-color=123456',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: 'a2345e',\n }),\n 'region=asia&bg-color=a2345e',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: '123',\n }),\n 'region=asia&bg-color=123',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: 'a2e',\n }),\n 'region=asia&bg-color=a2e',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n bgColor: '12',\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n bgColor: '12j',\n }),\n TypeError,\n );\n\n // RGB(A)\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: {\n r: 255,\n g: 0,\n b: 128,\n },\n }),\n 'region=asia&bg-color=255,0,128',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n bgColor: {\n r: 255,\n g: 0,\n b: 128,\n a: 0.5,\n },\n }),\n 'region=asia&bg-color=255,0,128,0.500000',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n bgColor: {\n r: 12,\n b: 12,\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n bgColor: {\n r: 12,\n b: 1212,\n g: 12,\n },\n }),\n TypeError,\n );\n\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n bgColor: 123123,\n }),\n TypeError,\n );\n});\n\nroutes.set('/image-optimizer/options/blur', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, blur: 0.5 }),\n 'region=asia&blur=0.500000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, blur: 1000 }),\n 'region=asia&blur=1000.000000',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, blur: 1001 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, blur: 0.4 }),\n TypeError,\n );\n\n assert(\n optionsToQueryString({ region: Region.Asia, blur: '10%' }),\n 'region=asia&blur=10.000000p',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, blur: '0.5%' }),\n 'region=asia&blur=0.500000p',\n );\n});\nroutes.set('/image-optimizer/options/brightness', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, brightness: 0.5 }),\n 'region=asia&brightness=0.500000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, brightness: 100 }),\n 'region=asia&brightness=100.000000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, brightness: -100 }),\n 'region=asia&brightness=-100.000000',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, brightness: 1001 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, brightness: -101 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/canvas', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n },\n }),\n 'region=asia&canvas=100,10.000000p',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n },\n }),\n 'region=asia&canvas=4.000000:3.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n position: {\n x: 10,\n offsetY: 10,\n },\n },\n }),\n 'region=asia&canvas=100,10.000000p,x10,offset-y10.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n 'region=asia&canvas=4.000000:3.000000,offset-x10.000000,y10.000000p',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n x: 100,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n canvas: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/crop', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n },\n }),\n 'region=asia&crop=100,10.000000p',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n },\n }),\n 'region=asia&crop=4.000000:3.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n position: {\n x: 10,\n offsetY: 10,\n },\n },\n }),\n 'region=asia&crop=100,10.000000p,x10,offset-y10.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n 'region=asia&crop=4.000000:3.000000,offset-x10.000000,y10.000000p',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n mode: CropMode.Safe,\n },\n }),\n 'region=asia&crop=4.000000:3.000000,offset-x10.000000,y10.000000p,safe',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n x: 100,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n crop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n mode: 'invalid',\n },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/precrop', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n },\n }),\n 'region=asia&precrop=100,10.000000p',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n },\n }),\n 'region=asia&precrop=4.000000:3.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n absolute: {\n width: 100,\n height: '10%',\n },\n },\n position: {\n x: 10,\n offsetY: 10,\n },\n },\n }),\n 'region=asia&precrop=100,10.000000p,x10,offset-y10.000000',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n 'region=asia&precrop=4.000000:3.000000,offset-x10.000000,y10.000000p',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n mode: CropMode.Safe,\n },\n }),\n 'region=asia&precrop=4.000000:3.000000,offset-x10.000000,y10.000000p,safe',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n x: 100,\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: '4%',\n height: 3,\n },\n },\n position: {\n y: '10%',\n },\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n precrop: {\n size: {\n ratio: {\n width: 4,\n height: 3,\n },\n },\n position: {\n offsetX: 10,\n y: '10%',\n },\n mode: 'invalid',\n },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/dpr', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, dpr: 1.5 }),\n 'region=asia&dpr=1.500000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, dpr: 10 }),\n 'region=asia&dpr=10.000000',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, dpr: '1001' }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, dpr: 1001 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, dpr: 0.5 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/frame', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, frame: 1 }),\n 'region=asia&frame=1',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, frame: 2 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/height', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, height: 1000 }),\n 'region=asia&height=1000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, height: '10%' }),\n 'region=asia&height=10.000000p',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, height: '1001' }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, height: 100.5 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/level', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, level: '1.1' }),\n 'region=asia&level=1.1',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, level: '5.1' }),\n 'region=asia&level=5.1',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, level: 5.1 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, level: '7.1' }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/pad', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n pad: {\n top: 10,\n bottom: 20,\n left: '10%',\n right: '20%',\n },\n }),\n 'region=asia&pad=10,20.000000p,20,10.000000p',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n pad: {\n top: 10,\n bottom: 20,\n left: '10',\n right: '20%',\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n pad: {\n top: 10,\n left: '10',\n right: '20%',\n },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/quality', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, quality: 1 }),\n 'region=asia&quality=1',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, quality: 100 }),\n 'region=asia&quality=100',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, quality: 1001 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, quality: 1.5 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, quality: 0.4 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/saturation', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, saturation: 1 }),\n 'region=asia&saturation=1.000000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, saturation: 100 }),\n 'region=asia&saturation=100.000000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, saturation: -100 }),\n 'region=asia&saturation=-100.000000',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, saturation: 1001 }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, saturation: -101 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/sharpen', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: 10,\n radius: 10,\n threshold: 1,\n },\n }),\n 'region=asia&sharpen=a10.000000,r10.000000,t1',\n );\n assert(\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: 0.1,\n radius: 0.5,\n threshold: 255,\n },\n }),\n 'region=asia&sharpen=a0.100000,r0.500000,t255',\n );\n assertThrows(() => {\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: 0.1,\n radius: 0.5,\n threshold: 256,\n },\n });\n }, TypeError);\n assertThrows(() => {\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: 0.1,\n radius: 0.4,\n threshold: 255,\n },\n });\n }, TypeError);\n assertThrows(() => {\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: -1,\n radius: 0.5,\n threshold: 255,\n },\n });\n }, TypeError);\n assertThrows(() => {\n optionsToQueryString({\n region: Region.Asia,\n sharpen: {\n amount: 1,\n radius: 1,\n },\n });\n }, TypeError);\n});\nroutes.set('/image-optimizer/options/trim', () => {\n assert(\n optionsToQueryString({\n region: Region.Asia,\n trim: {\n top: 10,\n bottom: 20,\n left: '10%',\n right: '20%',\n },\n }),\n 'region=asia&trim=10,20.000000p,20,10.000000p',\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n trim: {\n top: 10,\n bottom: 20,\n left: '10',\n right: '20%',\n },\n }),\n TypeError,\n );\n assertThrows(\n () =>\n optionsToQueryString({\n region: Region.Asia,\n trim: {\n top: 10,\n left: '10',\n right: '20%',\n },\n }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/viewbox', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, viewbox: 1 }),\n 'region=asia&viewbox=1',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, viewbox: 2 }),\n TypeError,\n );\n});\nroutes.set('/image-optimizer/options/width', () => {\n assert(\n optionsToQueryString({ region: Region.Asia, width: 1000 }),\n 'region=asia&width=1000',\n );\n assert(\n optionsToQueryString({ region: Region.Asia, width: '10%' }),\n 'region=asia&width=10.000000p',\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, width: '1001' }),\n TypeError,\n );\n assertThrows(\n () => optionsToQueryString({ region: Region.Asia, width: 100.5 }),\n TypeError,\n );\n});\n", "export const Logger = globalThis.Logger;\nexport const configureConsole = Logger.configureConsole;\ndelete globalThis.Logger.configureConsole;\n", "import { Logger, configureConsole } from 'fastly:logger';\nimport { routes, isRunningLocally } from './routes';\n\nconfigureConsole({ prefixing: false, stderr: true });\n\nconst earlyLogger = new Logger('AnotherLog');\n\nroutes.set('/logger', () => {\n if (isRunningLocally()) {\n let logger = new Logger('ComputeLog');\n logger.log('Hello!');\n earlyLogger.log('World!');\n }\n\n console.log('LOG');\n console.error('ERROR');\n\n return new Response();\n});\n", "/// \n/* eslint-env serviceworker */\n\nimport { CacheOverride } from 'fastly:cache-override';\nimport { assert, assertRejects } from './assertions.js';\nimport { routes, isRunningLocally } from './routes.js';\n\nasync function requestInitObjectLiteral(manualFramingHeaders) {\n let request = new Request('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n method: 'POST',\n body: 'meow',\n manualFramingHeaders,\n headers: {\n 'content-length': '1',\n },\n });\n let response = await fetch(request);\n let body = await response.json();\n return body?.headers?.['content-length'];\n}\n\nasync function requestMethod(manualFramingHeaders) {\n let request = new Request('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n method: 'POST',\n body: 'meow',\n headers: {\n 'content-length': '1',\n },\n });\n request.setManualFramingHeaders(manualFramingHeaders);\n let response = await fetch(request);\n let body = await response.json();\n return body?.headers?.['content-length'];\n}\n\nasync function requestClone(manualFramingHeaders) {\n let request = new Request('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n method: 'POST',\n body: 'meow',\n manualFramingHeaders,\n headers: {\n 'content-length': '1',\n },\n });\n let response = await fetch(request.clone());\n let body = await response.json();\n return body?.headers?.['content-length'];\n}\n\nasync function fetchInitObjectLiteral(manualFramingHeaders) {\n let response = await fetch('https://http-me.glitch.me/anything', {\n backend: 'httpme',\n method: 'POST',\n body: 'meow',\n manualFramingHeaders,\n headers: {\n 'content-length': '1',\n },\n });\n let body = await response.json();\n return body?.headers?.['content-length'];\n}\n\nroutes.set(\n '/override-content-length/request/init/object-literal/true',\n async () => {\n if (isRunningLocally()) {\n await assertRejects(() => requestInitObjectLiteral(true));\n } else {\n let actual = await requestInitObjectLiteral(true);\n let expected = '1';\n assert(actual, expected, `await requestInitObjectLiteral(true)`);\n }\n },\n);\n\nroutes.set(\n '/override-content-length/request/init/object-literal/false',\n async () => {\n let actual = await requestInitObjectLiteral(false);\n let expected = '4';\n assert(actual, expected, `await requestInitObjectLiteral(false)`);\n },\n);\n\nroutes.set(\n '/override-content-length/request/method/object-literal/true',\n async () => {\n if (isRunningLocally()) {\n await assertRejects(() => requestMethod(true));\n } else {\n let actual = await requestMethod(true);\n let expected = '1';\n assert(actual, expected, `await requestMethod(true)`);\n }\n },\n);\n\nroutes.set(\n '/override-content-length/request/method/object-literal/false',\n async () => {\n let actual = await requestMethod(false);\n let expected = '4';\n assert(actual, expected, `await requestMethod(false)`);\n },\n);\n\nroutes.set('/override-content-length/request/clone/true', async () => {\n if (isRunningLocally()) {\n await assertRejects(() => requestClone(true));\n } else {\n let actual = await requestClone(true);\n let expected = '1';\n assert(actual, expected, `await requestClone(true)`);\n }\n});\n\nroutes.set('/override-content-length/request/clone/false', async () => {\n let actual = await requestClone(false);\n let expected = '4';\n assert(actual, expected, `await requestClone(false)`);\n});\n\nroutes.set(\n '/override-content-length/fetch/init/object-literal/true',\n async () => {\n if (isRunningLocally()) {\n await assertRejects(() => fetchInitObjectLiteral(true));\n } else {\n let actual = await fetchInitObjectLiteral(true);\n let expected = '1';\n assert(actual, expected, `await fetchInitObjectLiteral(true)`);\n }\n },\n);\n\nroutes.set(\n '/override-content-length/fetch/init/object-literal/false',\n async () => {\n let actual = await fetchInitObjectLiteral(false);\n let expected = '4';\n assert(actual, expected, `await fetchInitObjectLiteral(false)`);\n },\n);\n\nasync function responseInitObjectLiteral(manualFramingHeaders) {\n let response = new Response(\n new ReadableStream({\n start(controller) {\n controller.enqueue(new TextEncoder().encode('meow'));\n controller.close();\n },\n }),\n {\n manualFramingHeaders,\n headers: {\n 'content-length': '4',\n },\n },\n );\n return response;\n}\n\nasync function responseInitresponseInstance(manualFramingHeaders) {\n let response = new Response(\n new ReadableStream({\n start(controller) {\n controller.enqueue(new TextEncoder().encode('meow'));\n controller.close();\n },\n }),\n {\n manualFramingHeaders,\n headers: {\n 'content-length': '4',\n },\n },\n );\n response = new Response(\n new ReadableStream({\n start(controller) {\n controller.enqueue(new TextEncoder().encode('meow'));\n controller.close();\n },\n }),\n response,\n );\n return response;\n}\n\nroutes.set(\n '/override-content-length/response/init/object-literal/true',\n async () => {\n return responseInitObjectLiteral(true);\n },\n);\n\nroutes.set(\n '/override-content-length/response/init/object-literal/false',\n async () => {\n return responseInitObjectLiteral(false);\n },\n);\n\nroutes.set(\n '/override-content-length/response/init/response-instance/true',\n async () => {\n return responseInitresponseInstance(true);\n },\n);\n\nroutes.set(\n '/override-content-length/response/init/response-instance/false',\n async () => {\n return responseInitresponseInstance(false);\n },\n);\n\nasync function responseMethod(setManualFramingHeaders) {\n const response = await fetch('https://http-me.glitch.me/drip=11', {\n backend: 'httpme',\n cacheOverride: new CacheOverride('pass'),\n });\n response.setManualFramingHeaders(setManualFramingHeaders);\n response.headers.set('content-length', '11');\n response.headers.delete('transfer-encoding');\n return response;\n}\n\nroutes.set('/override-content-length/response/method/false', async () => {\n return responseMethod(false);\n});\n\nroutes.set('/override-content-length/response/method/true', async () => {\n return responseMethod(true);\n});\n\nasync function responseClone(setManualFramingHeaders) {\n let response = new Response('meow', {\n backend: 'httpme',\n method: 'POST',\n body: 'meow',\n setManualFramingHeaders,\n headers: {\n 'transfer-encoding': 'chunked',\n },\n });\n response = response.clone();\n return response;\n}\n\n// TODO: implement Response.clone\nroutes.set('/override-content-length/response/clone/true', async () => {\n return responseClone(true);\n});\n\n// TODO: implement Response.clone\nroutes.set('/override-content-length/response/clone/false', async () => {\n return responseClone(false);\n});\n", "import { assertRejects } from './assertions.js';\nimport { routes } from './routes.js';\n\nroutes.set('/missing-backend', async () => {\n await assertRejects(\n async () => fetch('https://example.com', { backend: 'missing' }),\n TypeError,\n `Requested backend named 'missing' does not exist`,\n );\n});\n", "import { routes } from './routes.js';\n\nroutes.set('/multiple-set-cookie/response-init', async () => {\n let h = new Headers();\n\n h.append(\n 'Set-Cookie',\n 'test=1; expires=Tue, 06-Dec-2022 12:34:56 GMT; Max-Age=60; Path=/; HttpOnly; Secure, test_id=1; Max-Age=60; Path=/; expires=Tue, 06-Dec-2022 12:34:56 GMT, test_id=1; Max-Age=60; Path=/; expires=Tue, 06-Dec-2022 12:34:56 GMT',\n );\n h.append('Set-Cookie', 'test2=2');\n h.append('Set-Cookie', 'test3=3');\n h.append('Set-Cookie', 'test4=4');\n h.append('Set-Cookie', 'test5=5');\n h.append('Set-Cookie', 'test6=6');\n h.append('Set-Cookie', 'test7=7');\n h.append('Set-Cookie', 'test8=8');\n h.append('Set-Cookie', 'test9=9');\n h.append('Set-Cookie', 'test10=10');\n h.append('Set-Cookie', 'test11=11');\n let r = new Response('Hello', {\n headers: h,\n });\n return r;\n});\nroutes.set('/multiple-set-cookie/response-direct', async () => {\n let r = new Response('Hello');\n\n r.headers.append(\n 'Set-Cookie',\n 'test=1; expires=Tue, 06-Dec-2022 12:34:56 GMT; Max-Age=60; Path=/; HttpOnly; Secure, test_id=1; Max-Age=60; Path=/; expires=Tue, 06-Dec-2022 12:34:56 GMT, test_id=1; Max-Age=60; Path=/; expires=Tue, 06-Dec-2022 12:34:56 GMT',\n );\n r.headers.append('Set-Cookie', 'test2=2');\n r.headers.append('Set-Cookie', 'test3=3');\n r.headers.append('Set-Cookie', 'test4=4');\n r.headers.append('Set-Cookie', 'test5=5');\n r.headers.append('Set-Cookie', 'test6=6');\n r.headers.append('Set-Cookie', 'test7=7');\n r.headers.append('Set-Cookie', 'test8=8');\n r.headers.append('Set-Cookie', 'test9=9');\n r.headers.append('Set-Cookie', 'test10=10');\n r.headers.append('Set-Cookie', 'test11=11');\n return r;\n});\nroutes.set('/multiple-set-cookie/downstream', async () => {\n let response = await fetch(\n 'https://http-me.glitch.me/append-header=Set-Cookie:test1=1/append-header=Set-Cookie:test2=2/append-header=Set-Cookie:test3=3/anything',\n {\n backend: 'httpme',\n },\n );\n\n return new Response('', response);\n});\n", "/* eslint-env serviceworker */\nimport { routes } from './routes.js';\nimport { assert, assertThrows } from './assertions.js';\n\nroutes.set('/Performance/interface', () => {\n let actual = Reflect.ownKeys(Performance);\n let expected = ['prototype', 'length', 'name'];\n assert(actual, expected, `Reflect.ownKeys(Performance)`);\n\n // Check the prototype descriptors are correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Performance, 'prototype');\n expected = {\n value: Performance.prototype,\n writable: false,\n enumerable: false,\n configurable: false,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance, 'prototype')`,\n );\n }\n\n // Check the constructor function's defined parameter length is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Performance, 'length');\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance, 'length')`,\n );\n }\n\n // Check the constructor function's name is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Performance, 'name');\n expected = {\n value: 'Performance',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance, 'name')`,\n );\n }\n\n // Check the prototype has the correct keys\n {\n actual = Reflect.ownKeys(Performance.prototype);\n expected = ['constructor', 'timeOrigin', 'now', Symbol.toStringTag];\n assert(actual, expected, `Reflect.ownKeys(Performance.prototype)`);\n }\n\n // Check the constructor on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype,\n 'constructor',\n );\n expected = {\n writable: true,\n enumerable: false,\n configurable: true,\n value: Performance.prototype.constructor,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype, 'constructor')`,\n );\n\n assert(\n typeof Performance.prototype.constructor,\n 'function',\n `typeof Performance.prototype.constructor`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype.constructor,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype.constructor,\n 'name',\n );\n expected = {\n value: 'Performance',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype.constructor, 'name')`,\n );\n }\n\n // Check the Symbol.toStringTag on the prototype is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype,\n Symbol.toStringTag,\n );\n expected = {\n value: 'performance',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype, [Symbol.toStringTag])`,\n );\n\n assert(\n typeof Performance.prototype[Symbol.toStringTag],\n 'string',\n `typeof Performance.prototype[Symbol.toStringTag]`,\n );\n }\n\n // Check the timeOrigin property is correct\n {\n const descriptors = Reflect.getOwnPropertyDescriptor(\n Performance.prototype,\n 'timeOrigin',\n );\n expected = { enumerable: true, configurable: true };\n assert(\n descriptors.enumerable,\n true,\n `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').enumerable`,\n );\n assert(\n descriptors.configurable,\n true,\n `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').configurable`,\n );\n assert(\n descriptors.value,\n undefined,\n `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').value`,\n );\n assert(\n descriptors.set,\n undefined,\n `Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').set`,\n );\n assert(\n typeof descriptors.get,\n 'function',\n `typeof Reflect.getOwnPropertyDescriptor(Performance, 'timeOrigin').get`,\n );\n\n assert(\n typeof Performance.prototype.timeOrigin,\n 'number',\n `typeof Performance.prototype.timeOrigin`,\n );\n }\n\n // Check the now property is correct\n {\n actual = Reflect.getOwnPropertyDescriptor(Performance.prototype, 'now');\n expected = {\n writable: true,\n enumerable: true,\n configurable: true,\n value: Performance.prototype.now,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance, 'now')`,\n );\n\n assert(\n typeof Performance.prototype.now,\n 'function',\n `typeof Performance.prototype.now`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype.now,\n 'length',\n );\n expected = {\n value: 0,\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'length')`,\n );\n\n actual = Reflect.getOwnPropertyDescriptor(\n Performance.prototype.now,\n 'name',\n );\n expected = {\n value: 'now',\n writable: false,\n enumerable: false,\n configurable: true,\n };\n assert(\n actual,\n expected,\n `Reflect.getOwnPropertyDescriptor(Performance.prototype.now, 'name')`,\n );\n }\n});\n\nroutes.set('/globalThis.performance', () => {\n assert(\n globalThis.performance instanceof Performance,\n true,\n `globalThis.performance instanceof Performance`,\n );\n});\n\nroutes.set('/globalThis.performance/now', () => {\n assertThrows(() => new performance.now());\n\n assert(typeof performance.now(), 'number');\n\n assert(performance.now() > 0, true);\n\n assert(Number.isNaN(performance.now()), false);\n\n assert(Number.isFinite(performance.now()), true);\n\n assert(performance.now() < Date.now(), true);\n});\n\nroutes.set('/globalThis.performance/timeOrigin', () => {\n assert(typeof performance.timeOrigin, 'number');\n\n assert(performance.timeOrigin > 0, true);\n\n assert(Number.isNaN(performance.timeOrigin), false);\n\n assert(Number.isFinite(performance.timeOrigin), true);\n\n assert(performance.timeOrigin < Date.now(), true);\n});\n", "/* eslint-env serviceworker */\nimport { routes } from './routes.js';\nimport { assert } from './assertions.js';\n\nfunction random3Decimals() {\n return String(Math.random()).slice(0, 5);\n}\n\nlet a = random3Decimals();\nlet b = random3Decimals();\n\n// This tests can fail sporadically as it is testing randomness.\n// If it fails, rerun the tests and it should pass, if it does not\n// then we may have another bug with how we are seeding the random\n// number generator in SpiderMonkey.\nroutes.set('/random', () => {\n assert(\n a !== b,\n true,\n 'The first 4 digits were repeated in sequential calls to Math.random() during wizening\\n\\n' +\n JSON.stringify({ a, b }, undefined, 4),\n );\n\n let c = random3Decimals();\n let d = random3Decimals();\n assert(\n c !== d,\n true,\n 'The first 4 digits were repeated in sequential calls to Math.random() during request handling\\n\\n' +\n JSON.stringify({ c, d }, undefined, 4),\n );\n});\n", "/* eslint-env serviceworker */\nimport { routes } from './routes.js';\n// React\nvar React = {};\n{\n /**\n * @license React\n * react.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n let exports = React;\n let l = Symbol.for('react.element'),\n n = Symbol.for('react.portal'),\n p = Symbol.for('react.fragment'),\n q = Symbol.for('react.strict_mode'),\n r = Symbol.for('react.profiler'),\n t = Symbol.for('react.provider'),\n u = Symbol.for('react.context'),\n v = Symbol.for('react.forward_ref'),\n w = Symbol.for('react.suspense'),\n x = Symbol.for('react.memo'),\n y = Symbol.for('react.lazy'),\n z = Symbol.iterator;\n function A(a) {\n if (null === a || 'object' !== typeof a) return null;\n a = (z && a[z]) || a['@@iterator'];\n return 'function' === typeof a ? a : null;\n }\n let B = {\n isMounted: function () {\n return !1;\n },\n enqueueForceUpdate: function () {},\n enqueueReplaceState: function () {},\n enqueueSetState: function () {},\n },\n C = Object.assign,\n D = {};\n function E(a, b, e) {\n this.props = a;\n this.context = b;\n this.refs = D;\n this.updater = e || B;\n }\n E.prototype.isReactComponent = {};\n E.prototype.setState = function (a, b) {\n if ('object' !== typeof a && 'function' !== typeof a && null != a)\n throw Error(\n 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.',\n );\n this.updater.enqueueSetState(this, a, b, 'setState');\n };\n E.prototype.forceUpdate = function (a) {\n this.updater.enqueueForceUpdate(this, a, 'forceUpdate');\n };\n function F() {}\n F.prototype = E.prototype;\n function G(a, b, e) {\n this.props = a;\n this.context = b;\n this.refs = D;\n this.updater = e || B;\n }\n var H = (G.prototype = new F());\n H.constructor = G;\n C(H, E.prototype);\n H.isPureReactComponent = !0;\n var I = Array.isArray,\n J = Object.prototype.hasOwnProperty,\n K = { current: null },\n L = { key: !0, ref: !0, __self: !0, __source: !0 };\n function M(a, b, e) {\n var d,\n c = {},\n k = null,\n h = null;\n if (null != b)\n for (d in (void 0 !== b.ref && (h = b.ref),\n void 0 !== b.key && (k = '' + b.key),\n b))\n J.call(b, d) && !L.hasOwnProperty(d) && (c[d] = b[d]);\n var g = arguments.length - 2;\n if (1 === g) c.children = e;\n else if (1 < g) {\n for (var f = Array(g), m = 0; m < g; m++) f[m] = arguments[m + 2];\n c.children = f;\n }\n if (a && a.defaultProps)\n for (d in ((g = a.defaultProps), g)) void 0 === c[d] && (c[d] = g[d]);\n return {\n $$typeof: l,\n type: a,\n key: k,\n ref: h,\n props: c,\n _owner: K.current,\n };\n }\n function N(a, b) {\n return {\n $$typeof: l,\n type: a.type,\n key: b,\n ref: a.ref,\n props: a.props,\n _owner: a._owner,\n };\n }\n function O(a) {\n return 'object' === typeof a && null !== a && a.$$typeof === l;\n }\n function escape(a) {\n var b = { '=': '=0', ':': '=2' };\n return (\n '$' +\n a.replace(/[=:]/g, function (a) {\n return b[a];\n })\n );\n }\n var P = /\\/+/g;\n function Q(a, b) {\n return 'object' === typeof a && null !== a && null != a.key\n ? escape('' + a.key)\n : b.toString(36);\n }\n function R(a, b, e, d, c) {\n var k = typeof a;\n if ('undefined' === k || 'boolean' === k) a = null;\n var h = !1;\n if (null === a) h = !0;\n else\n switch (k) {\n case 'string':\n case 'number':\n h = !0;\n break;\n case 'object':\n switch (a.$$typeof) {\n case l:\n case n:\n h = !0;\n }\n }\n if (h)\n return (\n (h = a),\n (c = c(h)),\n (a = '' === d ? '.' + Q(h, 0) : d),\n I(c)\n ? ((e = ''),\n null != a && (e = a.replace(P, '$&/') + '/'),\n R(c, b, e, '', function (a) {\n return a;\n }))\n : null != c &&\n (O(c) &&\n (c = N(\n c,\n e +\n (!c.key || (h && h.key === c.key)\n ? ''\n : ('' + c.key).replace(P, '$&/') + '/') +\n a,\n )),\n b.push(c)),\n 1\n );\n h = 0;\n d = '' === d ? '.' : d + ':';\n if (I(a))\n for (var g = 0; g < a.length; g++) {\n k = a[g];\n var f = d + Q(k, g);\n h += R(k, b, e, f, c);\n }\n else if (((f = A(a)), 'function' === typeof f))\n for (a = f.call(a), g = 0; !(k = a.next()).done; )\n (k = k.value), (f = d + Q(k, g++)), (h += R(k, b, e, f, c));\n else if ('object' === k)\n throw (\n ((b = String(a)),\n Error(\n 'Objects are not valid as a React child (found: ' +\n ('[object Object]' === b\n ? 'object with keys {' + Object.keys(a).join(', ') + '}'\n : b) +\n '). If you meant to render a collection of children, use an array instead.',\n ))\n );\n return h;\n }\n function S(a, b, e) {\n if (null == a) return a;\n var d = [],\n c = 0;\n R(a, d, '', '', function (a) {\n return b.call(e, a, c++);\n });\n return d;\n }\n function T(a) {\n if (-1 === a._status) {\n var b = a._result;\n b = b();\n b.then(\n function (b) {\n if (0 === a._status || -1 === a._status)\n (a._status = 1), (a._result = b);\n },\n function (b) {\n if (0 === a._status || -1 === a._status)\n (a._status = 2), (a._result = b);\n },\n );\n -1 === a._status && ((a._status = 0), (a._result = b));\n }\n if (1 === a._status) return a._result.default;\n throw a._result;\n }\n var U = { current: null },\n V = { transition: null },\n W = {\n ReactCurrentDispatcher: U,\n ReactCurrentBatchConfig: V,\n ReactCurrentOwner: K,\n };\n exports.Children = {\n map: S,\n forEach: function (a, b, e) {\n S(\n a,\n function () {\n b.apply(this, arguments);\n },\n e,\n );\n },\n count: function (a) {\n var b = 0;\n S(a, function () {\n b++;\n });\n return b;\n },\n toArray: function (a) {\n return (\n S(a, function (a) {\n return a;\n }) || []\n );\n },\n only: function (a) {\n if (!O(a))\n throw Error(\n 'React.Children.only expected to receive a single React element child.',\n );\n return a;\n },\n };\n exports.Component = E;\n exports.Fragment = p;\n exports.Profiler = r;\n exports.PureComponent = G;\n exports.StrictMode = q;\n exports.Suspense = w;\n exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = W;\n exports.cloneElement = function (a, b, e) {\n if (null === a || void 0 === a)\n throw Error(\n 'React.cloneElement(...): The argument must be a React element, but you passed ' +\n a +\n '.',\n );\n var d = C({}, a.props),\n c = a.key,\n k = a.ref,\n h = a._owner;\n if (null != b) {\n void 0 !== b.ref && ((k = b.ref), (h = K.current));\n void 0 !== b.key && (c = '' + b.key);\n if (a.type && a.type.defaultProps) var g = a.type.defaultProps;\n for (f in b)\n J.call(b, f) &&\n !L.hasOwnProperty(f) &&\n (d[f] = void 0 === b[f] && void 0 !== g ? g[f] : b[f]);\n }\n var f = arguments.length - 2;\n if (1 === f) d.children = e;\n else if (1 < f) {\n g = Array(f);\n for (var m = 0; m < f; m++) g[m] = arguments[m + 2];\n d.children = g;\n }\n return { $$typeof: l, type: a.type, key: c, ref: k, props: d, _owner: h };\n };\n exports.createContext = function (a) {\n a = {\n $$typeof: u,\n _currentValue: a,\n _currentValue2: a,\n _threadCount: 0,\n Provider: null,\n Consumer: null,\n _defaultValue: null,\n _globalName: null,\n };\n a.Provider = { $$typeof: t, _context: a };\n return (a.Consumer = a);\n };\n exports.createElement = M;\n exports.createFactory = function (a) {\n var b = M.bind(null, a);\n b.type = a;\n return b;\n };\n exports.createRef = function () {\n return { current: null };\n };\n exports.forwardRef = function (a) {\n return { $$typeof: v, render: a };\n };\n exports.isValidElement = O;\n exports.lazy = function (a) {\n return { $$typeof: y, _payload: { _status: -1, _result: a }, _init: T };\n };\n exports.memo = function (a, b) {\n return { $$typeof: x, type: a, compare: void 0 === b ? null : b };\n };\n exports.startTransition = function (a) {\n var b = V.transition;\n V.transition = {};\n try {\n a();\n } finally {\n V.transition = b;\n }\n };\n exports.unstable_act = function () {\n throw Error('act(...) is not supported in production builds of React.');\n };\n exports.useCallback = function (a, b) {\n return U.current.useCallback(a, b);\n };\n exports.useContext = function (a) {\n return U.current.useContext(a);\n };\n exports.useDebugValue = function () {};\n exports.useDeferredValue = function (a) {\n return U.current.useDeferredValue(a);\n };\n exports.useEffect = function (a, b) {\n return U.current.useEffect(a, b);\n };\n exports.useId = function () {\n return U.current.useId();\n };\n exports.useImperativeHandle = function (a, b, e) {\n return U.current.useImperativeHandle(a, b, e);\n };\n exports.useInsertionEffect = function (a, b) {\n return U.current.useInsertionEffect(a, b);\n };\n exports.useLayoutEffect = function (a, b) {\n return U.current.useLayoutEffect(a, b);\n };\n exports.useMemo = function (a, b) {\n return U.current.useMemo(a, b);\n };\n exports.useReducer = function (a, b, e) {\n return U.current.useReducer(a, b, e);\n };\n exports.useRef = function (a) {\n return U.current.useRef(a);\n };\n exports.useState = function (a) {\n return U.current.useState(a);\n };\n exports.useSyncExternalStore = function (a, b, e) {\n return U.current.useSyncExternalStore(a, b, e);\n };\n exports.useTransition = function () {\n return U.current.useTransition();\n };\n exports.version = '18.2.0';\n}\n\n// react/jsx-runtime\nlet jsx, jsxs;\n{\n /**\n * @license React\n * react-jsx-runtime.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n let k = Symbol.for('react.element'),\n m = Object.prototype.hasOwnProperty,\n n =\n React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED\n .ReactCurrentOwner,\n p = { key: !0, ref: !0, __self: !0, __source: !0 };\n function q(c, a, g) {\n var b,\n d = {},\n e = null,\n h = null;\n void 0 !== g && (e = '' + g);\n void 0 !== a.key && (e = '' + a.key);\n void 0 !== a.ref && (h = a.ref);\n for (b in a) m.call(a, b) && !p.hasOwnProperty(b) && (d[b] = a[b]);\n if (c && c.defaultProps)\n for (b in ((a = c.defaultProps), a)) void 0 === d[b] && (d[b] = a[b]);\n return {\n $$typeof: k,\n type: c,\n key: e,\n ref: h,\n props: d,\n _owner: n.current,\n };\n }\n jsx = jsxs = q;\n}\n\n// react-dom/server\nlet renderToReadableStream;\n{\n /**\n * @license React\n * react-dom-server.browser.production.min.js\n *\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n var aa = React;\n function k(a) {\n for (\n var b = 'https://reactjs.org/docs/error-decoder.html?invariant=' + a,\n c = 1;\n c < arguments.length;\n c++\n )\n b += '&args[]=' + encodeURIComponent(arguments[c]);\n return (\n 'Minified React error #' +\n a +\n '; visit ' +\n b +\n ' for the full message or use the non-minified dev environment for full errors and additional helpful warnings.'\n );\n }\n var l = null,\n n = 0;\n function p(a, b) {\n if (0 !== b.length)\n if (512 < b.length)\n 0 < n &&\n (a.enqueue(new Uint8Array(l.buffer, 0, n)),\n (l = new Uint8Array(512)),\n (n = 0)),\n a.enqueue(b);\n else {\n var c = l.length - n;\n c < b.length &&\n (0 === c\n ? a.enqueue(l)\n : (l.set(b.subarray(0, c), n), a.enqueue(l), (b = b.subarray(c))),\n (l = new Uint8Array(512)),\n (n = 0));\n l.set(b, n);\n n += b.length;\n }\n }\n function t(a, b) {\n p(a, b);\n return !0;\n }\n function ba(a) {\n l &&\n 0 < n &&\n (a.enqueue(new Uint8Array(l.buffer, 0, n)), (l = null), (n = 0));\n }\n var ca = new TextEncoder();\n function u(a) {\n return ca.encode(a);\n }\n function w(a) {\n return ca.encode(a);\n }\n function da(a, b) {\n 'function' === typeof a.error ? a.error(b) : a.close();\n }\n var x = Object.prototype.hasOwnProperty,\n ea =\n /^[:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD][:A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD\\-.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040]*$/,\n fa = {},\n ha = {};\n function ia(a) {\n if (x.call(ha, a)) return !0;\n if (x.call(fa, a)) return !1;\n if (ea.test(a)) return (ha[a] = !0);\n fa[a] = !0;\n return !1;\n }\n function y(a, b, c, d, f, e, g) {\n this.acceptsBooleans = 2 === b || 3 === b || 4 === b;\n this.attributeName = d;\n this.attributeNamespace = f;\n this.mustUseProperty = c;\n this.propertyName = a;\n this.type = b;\n this.sanitizeURL = e;\n this.removeEmptyString = g;\n }\n var z = {};\n 'children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style'\n .split(' ')\n .forEach(function (a) {\n z[a] = new y(a, 0, !1, a, null, !1, !1);\n });\n [\n ['acceptCharset', 'accept-charset'],\n ['className', 'class'],\n ['htmlFor', 'for'],\n ['httpEquiv', 'http-equiv'],\n ].forEach(function (a) {\n var b = a[0];\n z[b] = new y(b, 1, !1, a[1], null, !1, !1);\n });\n ['contentEditable', 'draggable', 'spellCheck', 'value'].forEach(function (a) {\n z[a] = new y(a, 2, !1, a.toLowerCase(), null, !1, !1);\n });\n [\n 'autoReverse',\n 'externalResourcesRequired',\n 'focusable',\n 'preserveAlpha',\n ].forEach(function (a) {\n z[a] = new y(a, 2, !1, a, null, !1, !1);\n });\n 'allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope'\n .split(' ')\n .forEach(function (a) {\n z[a] = new y(a, 3, !1, a.toLowerCase(), null, !1, !1);\n });\n ['checked', 'multiple', 'muted', 'selected'].forEach(function (a) {\n z[a] = new y(a, 3, !0, a, null, !1, !1);\n });\n ['capture', 'download'].forEach(function (a) {\n z[a] = new y(a, 4, !1, a, null, !1, !1);\n });\n ['cols', 'rows', 'size', 'span'].forEach(function (a) {\n z[a] = new y(a, 6, !1, a, null, !1, !1);\n });\n ['rowSpan', 'start'].forEach(function (a) {\n z[a] = new y(a, 5, !1, a.toLowerCase(), null, !1, !1);\n });\n var ja = /[\\-:]([a-z])/g;\n function ka(a) {\n return a[1].toUpperCase();\n }\n 'accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height'\n .split(' ')\n .forEach(function (a) {\n var b = a.replace(ja, ka);\n z[b] = new y(b, 1, !1, a, null, !1, !1);\n });\n 'xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type'\n .split(' ')\n .forEach(function (a) {\n var b = a.replace(ja, ka);\n z[b] = new y(b, 1, !1, a, 'http://www.w3.org/1999/xlink', !1, !1);\n });\n ['xml:base', 'xml:lang', 'xml:space'].forEach(function (a) {\n var b = a.replace(ja, ka);\n z[b] = new y(b, 1, !1, a, 'http://www.w3.org/XML/1998/namespace', !1, !1);\n });\n ['tabIndex', 'crossOrigin'].forEach(function (a) {\n z[a] = new y(a, 1, !1, a.toLowerCase(), null, !1, !1);\n });\n z.xlinkHref = new y(\n 'xlinkHref',\n 1,\n !1,\n 'xlink:href',\n 'http://www.w3.org/1999/xlink',\n !0,\n !1,\n );\n ['src', 'href', 'action', 'formAction'].forEach(function (a) {\n z[a] = new y(a, 1, !1, a.toLowerCase(), null, !0, !0);\n });\n var B = {\n animationIterationCount: !0,\n aspectRatio: !0,\n borderImageOutset: !0,\n borderImageSlice: !0,\n borderImageWidth: !0,\n boxFlex: !0,\n boxFlexGroup: !0,\n boxOrdinalGroup: !0,\n columnCount: !0,\n columns: !0,\n flex: !0,\n flexGrow: !0,\n flexPositive: !0,\n flexShrink: !0,\n flexNegative: !0,\n flexOrder: !0,\n gridArea: !0,\n gridRow: !0,\n gridRowEnd: !0,\n gridRowSpan: !0,\n gridRowStart: !0,\n gridColumn: !0,\n gridColumnEnd: !0,\n gridColumnSpan: !0,\n gridColumnStart: !0,\n fontWeight: !0,\n lineClamp: !0,\n lineHeight: !0,\n opacity: !0,\n order: !0,\n orphans: !0,\n tabSize: !0,\n widows: !0,\n zIndex: !0,\n zoom: !0,\n fillOpacity: !0,\n floodOpacity: !0,\n stopOpacity: !0,\n strokeDasharray: !0,\n strokeDashoffset: !0,\n strokeMiterlimit: !0,\n strokeOpacity: !0,\n strokeWidth: !0,\n },\n la = ['Webkit', 'ms', 'Moz', 'O'];\n Object.keys(B).forEach(function (a) {\n la.forEach(function (b) {\n b = b + a.charAt(0).toUpperCase() + a.substring(1);\n B[b] = B[a];\n });\n });\n var oa = /[\"'&<>]/;\n function C(a) {\n if ('boolean' === typeof a || 'number' === typeof a) return '' + a;\n a = '' + a;\n var b = oa.exec(a);\n if (b) {\n var c = '',\n d,\n f = 0;\n for (d = b.index; d < a.length; d++) {\n switch (a.charCodeAt(d)) {\n case 34:\n b = '"';\n break;\n case 38:\n b = '&';\n break;\n case 39:\n b = ''';\n break;\n case 60:\n b = '<';\n break;\n case 62:\n b = '>';\n break;\n default:\n continue;\n }\n f !== d && (c += a.substring(f, d));\n f = d + 1;\n c += b;\n }\n a = f !== d ? c + a.substring(f, d) : c;\n }\n return a;\n }\n var pa = /([A-Z])/g,\n qa = /^ms-/,\n ra = Array.isArray,\n sa = w('