{
  "version": 3,
  "sources": ["../../../../src/workers/kv/namespace.worker.ts", "../../../../src/workers/kv/constants.ts", "../../../../src/workers/kv/validator.worker.ts"],
  "sourcesContent": ["import assert from \"node:assert\";\nimport {\n\tDeferredPromise,\n\tDELETE,\n\tGET,\n\tHttpError,\n\tKeyValueStorage,\n\tmaybeApply,\n\tMiniflareDurableObject,\n\tPOST,\n\tPUT,\n} from \"miniflare:shared\";\nimport { KVHeaders, KVLimits, KVParams, MAX_BULK_GET_KEYS } from \"./constants\";\nimport {\n\tdecodeKey,\n\tdecodeListOptions,\n\tvalidateGetOptions,\n\tvalidateKey,\n\tvalidateListOptions,\n\tvalidatePutOptions,\n} from \"./validator.worker\";\nimport type { KeyValueEntry, RouteHandler } from \"miniflare:shared\";\n\ninterface KVParams {\n\tkey: string;\n}\n\nfunction createMaxValueSizeError(length: number, maxValueSize: number) {\n\treturn new HttpError(\n\t\t413,\n\t\t`Value length of ${length} exceeds limit of ${maxValueSize}.`\n\t);\n}\nclass MaxLengthStream extends TransformStream<Uint8Array, Uint8Array> {\n\treadonly signal: AbortSignal;\n\treadonly length: Promise<number>;\n\n\tconstructor(maxLength: number) {\n\t\tconst abortController = new AbortController();\n\t\tconst lengthPromise = new DeferredPromise<number>();\n\n\t\tlet length = 0;\n\t\tsuper({\n\t\t\ttransform(chunk, controller) {\n\t\t\t\tlength += chunk.byteLength;\n\t\t\t\t// If we exceeded the maximum length, don't enqueue the chunk, but don't\n\t\t\t\t// error the stream, so we get the correct final length in the error\n\t\t\t\tif (length <= maxLength) {\n\t\t\t\t\tcontroller.enqueue(chunk);\n\t\t\t\t} else if (!abortController.signal.aborted) {\n\t\t\t\t\tabortController.abort();\n\t\t\t\t}\n\t\t\t},\n\t\t\tflush() {\n\t\t\t\t// Previously, when this was running in Node, we `error()`ed the stream\n\t\t\t\t// here, and relied on the abort reason being propagated from the blob\n\t\t\t\t// store put to the HTTP handler. Now that we're running in `workerd`,\n\t\t\t\t// we have to use `fetch()` for file-system access, which throws an\n\t\t\t\t// un-catchable exception when the body stream is aborted.\n\t\t\t\tlengthPromise.resolve(length);\n\t\t\t},\n\t\t});\n\n\t\tthis.signal = abortController.signal;\n\t\tthis.length = lengthPromise;\n\t}\n}\n\nfunction millisToSeconds(millis: number): number {\n\treturn Math.floor(millis / 1000);\n}\n\nfunction secondsToMillis(seconds: number): number {\n\treturn seconds * 1000;\n}\n\nasync function processKeyValue(\n\tobj: KeyValueEntry<unknown> | null,\n\ttype: \"text\" | \"json\" = \"text\",\n\twithMetadata = false\n) {\n\tconst decoder = new TextDecoder();\n\tlet decodedValue = \"\";\n\tif (obj?.value) {\n\t\tfor await (const chunk of obj?.value) {\n\t\t\tdecodedValue += decoder.decode(chunk, { stream: true });\n\t\t}\n\t\tdecodedValue += decoder.decode();\n\t}\n\n\tlet val = null;\n\tconst size = decodedValue.length;\n\ttry {\n\t\tval = !obj?.value\n\t\t\t? null\n\t\t\t: type === \"json\"\n\t\t\t\t? JSON.parse(decodedValue)\n\t\t\t\t: decodedValue;\n\t} catch {\n\t\tthrow new HttpError(\n\t\t\t400,\n\t\t\t`At least one of the requested keys corresponds to a non-${type} value`\n\t\t);\n\t}\n\tif (val && withMetadata) {\n\t\treturn [\n\t\t\t{\n\t\t\t\tvalue: val,\n\t\t\t\tmetadata: obj?.metadata ?? null,\n\t\t\t},\n\t\t\tsize,\n\t\t];\n\t}\n\treturn [val, size];\n}\n\nexport class KVNamespaceObject extends MiniflareDurableObject {\n\t#storage?: KeyValueStorage;\n\tget storage() {\n\t\t// `KeyValueStorage` can only be constructed once `this.blob` is initialised\n\t\treturn (this.#storage ??= new KeyValueStorage(this));\n\t}\n\n\t@GET(\"/:key\")\n\t@POST(\"/bulk/get\")\n\tget: RouteHandler<KVParams> = async (req, params, url) => {\n\t\tif (req.method === \"POST\" && req.body != null) {\n\t\t\tlet decodedBody = \"\";\n\t\t\tconst decoder = new TextDecoder();\n\t\t\tfor await (const chunk of req.body) {\n\t\t\t\tdecodedBody += decoder.decode(chunk, { stream: true });\n\t\t\t}\n\t\t\tdecodedBody += decoder.decode();\n\t\t\tconst parsedBody = JSON.parse(decodedBody);\n\t\t\tconst keys: string[] = parsedBody.keys;\n\t\t\tconst type = parsedBody?.type;\n\t\t\tif (type && type !== \"text\" && type !== \"json\") {\n\t\t\t\tconst errorStr = `\"${type}\" is not a valid type. Use \"json\" or \"text\"`;\n\t\t\t\treturn new Response(errorStr, { status: 400, statusText: errorStr });\n\t\t\t}\n\t\t\tconst obj: { [key: string]: any } = {};\n\t\t\tif (keys.length > MAX_BULK_GET_KEYS) {\n\t\t\t\tconst errorStr = `You can request a maximum of ${MAX_BULK_GET_KEYS} keys`;\n\t\t\t\treturn new Response(errorStr, { status: 400, statusText: errorStr });\n\t\t\t}\n\t\t\tif (keys.length < 1) {\n\t\t\t\tconst errorStr = \"You must request a minimum of 1 key\";\n\t\t\t\treturn new Response(errorStr, { status: 400, statusText: errorStr });\n\t\t\t}\n\t\t\tlet totalBytes = 0;\n\t\t\tfor (const key of keys) {\n\t\t\t\tvalidateGetOptions(key, { cacheTtl: parsedBody?.cacheTtl });\n\t\t\t\tconst entry = await this.storage.get(key);\n\t\t\t\tconst [value, size] = await processKeyValue(\n\t\t\t\t\tentry,\n\t\t\t\t\tparsedBody?.type,\n\t\t\t\t\tparsedBody?.withMetadata\n\t\t\t\t);\n\t\t\t\ttotalBytes += size;\n\t\t\t\tobj[key] = value;\n\t\t\t}\n\t\t\tconst maxValueSize = this.beingTested\n\t\t\t\t? KVLimits.MAX_VALUE_SIZE_TEST_BYTES\n\t\t\t\t: KVLimits.MAX_BULK_SIZE_BYTES;\n\t\t\tif (totalBytes > maxValueSize) {\n\t\t\t\tthrow new HttpError(\n\t\t\t\t\t413,\n\t\t\t\t\t`Total size of request exceeds the limit of ${maxValueSize / 1024 / 1024}MB`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new Response(JSON.stringify(obj));\n\t\t}\n\n\t\t// Decode URL parameters\n\t\tconst key = decodeKey(params, url.searchParams);\n\t\tconst cacheTtlParam = url.searchParams.get(KVParams.CACHE_TTL);\n\t\tconst cacheTtl =\n\t\t\tcacheTtlParam === null ? undefined : parseInt(cacheTtlParam);\n\t\t// Get value from storage\n\t\tvalidateGetOptions(key, { cacheTtl });\n\t\tconst entry = await this.storage.get(key);\n\t\tif (entry === null) throw new HttpError(404, \"Not Found\");\n\n\t\t// Return value in runtime-friendly format\n\t\tconst headers = new Headers();\n\t\tif (entry.expiration !== undefined) {\n\t\t\theaders.set(\n\t\t\t\tKVHeaders.EXPIRATION,\n\t\t\t\tmillisToSeconds(entry.expiration).toString()\n\t\t\t);\n\t\t}\n\t\tif (entry.metadata !== undefined) {\n\t\t\theaders.set(KVHeaders.METADATA, JSON.stringify(entry.metadata));\n\t\t}\n\t\treturn new Response(entry.value, { headers });\n\t};\n\n\t@PUT(\"/:key\")\n\tput: RouteHandler<KVParams> = async (req, params, url) => {\n\t\t// Decode URL parameters and headers\n\t\tconst key = decodeKey(params, url.searchParams);\n\t\tconst rawExpiration = url.searchParams.get(KVParams.EXPIRATION);\n\t\tconst rawExpirationTtl = url.searchParams.get(KVParams.EXPIRATION_TTL);\n\t\tconst rawMetadata = req.headers.get(KVHeaders.METADATA);\n\t\t// Validate key, expiration and metadata\n\t\tconst now = millisToSeconds(this.timers.now());\n\t\tconst { expiration, metadata } = validatePutOptions(key, {\n\t\t\tnow,\n\t\t\trawExpiration,\n\t\t\trawExpirationTtl,\n\t\t\trawMetadata,\n\t\t});\n\n\t\t// Validate value size: if we know the value length, avoid passing the body\n\t\t// through a transform stream to count it (trusting `workerd` to send\n\t\t// correct value here).\n\t\tlet value = req.body;\n\t\tconst contentLength = parseInt(req.headers.get(\"Content-Length\") ?? \"NaN\");\n\t\tlet valueLengthHint: number | undefined;\n\t\tif (!Number.isNaN(contentLength)) valueLengthHint = contentLength;\n\t\telse if (value === null) valueLengthHint = 0;\n\n\t\t// Empty values may be put with `null` bodies:\n\t\t// https://github.com/cloudflare/miniflare/issues/703\n\t\tvalue ??= new ReadableStream<Uint8Array>({\n\t\t\tstart(controller) {\n\t\t\t\tcontroller.close();\n\t\t\t},\n\t\t});\n\n\t\tconst maxValueSize = this.beingTested\n\t\t\t? KVLimits.MAX_VALUE_SIZE_TEST_BYTES\n\t\t\t: KVLimits.MAX_VALUE_SIZE_BYTES;\n\t\tlet maxLengthStream: MaxLengthStream | undefined;\n\t\tif (valueLengthHint !== undefined && valueLengthHint > maxValueSize) {\n\t\t\t// If we know the size of the value (i.e. from `Content-Length`) use that\n\t\t\tthrow createMaxValueSizeError(valueLengthHint, maxValueSize);\n\t\t} else {\n\t\t\t// Otherwise, pipe through a transform stream that counts the number of\n\t\t\t// bytes and stops if it exceeds the max. The stream exposes an\n\t\t\t// `AbortSignal`, that will be aborted when the max is exceeded.\n\t\t\tmaxLengthStream = new MaxLengthStream(maxValueSize);\n\t\t\tvalue = value.pipeThrough(maxLengthStream);\n\t\t}\n\n\t\t// Put value into storage\n\t\ttry {\n\t\t\tawait this.storage.put({\n\t\t\t\tkey,\n\t\t\t\tvalue,\n\t\t\t\texpiration: maybeApply(secondsToMillis, expiration),\n\t\t\t\tmetadata,\n\t\t\t\tsignal: maxLengthStream?.signal,\n\t\t\t});\n\t\t} catch (e) {\n\t\t\tif (\n\t\t\t\ttypeof e === \"object\" &&\n\t\t\t\te !== null &&\n\t\t\t\t\"name\" in e &&\n\t\t\t\te.name === \"AbortError\"\n\t\t\t) {\n\t\t\t\t// `this.storage.put()` will only throw an abort error once the stream\n\t\t\t\t// has been written to the blob store (it gets cleaned up afterwards),\n\t\t\t\t// so we have the correct value length here.\n\t\t\t\tassert(maxLengthStream !== undefined);\n\t\t\t\tconst length = await maxLengthStream.length;\n\t\t\t\tthrow createMaxValueSizeError(length, maxValueSize);\n\t\t\t} else {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t}\n\n\t\treturn new Response();\n\t};\n\n\t@DELETE(\"/:key\")\n\tdelete: RouteHandler<KVParams> = async (req, params, url) => {\n\t\t// Decode URL parameters\n\t\tconst key = decodeKey(params, url.searchParams);\n\t\tvalidateKey(key);\n\n\t\t// Delete key from storage\n\t\tawait this.storage.delete(key);\n\t\treturn new Response();\n\t};\n\n\t@GET(\"/\")\n\tlist: RouteHandler = async (req, params, url) => {\n\t\t// Decode URL parameters\n\t\tconst options = decodeListOptions(url);\n\t\tvalidateListOptions(options);\n\n\t\t// List keys from storage\n\t\tconst res = await this.storage.list(options);\n\t\tconst keys = res.keys.map<KVNamespaceListKey<unknown>>((key) => ({\n\t\t\tname: key.key,\n\t\t\texpiration: maybeApply(millisToSeconds, key.expiration),\n\t\t\t// workerd expects metadata to be a JSON-serialised string\n\t\t\tmetadata: maybeApply(JSON.stringify, key.metadata),\n\t\t}));\n\t\tlet result: KVNamespaceListResult<unknown>;\n\t\tif (res.cursor === undefined) {\n\t\t\tresult = { keys, list_complete: true, cacheStatus: null };\n\t\t} else {\n\t\t\tresult = {\n\t\t\t\tkeys,\n\t\t\t\tlist_complete: false,\n\t\t\t\tcursor: res.cursor,\n\t\t\t\tcacheStatus: null,\n\t\t\t};\n\t\t}\n\t\treturn Response.json(result);\n\t};\n}\n", "import { testRegExps } from \"miniflare:shared\";\nimport type { MatcherRegExps } from \"miniflare:shared\";\n\nexport const KVLimits = {\n\tMIN_CACHE_TTL_SECONDS: 30,\n\tMIN_EXPIRATION_TTL_SECONDS: 60,\n\tMAX_LIST_KEYS: 1000,\n\tMAX_KEY_SIZE_BYTES: 512,\n\tMAX_VALUE_SIZE_BYTES: 25 * 1024 * 1024 /* 25MiB */,\n\tMAX_VALUE_SIZE_TEST_BYTES: 1024 /* 1KiB */,\n\tMAX_METADATA_SIZE_BYTES: 1024 /* 1KiB */,\n\tMAX_BULK_SIZE_BYTES: 25 * 1024 * 1024 /* 25MiB */,\n} as const;\n\nexport const KVParams = {\n\tURL_ENCODED: \"urlencoded\",\n\tCACHE_TTL: \"cache_ttl\",\n\tEXPIRATION: \"expiration\",\n\tEXPIRATION_TTL: \"expiration_ttl\",\n\tLIST_LIMIT: \"key_count_limit\",\n\tLIST_PREFIX: \"prefix\",\n\tLIST_CURSOR: \"cursor\",\n} as const;\n\nexport const KVHeaders = {\n\tEXPIRATION: \"CF-Expiration\",\n\tMETADATA: \"CF-KV-Metadata\",\n} as const;\n\nexport const SiteBindings = {\n\tKV_NAMESPACE_SITE: \"__STATIC_CONTENT\",\n\tJSON_SITE_MANIFEST: \"__STATIC_CONTENT_MANIFEST\",\n\tJSON_SITE_FILTER: \"MINIFLARE_SITE_FILTER\",\n} as const;\n\n// Magic prefix: if a URLs pathname starts with this, it shouldn't be cached.\n// This ensures edge caching of Workers Sites files is disabled, and the latest\n// local version is always served.\nexport const SITES_NO_CACHE_PREFIX = \"$__MINIFLARE_SITES__$/\";\nexport const MAX_BULK_GET_KEYS = 100;\n\nexport function encodeSitesKey(key: string): string {\n\t// `encodeURIComponent()` ensures `ETag`s used by `@cloudflare/kv-asset-handler`\n\t// are always byte strings.\n\treturn SITES_NO_CACHE_PREFIX + encodeURIComponent(key);\n}\nexport function decodeSitesKey(key: string): string {\n\treturn key.startsWith(SITES_NO_CACHE_PREFIX)\n\t\t? decodeURIComponent(key.substring(SITES_NO_CACHE_PREFIX.length))\n\t\t: key;\n}\n\nexport function isSitesRequest(request: { url: string }) {\n\tconst url = new URL(request.url);\n\treturn url.pathname.startsWith(`/${SITES_NO_CACHE_PREFIX}`);\n}\n\nexport interface SiteMatcherRegExps {\n\tinclude?: MatcherRegExps;\n\texclude?: MatcherRegExps;\n}\n\nexport interface SerialisableMatcherRegExps {\n\tinclude: string[];\n\texclude: string[];\n}\n\nexport interface SerialisableSiteMatcherRegExps {\n\tinclude?: SerialisableMatcherRegExps;\n\texclude?: SerialisableMatcherRegExps;\n}\n\nfunction serialiseRegExp(regExp: RegExp): string {\n\tconst str = regExp.toString();\n\treturn str.substring(str.indexOf(\"/\") + 1, str.lastIndexOf(\"/\"));\n}\n\nexport function serialiseRegExps(\n\tmatcher: MatcherRegExps\n): SerialisableMatcherRegExps {\n\treturn {\n\t\tinclude: matcher.include.map(serialiseRegExp),\n\t\texclude: matcher.exclude.map(serialiseRegExp),\n\t};\n}\n\nexport function deserialiseRegExps(\n\tmatcher: SerialisableMatcherRegExps\n): MatcherRegExps {\n\treturn {\n\t\tinclude: matcher.include.map((regExp) => new RegExp(regExp)),\n\t\texclude: matcher.exclude.map((regExp) => new RegExp(regExp)),\n\t};\n}\n\nexport function serialiseSiteRegExps(\n\tsiteRegExps: SiteMatcherRegExps\n): SerialisableSiteMatcherRegExps {\n\treturn {\n\t\tinclude: siteRegExps.include && serialiseRegExps(siteRegExps.include),\n\t\texclude: siteRegExps.exclude && serialiseRegExps(siteRegExps.exclude),\n\t};\n}\n\nexport function deserialiseSiteRegExps(\n\tsiteRegExps: SerialisableSiteMatcherRegExps\n): SiteMatcherRegExps {\n\treturn {\n\t\tinclude: siteRegExps.include && deserialiseRegExps(siteRegExps.include),\n\t\texclude: siteRegExps.exclude && deserialiseRegExps(siteRegExps.exclude),\n\t};\n}\n\nexport function testSiteRegExps(\n\tregExps: SiteMatcherRegExps,\n\tkey: string\n): boolean {\n\t// Either include globs undefined, or name matches them\n\tif (regExps.include !== undefined) return testRegExps(regExps.include, key);\n\t// Either exclude globs undefined, or name doesn't match them\n\tif (regExps.exclude !== undefined) return !testRegExps(regExps.exclude, key);\n\treturn true;\n}\n\nexport function getAssetsBindingsNames(\n\t// __STATIC_CONTENT and __STATIC_CONTENT_MANIFEST binding names are\n\t// reserved for Workers Sites. Since we want to allow both sites and\n\t// assets to work side by side, we cannot use the same binding name\n\t// for assets. Therefore deferring to a different default naming here.\n\tassetsKVBindingName = \"__STATIC_ASSETS_CONTENT\",\n\tassetsManifestBindingName = \"__STATIC_ASSETS_CONTENT_MANIFEST\"\n) {\n\treturn {\n\t\tASSETS_KV_NAMESPACE: assetsKVBindingName,\n\t\tASSETS_MANIFEST: assetsManifestBindingName,\n\t} as const;\n}\n", "import { Buffer } from \"node:buffer\";\nimport { HttpError } from \"miniflare:shared\";\nimport { KVLimits, KVParams } from \"./constants\";\n\nexport function decodeKey({ key }: { key: string }, query: URLSearchParams) {\n\tif (query.get(KVParams.URL_ENCODED)?.toLowerCase() !== \"true\") return key;\n\ttry {\n\t\treturn decodeURIComponent(key);\n\t} catch (e: any) {\n\t\tif (e instanceof URIError) {\n\t\t\tthrow new HttpError(400, \"Could not URL-decode key name\");\n\t\t} else {\n\t\t\tthrow e;\n\t\t}\n\t}\n}\n\nexport function validateKey(key: string): void {\n\tif (key === \"\") {\n\t\tthrow new HttpError(400, \"Key names must not be empty\");\n\t}\n\tif (key === \".\" || key === \"..\") {\n\t\tthrow new HttpError(\n\t\t\t400,\n\t\t\t`Illegal key name \"${key}\". Please use a different name.`\n\t\t);\n\t}\n\tvalidateKeyLength(key);\n}\n\nexport function validateKeyLength(key: string): void {\n\tconst keyLength = Buffer.byteLength(key);\n\tif (keyLength > KVLimits.MAX_KEY_SIZE_BYTES) {\n\t\tthrow new HttpError(\n\t\t\t414,\n\t\t\t`UTF-8 encoded length of ${keyLength} exceeds key length limit of ${KVLimits.MAX_KEY_SIZE_BYTES}.`\n\t\t);\n\t}\n}\n\nexport function validateGetOptions(\n\tkey: string,\n\toptions?: Omit<KVNamespaceGetOptions<never>, \"type\">\n): void {\n\tvalidateKey(key);\n\t// Validate cacheTtl, but ignore it as there's only one \"edge location\":\n\t// the user's computer\n\tconst cacheTtl = options?.cacheTtl;\n\tif (\n\t\tcacheTtl !== undefined &&\n\t\t(isNaN(cacheTtl) || cacheTtl < KVLimits.MIN_CACHE_TTL_SECONDS)\n\t) {\n\t\tthrow new HttpError(\n\t\t\t400,\n\t\t\t`Invalid ${KVParams.CACHE_TTL} of ${cacheTtl}. Cache TTL must be at least ${KVLimits.MIN_CACHE_TTL_SECONDS}.`\n\t\t);\n\t}\n}\n\nexport function validatePutOptions(\n\tkey: string,\n\toptions: {\n\t\tnow: number /* seconds */;\n\t\trawExpiration: string /* seconds */ | null;\n\t\trawExpirationTtl: string /* seconds */ | null;\n\t\trawMetadata: string /* JSON */ | null;\n\t}\n): { expiration?: number /* seconds */; metadata?: unknown } {\n\tconst { now, rawExpiration, rawExpirationTtl, rawMetadata } = options;\n\n\tvalidateKey(key);\n\n\t// Validate expiration\n\tlet expiration: number | undefined;\n\tif (rawExpirationTtl !== null) {\n\t\tconst expirationTtl = parseInt(rawExpirationTtl);\n\t\tif (Number.isNaN(expirationTtl) || expirationTtl <= 0) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.EXPIRATION_TTL} of ${rawExpirationTtl}. Please specify integer greater than 0.`\n\t\t\t);\n\t\t}\n\t\tif (expirationTtl < KVLimits.MIN_EXPIRATION_TTL_SECONDS) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.EXPIRATION_TTL} of ${rawExpirationTtl}. Expiration TTL must be at least ${KVLimits.MIN_EXPIRATION_TTL_SECONDS}.`\n\t\t\t);\n\t\t}\n\t\texpiration = now + expirationTtl;\n\t} else if (rawExpiration !== null) {\n\t\texpiration = parseInt(rawExpiration);\n\t\tif (Number.isNaN(expiration) || expiration <= now) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.EXPIRATION} of ${rawExpiration}. Please specify integer greater than the current number of seconds since the UNIX epoch.`\n\t\t\t);\n\t\t}\n\t\tif (expiration < now + KVLimits.MIN_EXPIRATION_TTL_SECONDS) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.EXPIRATION} of ${rawExpiration}. Expiration times must be at least ${KVLimits.MIN_EXPIRATION_TTL_SECONDS} seconds in the future.`\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate metadata size\n\tlet metadata: unknown | undefined;\n\tif (rawMetadata !== null) {\n\t\tconst metadataLength = Buffer.byteLength(rawMetadata);\n\t\tif (metadataLength > KVLimits.MAX_METADATA_SIZE_BYTES) {\n\t\t\tthrow new HttpError(\n\t\t\t\t413,\n\t\t\t\t`Metadata length of ${metadataLength} exceeds limit of ${KVLimits.MAX_METADATA_SIZE_BYTES}.`\n\t\t\t);\n\t\t}\n\t\tmetadata = JSON.parse(rawMetadata);\n\t}\n\n\treturn { expiration, metadata };\n}\n\nexport function decodeListOptions(url: URL) {\n\tconst limitParam = url.searchParams.get(KVParams.LIST_LIMIT);\n\tconst limit =\n\t\tlimitParam === null ? KVLimits.MAX_LIST_KEYS : parseInt(limitParam);\n\tconst prefix = url.searchParams.get(KVParams.LIST_PREFIX) ?? undefined;\n\tconst cursor = url.searchParams.get(KVParams.LIST_CURSOR) ?? undefined;\n\treturn { limit, prefix, cursor };\n}\n\nexport function validateListOptions(options: KVNamespaceListOptions): void {\n\t// Validate key limit\n\tconst limit = options.limit;\n\tif (limit !== undefined) {\n\t\tif (isNaN(limit) || limit < 1) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.LIST_LIMIT} of ${limit}. Please specify an integer greater than 0.`\n\t\t\t);\n\t\t}\n\t\tif (limit > KVLimits.MAX_LIST_KEYS) {\n\t\t\tthrow new HttpError(\n\t\t\t\t400,\n\t\t\t\t`Invalid ${KVParams.LIST_LIMIT} of ${limit}. Please specify an integer less than ${KVLimits.MAX_LIST_KEYS}.`\n\t\t\t);\n\t\t}\n\t}\n\n\t// Validate key prefix\n\tconst prefix = options.prefix;\n\tif (prefix != null) validateKeyLength(prefix);\n}\n"],
  "mappings": "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",
  "names": ["HttpError", "Buffer", "Buffer", "HttpError", "key", "entry"]
}
