From ffde8e07dbf37509bd5722c92962919dbfe4a7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:45:42 +0000 Subject: [PATCH 01/71] Report version from manifest --- src/pin.ts | 19 ++++++++++--------- src/serve/server.ts | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index 20c40e5..4f8f69a 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -36,8 +36,8 @@ export async function pin (args: ArgumentsCamelCase): Promise { exit(`Manifest file not found: ${manifestPath}`) } - const { contractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - console.log(colors.blue(`Contract name: ${contractName}`)) + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + console.log(colors.blue(`Contract name: ${fullContractName}`)) console.log(colors.blue(`Manifest version: ${manifestVersion}`)) if (version) { @@ -50,31 +50,31 @@ export async function pin (args: ArgumentsCamelCase): Promise { console.log(colors.green(`✅ Version validation passed: ${version}`)) } - const currentPinnedVersion = cheloniaConfig.contracts[contractName]?.version + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version if (currentPinnedVersion === manifestVersion) { - console.log(colors.yellow(`✨ Contract ${contractName} is already pinned to version ${manifestVersion} - no action needed`)) + console.log(colors.yellow(`✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)) return } if (currentPinnedVersion) { - console.log(colors.cyan(`📌 Updating ${contractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) + console.log(colors.cyan(`📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) } else { - console.log(colors.cyan(`📌 Pinning ${contractName} to version ${manifestVersion} (first time)`)) + console.log(colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`)) } const contractVersionDir = join(projectRoot, 'contracts', contractName, manifestVersion) if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${contractName}. Use --overwrite to replace it.`) + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`) } - console.log(colors.yellow(`Version ${manifestVersion} already exists for ${contractName} - checking files...`)) + console.log(colors.yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)) } else { await createVersionDirectory(contractName, manifestVersion) } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) - await updateCheloniaConfig(contractName, manifestVersion, manifestPath) + await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath) console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${version}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) @@ -103,6 +103,7 @@ async function parseManifest (manifestPath: string) { return { contractName, manifestVersion, + fullContractName, contractFiles: { main: mainFile, slim: slimFile diff --git a/src/serve/server.ts b/src/serve/server.ts index b46e64d..0127ecb 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -34,6 +34,16 @@ import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pus // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' +const cheloniaAppManifest = await (async () => { + try { + return await import(join(process.cwd(), 'chelonia.json'), { + with: { type: 'json' } + }) + } catch { + console.warn('`chelonia.json` not found. Version information will be unavailable.') + } +})() + const ARCHIVE_MODE = nconf.get('server:archiveMode') if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { @@ -49,8 +59,6 @@ const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? undefined : createWorker(join(import.meta.dirname || '.', import.meta.workerDir || '.', 'creditsWorker.js')) -const { CONTRACTS_VERSION, GI_VERSION } = process.env - // Dynamic runtime import to bypass bundling issues with npm: specifier const hapi = new Hapi.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements @@ -426,8 +434,11 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { serverHandlers: { connection (socket) { const versionInfo = { - GI_VERSION: GI_VERSION || null, - CONTRACTS_VERSION: CONTRACTS_VERSION || null + appVersion: cheloniaAppManifest?.appVersion || null, + contractsVersion: Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts || {}) + .map(([k, v]) => [k, (v as Record).version]) + ) } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) } From cbee166efad2a4450f29dac2e7f56b88d29d1521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 2 Apr 2026 18:59:14 +0000 Subject: [PATCH 02/71] Updates --- src/serve/server.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/serve/server.ts b/src/serve/server.ts index 0127ecb..ae5b29e 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -31,14 +31,15 @@ import { type WSS } from './pubsub.ts' import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pushServerActionhandlers, subscriptionInfoWrapper } from './push.ts' +import { pathToFileURL } from 'node:url' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' const cheloniaAppManifest = await (async () => { try { - return await import(join(process.cwd(), 'chelonia.json'), { + return (await import(pathToFileURL(join(process.cwd(), 'chelonia.json')).toString(), { with: { type: 'json' } - }) + })).default } catch { console.warn('`chelonia.json` not found. Version information will be unavailable.') } @@ -435,10 +436,10 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { connection (socket) { const versionInfo = { appVersion: cheloniaAppManifest?.appVersion || null, - contractsVersion: Object.fromEntries( - Object.entries(cheloniaAppManifest?.contracts || {}) + contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts) .map(([k, v]) => [k, (v as Record).version]) - ) + ) : null } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) } From 93eba67b8894ba818520056d6e83ee8a74f74507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 12:47:41 -0400 Subject: [PATCH 03/71] build --- build/main.js | 51 ++++++++++++++++++----------- build/serve/creditsWorker.js | 4 +-- build/serve/ownerSizeTotalWorker.js | 4 +-- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/build/main.js b/build/main.js index b00c4b7..2cf0783 100644 --- a/build/main.js +++ b/build/main.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/main.js-tmp @@ -3094,6 +3094,7 @@ import path6 from "node:path"; import process9 from "node:process"; import { join as join72 } from "node:path"; import process10 from "node:process"; +import { pathToFileURL } from "node:url"; import process11 from "node:process"; import process13 from "node:process"; @@ -87653,7 +87654,7 @@ var require_thread_stream = __commonJS({ var { EventEmitter } = __require2("events"); var { Worker: Worker2 } = __require2("worker_threads"); var { join: join92 } = __require2("path"); - var { pathToFileURL } = __require2("url"); + var { pathToFileURL: pathToFileURL2 } = __require2("url"); var { wait } = require_wait2(); var { WRITE_INDEX, @@ -87693,7 +87694,7 @@ var require_thread_stream = __commonJS({ ...opts.workerOpts, trackUnmanagedFds: false, workerData: { - filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL(filename).href, + filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, dataBuf: stream[kImpl].dataBuf, stateBuf: stream[kImpl].stateBuf, workerData: { @@ -108555,15 +108556,14 @@ var Hapi2; var import_inert2; var import_npm_chalk3; var import_npm_nconf6; +var cheloniaAppManifest; var ARCHIVE_MODE2; var ownerSizeTotalWorker; var creditsWorker; -var CONTRACTS_VERSION; -var GI_VERSION; var hapi; var appendToOrphanedNamesIndex; var init_server = __esm({ - "src/serve/server.ts"() { + async "src/serve/server.ts"() { "use strict"; init_SPMessage(); init_chelonia(); @@ -108585,6 +108585,15 @@ var init_server = __esm({ init_pubsub2(); init_push(); import_npm_nconf6 = __toESM(require_nconf()); + cheloniaAppManifest = await (async () => { + try { + return (await import(pathToFileURL(join72(process10.cwd(), "chelonia.json")).toString(), { + with: { type: "json" } + })).default; + } catch { + console.warn("`chelonia.json` not found. Version information will be unavailable."); + } + })(); ARCHIVE_MODE2 = import_npm_nconf6.default.get("server:archiveMode"); if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { process10.stderr.write("The size calculation worker must run more frequently than the credits worker for accurate billing"); @@ -108592,7 +108601,6 @@ var init_server = __esm({ } ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "ownerSizeTotalWorker.js")); creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "creditsWorker.js")); - ({ CONTRACTS_VERSION, GI_VERSION } = process10.env); hapi = new Hapi2.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements // // v17 doesn't seem to do this anymore so I've re-enabled the logging @@ -108874,8 +108882,10 @@ var init_server = __esm({ serverHandlers: { connection(socket) { const versionInfo = { - GI_VERSION: GI_VERSION || null, - CONTRACTS_VERSION: CONTRACTS_VERSION || null + appVersion: cheloniaAppManifest?.appVersion || null, + contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( + Object.entries(cheloniaAppManifest?.contracts).map(([k, v2]) => [k, v2.version]) + ) : null }; socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)); } @@ -109074,7 +109084,7 @@ var init_serve = __esm({ console.info(import_npm_chalk4.default.bold("backend startup sequence complete.")); resolve82(); }); - Promise.resolve().then(() => (init_server(), server_exports)).catch(reject); + init_server().then(() => server_exports).catch(reject); }); esm_default("okTurtles.events/once", SERVER_EXITING, () => { esm_default("okTurtles.data/apply", PUBSUB_INSTANCE, function(pubsub) { @@ -110628,8 +110638,8 @@ async function pin(args) { if (!existsSync(fullManifestPath)) { exit(`Manifest file not found: ${manifestPath}`); } - const { contractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - console.log(blue(`Contract name: ${contractName}`)); + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + console.log(blue(`Contract name: ${fullContractName}`)); console.log(blue(`Manifest version: ${manifestVersion}`)); if (version3) { if (version3 !== manifestVersion) { @@ -110639,27 +110649,27 @@ async function pin(args) { } console.log(green(`\u2705 Version validation passed: ${version3}`)); } - const currentPinnedVersion = cheloniaConfig.contracts[contractName]?.version; + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; if (currentPinnedVersion === manifestVersion) { - console.log(yellow(`\u2728 Contract ${contractName} is already pinned to version ${manifestVersion} - no action needed`)); + console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); return; } if (currentPinnedVersion) { - console.log(cyan(`\u{1F4CC} Updating ${contractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); } else { - console.log(cyan(`\u{1F4CC} Pinning ${contractName} to version ${manifestVersion} (first time)`)); + console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); } const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${contractName}. Use --overwrite to replace it.`); + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); } - console.log(yellow(`Version ${manifestVersion} already exists for ${contractName} - checking files...`)); + console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); } else { await createVersionDirectory(contractName, manifestVersion); } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(contractName, manifestVersion, manifestPath); + await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath); console.log(green(`\u2705 Successfully pinned ${contractName} to version ${version3}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { @@ -110682,6 +110692,7 @@ async function parseManifest(manifestPath) { return { contractName, manifestVersion, + fullContractName, contractFiles: { main: mainFile, slim: slimFile diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 814a512..7b2d5ed 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1,5 +1,5 @@ -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/serve/creditsWorker.js-tmp diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index deaef25..ec3e39a 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1,5 +1,5 @@ -import { createRequire as __deno_internal_createRequire } from "node:module"; -var __require = __deno_internal_createRequire(import.meta.url); +import { createRequire } from "node:module"; +var __require = createRequire(import.meta.url); // build/serve/ownerSizeTotalWorker.js-tmp From 42f14250fadd18ede52e520cb5e5ab2cdf59bc44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:22:00 -0400 Subject: [PATCH 04/71] Use hono for the API --- deno.json | 11 +- deno.lock | 305 +------ src/eventsAfter.ts | 2 +- src/serve/auth.ts | 106 ++- src/serve/dashboard-server.ts | 64 +- src/serve/database.ts | 8 +- src/serve/errors.ts | 1 + src/serve/index.ts | 2 +- src/serve/routes.ts | 1516 ++++++++++++++++----------------- src/serve/server.ts | 110 +-- 10 files changed, 877 insertions(+), 1248 deletions(-) diff --git a/deno.json b/deno.json index f695c5c..8920949 100644 --- a/deno.json +++ b/deno.json @@ -45,18 +45,14 @@ "npm:vuelidate": "npm:vuelidate@0.7.6", "npm:vuex": "npm:vuex@3.6.0", "npm:multiformats/": "npm:multiformats@11.0.2/", - "npm:@hapi/hapi": "npm:@hapi/hapi@21.4.3", - "npm:@hapi/boom": "npm:@hapi/boom@10.0.1", "npm:@chelonia/lib/": "npm:@chelonia/lib@1.2.9/", "npm:lru-cache": "npm:lru-cache@7.14.0", "npm:pino": "npm:pino@8.19.0", "npm:tweetnacl": "npm:tweetnacl@1.0.3", - "npm:@hapi/inert": "npm:@hapi/inert@7.1.0", "npm:chalk": "npm:chalk@4.1.0", "npm:ws": "npm:ws@8.5.0", "npm:zod": "npm:zod@4.0.5", "npm:@types/ws": "npm:@types/ws@8.5.10", - "npm:joi": "npm:joi@18.0.1", "npm:bottleneck": "npm:bottleneck@2.19.5", "npm:@apeleghq/rfc8188/": "npm:@apeleghq/rfc8188@1.0.7/", "npm:redis": "npm:redis@5.9.0", @@ -65,7 +61,12 @@ "npm:@types/nconf": "npm:@types/nconf@0.10.7", "npm:@types/yargs": "npm:@types/yargs@17.0.34", "npm:smol-toml": "npm:smol-toml@1.4.2", - "npm:@chelonia/serdes": "npm:@chelonia/serdes@1.0.0" + "npm:@chelonia/serdes": "npm:@chelonia/serdes@1.0.0", + "npm:hono": "npm:hono@4.12.12", + "npm:hono/": "npm:hono@4.12.12/", + "npm:@hono/node-server": "npm:@hono/node-server@1.19.14", + "npm:@hono/node-server/": "npm:@hono/node-server@1.19.14/", + "npm:@hono/zod-validator": "npm:@hono/zod-validator@0.7.6" }, "nodeModulesDir": "auto", "fmt": { diff --git a/deno.lock b/deno.lock index 49b2504..6998d96 100644 --- a/deno.lock +++ b/deno.lock @@ -22,7 +22,7 @@ "jsr:@std/path@1.1.1": "1.1.1", "jsr:@std/path@^1.1.3": "1.1.3", "jsr:@std/streams@1.0.10": "1.0.10", - "npm:@apeleghq/rfc8188@*": "1.0.7", + "npm:@apeleghq/rfc8188@*": "1.0.8", "npm:@apeleghq/rfc8188@1.0.7": "1.0.7", "npm:@chelonia/crypto@*": "1.0.1", "npm:@chelonia/lib@*": "1.2.9_@sbp+sbp@2.4.1", @@ -30,9 +30,9 @@ "npm:@chelonia/lib@1.2.9": "1.2.9_@sbp+sbp@2.4.1", "npm:@chelonia/serdes@1.0.0": "1.0.0", "npm:@eslint/js@9.31.0": "9.31.0", - "npm:@hapi/boom@10.0.1": "10.0.1", - "npm:@hapi/hapi@21.4.3": "21.4.3", - "npm:@hapi/inert@7.1.0": "7.1.0", + "npm:@hono/node-server@*": "1.19.14_hono@4.12.12", + "npm:@hono/node-server@1.19.14": "1.19.14_hono@4.12.12", + "npm:@hono/zod-validator@0.7.6": "0.7.6_hono@4.12.12_zod@4.0.5", "npm:@sbp/okturtles.data@0.1.5": "0.1.5_@sbp+sbp@2.4.1", "npm:@sbp/okturtles.data@0.1.7": "0.1.7_@sbp+sbp@2.4.1", "npm:@sbp/okturtles.eventqueue@1.2.0": "1.2.0_@sbp+sbp@2.4.1", @@ -47,11 +47,12 @@ "npm:bottleneck@2.19.5": "2.19.5", "npm:chalk@4.1.0": "4.1.0", "npm:dompurify@2.4.2": "2.4.2", - "npm:esbuild-sass-plugin@3.3.1": "3.3.1_esbuild@0.25.6_sass-embedded@1.93.3", + "npm:esbuild-sass-plugin@3.3.1": "3.3.1_esbuild@0.25.8", "npm:esbuild@0.25.6": "0.25.6", "npm:esbuild@0.25.8": "0.25.8", "npm:eslint@9.31.0": "9.31.0", - "npm:joi@18.0.1": "18.0.1", + "npm:hono@*": "4.12.12", + "npm:hono@4.12.12": "4.12.12", "npm:lru-cache@7.14.0": "7.14.0", "npm:multiformats@*": "11.0.2", "npm:multiformats@11.0.2": "11.0.2", @@ -558,247 +559,17 @@ "levn" ] }, - "@hapi/accept@6.0.3": { - "integrity": "sha512-p72f9k56EuF0n3MwlBNThyVE5PXX40g+aQh+C/xbKrfzahM2Oispv3AXmOIU51t3j77zay1qrX7IIziZXspMlw==", + "@hono/node-server@1.19.14_hono@4.12.12": { + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "dependencies": [ - "@hapi/boom", - "@hapi/hoek" + "hono" ] }, - "@hapi/address@5.1.1": { - "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "@hono/zod-validator@0.7.6_hono@4.12.12_zod@4.0.5": { + "integrity": "sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw==", "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/ammo@6.0.1": { - "integrity": "sha512-pmL+nPod4g58kXrMcsGLp05O2jF4P2Q3GiL8qYV7nKYEh3cGf+rV4P5Jyi2Uq0agGhVU63GtaSAfBEZOlrJn9w==", - "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/b64@6.0.1": { - "integrity": "sha512-ZvjX4JQReUmBheeCq+S9YavcnMMHWqx3S0jHNXWIM1kQDxB9cyfSycpVvjfrKcIS8Mh5N3hmu/YKo4Iag9g2Kw==", - "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/boom@10.0.1": { - "integrity": "sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==", - "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/bounce@3.0.2": { - "integrity": "sha512-d0XmlTi3H9HFDHhQLjg4F4auL1EY3Wqj7j7/hGDhFFe6xAbnm3qiGrXeT93zZnPH8gH+SKAFYiRzu26xkXcH3g==", - "dependencies": [ - "@hapi/boom", - "@hapi/hoek" - ] - }, - "@hapi/bourne@3.0.0": { - "integrity": "sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==" - }, - "@hapi/call@9.0.1": { - "integrity": "sha512-uPojQRqEL1GRZR4xXPqcLMujQGaEpyVPRyBlD8Pp5rqgIwLhtveF9PkixiKru2THXvuN8mUrLeet5fqxKAAMGg==", - "dependencies": [ - "@hapi/boom", - "@hapi/hoek" - ] - }, - "@hapi/catbox-memory@6.0.2": { - "integrity": "sha512-H1l4ugoFW/ZRkqeFrIo8p1rWN0PA4MDTfu4JmcoNDvnY975o29mqoZblqFTotxNHlEkMPpIiIBJTV+Mbi+aF0g==", - "dependencies": [ - "@hapi/boom", - "@hapi/hoek" - ] - }, - "@hapi/catbox@12.1.1": { - "integrity": "sha512-hDqYB1J+R0HtZg4iPH3LEnldoaBsar6bYp0EonBmNQ9t5CO+1CqgCul2ZtFveW1ReA5SQuze9GPSU7/aecERhw==", - "dependencies": [ - "@hapi/boom", - "@hapi/hoek", - "@hapi/podium", - "@hapi/validate" - ] - }, - "@hapi/content@6.0.0": { - "integrity": "sha512-CEhs7j+H0iQffKfe5Htdak5LBOz/Qc8TRh51cF+BFv0qnuph3Em4pjGVzJMkI2gfTDdlJKWJISGWS1rK34POGA==", - "dependencies": [ - "@hapi/boom" - ] - }, - "@hapi/cryptiles@6.0.1": { - "integrity": "sha512-9GM9ECEHfR8lk5ASOKG4+4ZsEzFqLfhiryIJ2ISePVB92OHLp/yne4m+zn7z9dgvM98TLpiFebjDFQ0UHcqxXQ==", - "dependencies": [ - "@hapi/boom" - ] - }, - "@hapi/file@3.0.0": { - "integrity": "sha512-w+lKW+yRrLhJu620jT3y+5g2mHqnKfepreykvdOcl9/6up8GrQQn+l3FRTsjHTKbkbfQFkuksHpdv2EcpKcJ4Q==" - }, - "@hapi/formula@3.0.2": { - "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==" - }, - "@hapi/hapi@21.4.3": { - "integrity": "sha512-Q7g0ZY4gxU69wabFKH75qR0AFOdiOECj6vGqTHBSO5Lrwe6TwD8r9LkYQIbvtG8N423VDpdVsiZP8MnBwmD6Hw==", - "dependencies": [ - "@hapi/accept", - "@hapi/ammo", - "@hapi/boom", - "@hapi/bounce", - "@hapi/call", - "@hapi/catbox", - "@hapi/catbox-memory", - "@hapi/heavy", - "@hapi/hoek", - "@hapi/mimos", - "@hapi/podium", - "@hapi/shot", - "@hapi/somever", - "@hapi/statehood", - "@hapi/subtext", - "@hapi/teamwork", - "@hapi/topo", - "@hapi/validate" - ] - }, - "@hapi/heavy@8.0.1": { - "integrity": "sha512-gBD/NANosNCOp6RsYTsjo2vhr5eYA3BEuogk6cxY0QdhllkkTaJFYtTXv46xd6qhBVMbMMqcSdtqey+UQU3//w==", - "dependencies": [ - "@hapi/boom", - "@hapi/hoek", - "@hapi/validate" - ] - }, - "@hapi/hoek@11.0.7": { - "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==" - }, - "@hapi/inert@7.1.0": { - "integrity": "sha512-5X+cl/Ozm0U9uPGGX1dSKhnhTQIf161bH/kkTN9OBVAZKFG+nrj8j/NMj6S1zBBZWmQrkVRNPfCUGrXzB4fCFQ==", - "dependencies": [ - "@hapi/ammo", - "@hapi/boom", - "@hapi/bounce", - "@hapi/hoek", - "@hapi/validate", - "lru-cache@7.18.3" - ] - }, - "@hapi/iron@7.0.1": { - "integrity": "sha512-tEZnrOujKpS6jLKliyWBl3A9PaE+ppuL/+gkbyPPDb/l2KSKQyH4lhMkVb+sBhwN+qaxxlig01JRqB8dk/mPxQ==", - "dependencies": [ - "@hapi/b64", - "@hapi/boom", - "@hapi/bourne", - "@hapi/cryptiles", - "@hapi/hoek" - ] - }, - "@hapi/mimos@7.0.1": { - "integrity": "sha512-b79V+BrG0gJ9zcRx1VGcCI6r6GEzzZUgiGEJVoq5gwzuB2Ig9Cax8dUuBauQCFKvl2YWSWyOc8mZ8HDaJOtkew==", - "dependencies": [ - "@hapi/hoek", - "mime-db" - ] - }, - "@hapi/nigel@5.0.1": { - "integrity": "sha512-uv3dtYuB4IsNaha+tigWmN8mQw/O9Qzl5U26Gm4ZcJVtDdB1AVJOwX3X5wOX+A07qzpEZnOMBAm8jjSqGsU6Nw==", - "dependencies": [ - "@hapi/hoek", - "@hapi/vise" - ] - }, - "@hapi/pez@6.1.0": { - "integrity": "sha512-+FE3sFPYuXCpuVeHQ/Qag1b45clR2o54QoonE/gKHv9gukxQ8oJJZPR7o3/ydDTK6racnCJXxOyT1T93FCJMIg==", - "dependencies": [ - "@hapi/b64", - "@hapi/boom", - "@hapi/content", - "@hapi/hoek", - "@hapi/nigel" - ] - }, - "@hapi/pinpoint@2.0.1": { - "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==" - }, - "@hapi/podium@5.0.2": { - "integrity": "sha512-T7gf2JYHQQfEfewTQFbsaXoZxSvuXO/QBIGljucUQ/lmPnTTNAepoIKOakWNVWvo2fMEDjycu77r8k6dhreqHA==", - "dependencies": [ - "@hapi/hoek", - "@hapi/teamwork", - "@hapi/validate" - ] - }, - "@hapi/shot@6.0.2": { - "integrity": "sha512-WKK1ShfJTrL1oXC0skoIZQYzvLsyMDEF8lfcWuQBjpjCN29qivr9U36ld1z0nt6edvzv28etNMOqUF4klnHryw==", - "dependencies": [ - "@hapi/hoek", - "@hapi/validate" - ] - }, - "@hapi/somever@4.1.1": { - "integrity": "sha512-lt3QQiDDOVRatS0ionFDNrDIv4eXz58IibQaZQDOg4DqqdNme8oa0iPWcE0+hkq/KTeBCPtEOjDOBKBKwDumVg==", - "dependencies": [ - "@hapi/bounce", - "@hapi/hoek" - ] - }, - "@hapi/statehood@8.2.0": { - "integrity": "sha512-63JlCVIrsmuunWsyc3OeuFO+gH6v56swLCl7OM1w09l/exQKPUxSUDF2Slkuw8k91nIzr0A2/aPvjLOWf9ksrg==", - "dependencies": [ - "@hapi/boom", - "@hapi/bounce", - "@hapi/bourne", - "@hapi/cryptiles", - "@hapi/hoek", - "@hapi/iron", - "@hapi/validate" - ] - }, - "@hapi/subtext@8.1.1": { - "integrity": "sha512-ex1Y2s/KuJktS8Ww0k6XJ5ysSKrzNym4i5pDVuCwlSgHHviHUsT1JNzE6FYhNU9TTHSNdyfue/t2m89bpkX9Jw==", - "dependencies": [ - "@hapi/boom", - "@hapi/bourne", - "@hapi/content", - "@hapi/file", - "@hapi/hoek", - "@hapi/pez", - "@hapi/wreck" - ] - }, - "@hapi/teamwork@6.0.1": { - "integrity": "sha512-52OXRslUfYwXAOG8k58f2h2ngXYQGP0x5RPOo+eWA/FtyLgHjGMrE3+e9LSXP/0q2YfHAK5wj9aA9DTy1K+kyQ==" - }, - "@hapi/tlds@1.1.3": { - "integrity": "sha512-QIvUMB5VZ8HMLZF9A2oWr3AFM430QC8oGd0L35y2jHpuW6bIIca6x/xL7zUf4J7L9WJ3qjz+iJII8ncaeMbpSg==" - }, - "@hapi/topo@6.0.2": { - "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", - "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/validate@2.0.1": { - "integrity": "sha512-NZmXRnrSLK8MQ9y/CMqE9WSspgB9xA41/LlYR0k967aSZebWr4yNrpxIbov12ICwKy4APSlWXZga9jN5p6puPA==", - "dependencies": [ - "@hapi/hoek", - "@hapi/topo" - ] - }, - "@hapi/vise@5.0.1": { - "integrity": "sha512-XZYWzzRtINQLedPYlIkSkUr7m5Ddwlu99V9elh8CSygXstfv3UnWIXT0QD+wmR0VAG34d2Vx3olqcEhRRoTu9A==", - "dependencies": [ - "@hapi/hoek" - ] - }, - "@hapi/wreck@18.1.0": { - "integrity": "sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w==", - "dependencies": [ - "@hapi/boom", - "@hapi/bourne", - "@hapi/hoek" + "hono", + "zod" ] }, "@humanfs/core@0.19.1": { @@ -1008,9 +779,6 @@ "@sbp/sbp@2.4.1": { "integrity": "sha512-k6Blz95Gl1KlTc/PHNRMCQDD3niZ1p5tTHOzABiLo82YYQe8UGNl/AiastIJ8GfByW7M/VHLYLsQEK/41Skx3g==" }, - "@standard-schema/spec@1.0.0": { - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==" - }, "@tweenjs/tween.js@23.1.3": { "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==" }, @@ -1023,16 +791,10 @@ "@types/nconf@0.10.7": { "integrity": "sha512-ltJgbQX0XgjkeDrz0anTCXLBLatppWYFCxp88ILEwybfAuyNWr0Qb+ceFFqZ0VDR8fguEjr0hH37ZF+AF4gsxw==" }, - "@types/node@22.15.15": { - "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", - "dependencies": [ - "undici-types@6.21.0" - ] - }, "@types/node@24.0.13": { "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", "dependencies": [ - "undici-types@7.8.0" + "undici-types" ] }, "@types/stats.js@0.17.4": { @@ -1056,7 +818,7 @@ "@types/ws@8.5.10": { "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dependencies": [ - "@types/node@22.15.15" + "@types/node" ] }, "@types/yargs-parser@21.0.3": { @@ -1557,10 +1319,10 @@ "es-errors" ] }, - "esbuild-sass-plugin@3.3.1_esbuild@0.25.6_sass-embedded@1.93.3": { + "esbuild-sass-plugin@3.3.1_esbuild@0.25.8": { "integrity": "sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==", "dependencies": [ - "esbuild@0.25.6", + "esbuild@0.25.8", "resolve", "safe-identifier", "sass", @@ -1901,6 +1663,9 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "bin": true }, + "hono@4.12.12": { + "integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==" + }, "icss-replace-symbols@1.1.0": { "integrity": "sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==" }, @@ -1990,18 +1755,6 @@ "isexe@2.0.0": { "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, - "joi@18.0.1": { - "integrity": "sha512-IiQpRyypSnLisQf3PwuN2eIHAsAIGZIrLZkd4zdvIar2bDyhM91ubRjy8a3eYablXsh9BeI/c7dmPYHca5qtoA==", - "dependencies": [ - "@hapi/address", - "@hapi/formula", - "@hapi/hoek", - "@hapi/pinpoint", - "@hapi/tlds", - "@hapi/topo", - "@standard-schema/spec" - ] - }, "js-base64@2.6.4": { "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" }, @@ -2103,9 +1856,6 @@ "lru-cache@7.14.0": { "integrity": "sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==" }, - "lru-cache@7.18.3": { - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" - }, "make-dir@2.1.0": { "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dependencies": [ @@ -2135,9 +1885,6 @@ "picomatch" ] }, - "mime-db@1.54.0": { - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==" - }, "mime@1.6.0": { "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "bin": true @@ -2918,9 +2665,6 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "bin": true }, - "undici-types@6.21.0": { - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" - }, "undici-types@7.8.0": { "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==" }, @@ -3063,9 +2807,8 @@ "npm:@chelonia/lib@1.2.9", "npm:@chelonia/serdes@1.0.0", "npm:@eslint/js@9.31.0", - "npm:@hapi/boom@10.0.1", - "npm:@hapi/hapi@21.4.3", - "npm:@hapi/inert@7.1.0", + "npm:@hono/node-server@1.19.14", + "npm:@hono/zod-validator@0.7.6", "npm:@sbp/okturtles.data@0.1.7", "npm:@sbp/okturtles.eventqueue@1.2.0", "npm:@sbp/okturtles.events@1.0.0", @@ -3081,7 +2824,7 @@ "npm:dompurify@2.4.2", "npm:esbuild-sass-plugin@3.3.1", "npm:esbuild@0.25.8", - "npm:joi@18.0.1", + "npm:hono@4.12.12", "npm:lru-cache@7.14.0", "npm:multiformats@11.0.2", "npm:nconf@0.13.0", diff --git a/src/eventsAfter.ts b/src/eventsAfter.ts index 8cf7126..b8bc8bd 100644 --- a/src/eventsAfter.ts +++ b/src/eventsAfter.ts @@ -50,7 +50,7 @@ async function getMessagesSince (contractID: string, sinceHeight: number, limit: async function getRemoteMessagesSince (src: string, contractID: string, sinceHeight: number, limit: number): Promise { const response = await fetch(`${src}/eventsAfter/${contractID}/${sinceHeight}`) if (!response.ok) { - // The response body may contain some useful error info if we got a Boom error response. + // The response body may contain some useful error info. const bodyText = await response.text().catch(() => '') || '' throw new Error(`failed network request to ${src}: ${response.status} - ${response.statusText} - '${bodyText}'`) } diff --git a/src/serve/auth.ts b/src/serve/auth.ts index 39c93c1..84e7ca1 100644 --- a/src/serve/auth.ts +++ b/src/serve/auth.ts @@ -1,52 +1,68 @@ import { verifyShelterAuthorizationHeader } from 'npm:@chelonia/lib/utils' -import Boom from 'npm:@hapi/boom' -import type * as Hapi from 'npm:@hapi/hapi' +import { HTTPException } from 'npm:hono/http-exception' +import type { Context, MiddlewareHandler } from 'npm:hono' -const plugin: Hapi.NamedPlugin = { - name: 'chel-auth', - register: function (server: Hapi.Server) { - server.auth.scheme('chel-bearer', () => { - return { - authenticate: function (request, h) { - const { authorization } = request.headers - if (!authorization) { - return h.unauthenticated(Boom.unauthorized(null, 'bearer')) - } - const thisScheme = 'bearer ' - if (authorization.slice(0, thisScheme.length) !== thisScheme) { - return h.unauthenticated(Boom.unauthorized(null, 'bearer')) - } - const token = authorization.slice(thisScheme.length) - return h.authenticated({ credentials: { token } }) - } - } - }) +export type AuthCredentials = { + token?: string + billableContractID?: string +} - server.auth.scheme ('chel-shelter', () => { - return { - authenticate: function (request, h) { - const { authorization } = request.headers - if (!authorization) { - return h.unauthenticated(Boom.unauthorized(null, 'shelter')) - } - const thisScheme = 'shelter ' - if (authorization.slice(0, thisScheme.length) !== thisScheme) { - return h.unauthenticated(Boom.unauthorized(null, 'shelter')) - } - try { - const billableContractID = verifyShelterAuthorizationHeader(authorization) - return h.authenticated({ credentials: { billableContractID } }) - } catch (e) { - console.warn(e, 'Shelter authorization failed') - return h.unauthenticated(Boom.unauthorized('Authentication failed', 'shelter')) - } - } - } - }) +declare module 'npm:hono' { + interface ContextVariableMap { + credentials: AuthCredentials + authStrategy: string + } +} + +function extractBearer (c: Context): AuthCredentials | null { + const authorization = c.req.header('authorization') + if (!authorization) return null + const prefix = 'bearer ' + if (authorization.slice(0, prefix.length) !== prefix) return null + return { token: authorization.slice(prefix.length) } +} - server.auth.strategy('chel-bearer', 'chel-bearer') - server.auth.strategy('chel-shelter', 'chel-shelter') +function extractShelter (c: Context): AuthCredentials | null { + const authorization = c.req.header('authorization') + if (!authorization) return null + const prefix = 'shelter ' + if (authorization.slice(0, prefix.length) !== prefix) return null + try { + const billableContractID = verifyShelterAuthorizationHeader(authorization) + return { billableContractID } + } catch (e) { + console.warn(e, 'Shelter authorization failed') + return null } } -export default plugin +const extractors: Record AuthCredentials | null> = { + 'chel-bearer': extractBearer, + 'chel-shelter': extractShelter +} + +export function authMiddleware ( + strategies: string | string[], + mode: 'required' | 'optional' = 'required' +): MiddlewareHandler { + const strategyList = Array.isArray(strategies) ? strategies : [strategies] + + return async (c, next) => { + for (const strategy of strategyList) { + const extractor = extractors[strategy] + if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`) + const credentials = extractor(c) + if (credentials) { + c.set('credentials', credentials) + c.set('authStrategy', strategy) + return next() + } + } + if (mode === 'optional') { + c.set('credentials', {} as AuthCredentials) + c.set('authStrategy', '') + return next() + } + throw new HTTPException(401, { message: 'Unauthorized' }) + } +} diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index 64391b5..4eced9a 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -1,71 +1,33 @@ import path from 'node:path' import process from 'node:process' -import * as Hapi from 'npm:@hapi/hapi' -import Inert from 'npm:@hapi/inert' +import { Hono } from 'npm:hono' +import { serveStatic } from 'npm:hono/deno' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' -// Get the current directory for dashboard assets const getDashboardPath = () => { - // In development, use relative path from serve directory return path.resolve(import.meta.dirname || process.cwd(), 'dist-dashboard') } export async function startDashboard (): Promise { - // Create a separate Hapi server for the dashboard const port = nconf.get('server:dashboardPort') - const dashboardServer = new Hapi.Server({ - port, - host: nconf.get('server:host'), - routes: { - files: { - relativeTo: getDashboardPath() - } - } - }) + const host = nconf.get('server:host') || '0.0.0.0' + const dashboardRoot = getDashboardPath() - // Register the Inert plugin for static file serving - await dashboardServer.register(Inert) + const app = new Hono() - // Dashboard assets routes (must come first to handle static files) - dashboardServer.route({ - method: 'GET', - path: '/assets/{path*}', - handler: { - directory: { - path: 'assets', - redirectToSlash: false - } - } - }) + app.get('/assets/*', serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })) - // Support accessing dashboard under /dashboard/ path - dashboardServer.route({ - method: 'GET', - path: '/dashboard', - handler: (_request: Hapi.Request, h: Hapi.ResponseToolkit) => h.file('index.html') - }) + app.get('/dashboard', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) + app.get('/dashboard/', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) - dashboardServer.route({ - method: 'GET', - path: '/dashboard/', - handler: (_request: Hapi.Request, h: Hapi.ResponseToolkit) => h.file('index.html') - }) + app.get('/*', serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })) - // Catch-all route for root and other paths (serves index.html) - dashboardServer.route({ - method: 'GET', - path: '/{path*}', - handler: { - directory: { - path: '.', - index: ['index.html'] - } - } - }) + app.get('/*', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) - // Start the dashboard server - await dashboardServer.start() + await new Promise((resolve) => { + Deno.serve({ port, hostname: host, onListen: () => resolve() }, app.fetch) + }) } export default startDashboard diff --git a/src/serve/database.ts b/src/serve/database.ts index 502beb6..b093656 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -5,9 +5,9 @@ import 'npm:@chelonia/lib/chelonia' import 'npm:@chelonia/lib/db' import { checkKey, parsePrefixableKey, prefixHandlers } from 'npm:@chelonia/lib/db' import { strToB64 } from 'npm:@chelonia/lib/functions' -import Boom from 'npm:@hapi/boom' import sbp from 'npm:@sbp/sbp' import LRU from 'npm:lru-cache' +import { BackendErrorConflict, BackendErrorGone, BackendErrorNotFound } from './errors.ts' import { SERVER_EXITING } from './events.ts' import { initVapid } from './vapid.ts' import { initZkpp } from './zkppSalt.ts' @@ -25,10 +25,10 @@ export default sbp('sbp/selectors/register', { const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize) const latestHEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) if (latestHEADinfo === '') { - throw Boom.resourceGone(`contractID ${contractID} has been deleted!`) + throw new BackendErrorGone(`contractID ${contractID} has been deleted!`) } if (!latestHEADinfo) { - throw Boom.notFound(`contractID ${contractID} doesn't exist!`) + throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`) } // Number of entries pushed. let counter = 0 @@ -159,7 +159,7 @@ export default sbp('sbp/selectors/register', { 'backend/db/registerName': async function (name: string, value: string): Promise<{ name: string, value: string }> { const exists = await sbp('backend/db/lookupName', name) if (exists) { - throw Boom.conflict('exists') + throw new BackendErrorConflict('exists') } await sbp('chelonia.db/set', namespaceKey(name), value) await sbp('chelonia.db/set', `_private_cid2name_${value}`, name) diff --git a/src/serve/errors.ts b/src/serve/errors.ts index a49225e..adcecfc 100644 --- a/src/serve/errors.ts +++ b/src/serve/errors.ts @@ -3,3 +3,4 @@ import { ChelErrorGenerator } from 'npm:@chelonia/lib/errors' export const BackendErrorNotFound = ChelErrorGenerator('BackendErrorNotFound') export const BackendErrorGone = ChelErrorGenerator('BackendErrorGone') export const BackendErrorBadData = ChelErrorGenerator('BackendErrorBadData') +export const BackendErrorConflict = ChelErrorGenerator('BackendErrorConflict') diff --git a/src/serve/index.ts b/src/serve/index.ts index 66414ba..b887885 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -46,7 +46,7 @@ sbp('okTurtles.events/once', SERVER_EXITING, () => { pubsub.on('close', async function () { try { await sbp('backend/server/stop') - console.info('Hapi server down') + console.info('Server down') } catch (err) { console.error(err, 'Error during shutdown') } finally { diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 6579605..1158512 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -5,12 +5,11 @@ import { SPMessage } from 'npm:@chelonia/lib/SPMessage' import 'npm:@chelonia/lib/chelonia' import { blake32Hash, createCID, maybeParseCID, multicodes } from 'npm:@chelonia/lib/functions' import 'npm:@chelonia/lib/persistent-actions' -import Boom from 'npm:@hapi/boom' -import * as Hapi from 'npm:@hapi/hapi' import sbp from 'npm:@sbp/sbp' import Bottleneck from 'npm:bottleneck' import chalk from 'npm:chalk' -import Joi from 'npm:joi' +import { HTTPException } from 'npm:hono/http-exception' +import { getConnInfo } from 'npm:@hono/node-server/conninfo' // TODO: Use logger for debugging route handlers import { isIP } from 'node:net' import path from 'node:path' @@ -21,6 +20,9 @@ import logger from './logger.ts' import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' +import { authMiddleware, type AuthCredentials } from './auth.ts' +import type { Hono, Context } from 'npm:hono' +import { Readable } from 'node:stream' const MEGABYTE = 1048576 // TODO: add settings for these const SECOND = 1000 @@ -146,240 +148,225 @@ const ctEq = (expected: string, actual: string): boolean => { return r === 0 } -// Boom and Joi already imported above const isCheloniaDashboard = process.env.IS_CHELONIA_DASHBOARD_DEV const appDir = nconf.get('server:appDir') || '.' const dashboardDir = import.meta.dirname || './build/dist-dashboard' -const staticServeConfig = { +export const staticServeConfig = { routePath: isCheloniaDashboard ? '/dashboard/{path*}' : '/app/{path*}', distAssets: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'assets')), distIndexHtml: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'index.html')), redirect: isCheloniaDashboard ? '/dashboard/' : '/app/' } -const errorMapper = (e: Error): ReturnType => { +const errorMapper = (e: Error): never => { switch (e?.name) { case 'BackendErrorNotFound': - return Boom.notFound() + throw new HTTPException(404) case 'BackendErrorGone': - return Boom.resourceGone() + throw new HTTPException(410) case 'BackendErrorBadData': - return Boom.badData(e.message) + throw new HTTPException(422, { message: e.message }) default: console.error(e, 'Unexpected backend error') - return Boom.internal(e.message ?? 'internal error') + throw new HTTPException(500, { message: e.message ?? 'internal error' }) } } -// We define a `Proxy` for route so that we can use `route.VERB` syntax for -// defining routes instead of calling `server.route` with an object, and to -// dynamically get the HAPI server object from the `SERVER_INSTANCE`, which is -// defined in `server.js`. -interface RouteHandler { - (path: string, options: Hapi.RouteOptions, handler: Hapi.Lifecycle.Method | Hapi.HandlerDecorations): void; -} - -type RouteProxy = Record - -const route = new Proxy({} as RouteProxy, { - get: function (_obj, prop: Hapi.RouteDefMethods): RouteHandler { - return function (path, options, handler): void { - sbp('okTurtles.data/apply', SERVER_INSTANCE, function (server: Hapi.Server) { - server.route({ path, method: prop, options, handler }) - }) - } +function getClientIP (c: Context): string { + const headerIP = c.req.header('x-real-ip') + if (headerIP) return headerIP + try { + const info = getConnInfo(c) + return info.remote.address || 'unknown' + } catch { + return 'unknown' } -}) +} // helper function that returns 404 and prevents client from caching the 404 response // which can sometimes break things: https://github.com/okTurtles/group-income/issues/2608 -function notFoundNoCache (h: Hapi.ResponseToolkit): ReturnType { - return h.response().code(404).header('Cache-Control', 'no-store') +function notFoundNoCache (c: Context): Response { + return c.body(null, 404, { 'Cache-Control': 'no-store' }) } +// Get the Hono app via SERVER_INSTANCE +const app: Hono = sbp('okTurtles.data/get', SERVER_INSTANCE) + // RESTful API routes // NOTE: We could get rid of this RESTful API and just rely on pubsub.js to do this // —BUT HTTP2 might be better than websockets and so we keep this around. // See related TODO in pubsub.js and the reddit discussion link. -route.POST('/event', { - auth: { - strategy: 'chel-shelter', - mode: 'optional' - }, - validate: { - headers: Joi.object({ - 'shelter-namespace-registration': Joi.string().regex(NAME_REGEX) - }), - options: { - allowUnknown: true - }, - payload: Joi.string().required() - } -}, async function (request) { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE - // X-Real-IP HEADER! OTHERWISE THIS IS EASILY SPOOFED! - const ip = request.headers['x-real-ip'] || request.info.remoteAddress - try { - const deserializedHEAD = SPMessage.deserializeHEAD(request.payload as string) +app.post('/event', + authMiddleware('chel-shelter', 'optional'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE + // X-Real-IP HEADER! OTHERWISE THIS IS EASILY SPOOFED! + const ip = getClientIP(c) try { - const parsed = maybeParseCID(deserializedHEAD.head.manifest) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { - return Boom.badData('Invalid manifest') + const payload = await c.req.text() + const namespaceRegistration = c.req.header('shelter-namespace-registration') + if (namespaceRegistration && !NAME_REGEX.test(namespaceRegistration)) { + throw new HTTPException(400, { message: 'Invalid shelter-namespace-registration header' }) } - const credentials = request.auth.credentials - // Only allow identity contracts to be created without attribution - if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { - const manifest = await sbp('chelonia.db/get', deserializedHEAD.head.manifest) - const parsedManifest = JSON.parse(manifest) - const { name } = JSON.parse(parsedManifest.body) - if (name !== 'gi.contracts/identity') { - return Boom.unauthorized('This contract type requires ownership information', 'shelter') - } - if (nconf.get('server:signup:disabled')) { - return Boom.forbidden('Registration disabled') + const deserializedHEAD = SPMessage.deserializeHEAD(payload) + try { + const parsed = maybeParseCID(deserializedHEAD.head.manifest) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { + throw new HTTPException(422, { message: 'Invalid manifest' }) } - // rate limit signups in production - if (!SIGNUP_LIMIT_DISABLED) { - try { - // See discussion: https://github.com/okTurtles/group-income/pull/2280#pullrequestreview-2219347378 - const keyedIp = limiterKey(ip) - await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()) - await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()) - await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()) - } catch { - console.warn('rate limit hit for IP:', ip) - throw Boom.tooManyRequests('Rate limit exceeded') + const credentials = c.get('credentials') as AuthCredentials | undefined + // Only allow identity contracts to be created without attribution + if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { + const manifest = await sbp('chelonia.db/get', deserializedHEAD.head.manifest) + const parsedManifest = JSON.parse(manifest) + const { name } = JSON.parse(parsedManifest.body) + if (name !== 'gi.contracts/identity') { + throw new HTTPException(401, { message: 'This contract type requires ownership information' }) + } + if (nconf.get('server:signup:disabled')) { + throw new HTTPException(403, { message: 'Registration disabled' }) + } + // rate limit signups in production + if (!SIGNUP_LIMIT_DISABLED) { + try { + // See discussion: https://github.com/okTurtles/group-income/pull/2280#pullrequestreview-2219347378 + const keyedIp = limiterKey(ip) + await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()) + await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()) + await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()) + } catch { + console.warn('rate limit hit for IP:', ip) + throw new HTTPException(429, { message: 'Rate limit exceeded' }) + } } } - } - const saltUpdateToken = request.headers['shelter-salt-update-token'] - let updateSalts - if (saltUpdateToken) { - // If we've got a salt update token (i.e., a password change), - // validate the token - updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken) - } - await sbp('backend/server/handleEntry', deserializedHEAD, request.payload) - // If it's a salt update, do it now after handling the message. This way - // we make it less likely that someone will end up locked out from their - // identity contract. - await updateSalts?.(deserializedHEAD.hash) - if (deserializedHEAD.isFirstMessage) { - // Store attribution information - if (credentials?.billableContractID) { - await sbp('backend/server/saveOwner', credentials.billableContractID, deserializedHEAD.contractID) - // A billable entity has been created - } else { - await sbp('backend/server/registerBillableEntity', deserializedHEAD.contractID) + const saltUpdateToken = c.req.header('shelter-salt-update-token') + let updateSalts + if (saltUpdateToken) { + // If we've got a salt update token (i.e., a password change), + // validate the token + updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken) } - // If this is the first message in a contract and the - // `shelter-namespace-registration` header is present, proceed with also - // registering a name for the new contract - const name = request.headers['shelter-namespace-registration'] - if (name) { - // Name registation is enabled only for identity contracts - const cheloniaState = sbp('chelonia/rootState') - if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === 'gi.contracts/identity') { - const r = await sbp('backend/db/registerName', name, deserializedHEAD.contractID) - if (Boom.isBoom(r)) { - return r - } - const saltRegistrationToken = request.headers['shelter-salt-registration-token'] - console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`) - if (saltRegistrationToken) { - // If we've got a salt registration token, redeem it - await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken) + await sbp('backend/server/handleEntry', deserializedHEAD, payload) + // If it's a salt update, do it now after handling the message. This way + // we make it less likely that someone will end up locked out from their + // identity contract. + await updateSalts?.(deserializedHEAD.hash) + if (deserializedHEAD.isFirstMessage) { + // Store attribution information + if (credentials?.billableContractID) { + await sbp('backend/server/saveOwner', credentials.billableContractID, deserializedHEAD.contractID) + // A billable entity has been created + } else { + await sbp('backend/server/registerBillableEntity', deserializedHEAD.contractID) + } + // If this is the first message in a contract and the + // `shelter-namespace-registration` header is present, proceed with also + // registering a name for the new contract + const name = c.req.header('shelter-namespace-registration') + if (name) { + // Name registation is enabled only for identity contracts + const cheloniaState = sbp('chelonia/rootState') + if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === 'gi.contracts/identity') { + try { + await sbp('backend/db/registerName', name, deserializedHEAD.contractID) + } catch (registerErr: unknown) { + if ((registerErr as Error).name === 'BackendErrorConflict') { + throw new HTTPException(409, { message: 'Name already exists' }) + } + throw registerErr + } + const saltRegistrationToken = c.req.header('shelter-salt-registration-token') + console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`) + if (saltRegistrationToken) { + // If we've got a salt registration token, redeem it + await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken) + } } } + const deletionTokenDgst = c.req.header('shelter-deletion-token-digest') + if (deletionTokenDgst) { + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst) + } } - const deletionTokenDgst = request.headers['shelter-deletion-token-digest'] - if (deletionTokenDgst) { - await sbp('chelonia.db/set', `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst) + // Store size information + await sbp('backend/server/updateSize', deserializedHEAD.contractID, Buffer.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : undefined) + } catch (err: unknown) { + if (err instanceof HTTPException) throw err + console.error(err, chalk.bold.yellow((err as Error).name)) + if ((err as Error).name === 'ChelErrorDBBadPreviousHEAD' || (err as Error).name === 'ChelErrorAlreadyProcessed') { + const HEADinfo = await sbp('chelonia/db/latestHEADinfo', deserializedHEAD.contractID) ?? { HEAD: null, height: 0 } + return c.json({ message: (err as Error).message, data: { HEADinfo } }, 409, { + 'shelter-headinfo-head': HEADinfo.HEAD, + 'shelter-headinfo-height': String(HEADinfo.height) + }) + } else if ((err as Error).name === 'ChelErrorSignatureError') { + throw new HTTPException(422, { message: 'Invalid signature' }) + } else if ((err as Error).name === 'ChelErrorSignatureKeyUnauthorized') { + throw new HTTPException(403, { message: 'Unauthorized signing key' }) } + throw err // rethrow error } - // Store size information - await sbp('backend/server/updateSize', deserializedHEAD.contractID, Buffer.byteLength(request.payload as Buffer), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : undefined) - } catch (err: unknown) { - console.error(err, chalk.bold.yellow((err as Error).name)) - if ((err as Error).name === 'ChelErrorDBBadPreviousHEAD' || (err as Error).name === 'ChelErrorAlreadyProcessed') { - const HEADinfo = await sbp('chelonia/db/latestHEADinfo', deserializedHEAD.contractID) ?? { HEAD: null, height: 0 } - const r = Boom.conflict((err as Error).message, { HEADinfo }) - Object.assign(r.output.headers, { - 'shelter-headinfo-head': HEADinfo.HEAD, - 'shelter-headinfo-height': HEADinfo.height - }) - return r - } else if ((err as Error).name === 'ChelErrorSignatureError') { - return Boom.badData('Invalid signature') - } else if ((err as Error).name === 'ChelErrorSignatureKeyUnauthorized') { - return Boom.forbidden('Unauthorized signing key') - } - throw err // rethrow error + return c.text(deserializedHEAD.hash) + } catch (err) { + if (err instanceof HTTPException) throw err + ;(err as unknown as { ip: string }).ip = ip + logger.error(err, 'POST /event', (err as Error).message) + throw err } - return deserializedHEAD.hash - } catch (err) { - (err as unknown as { ip: string }).ip = ip - logger.error(err, 'POST /event', (err as Error).message) - return err - } -}) + }) -route.GET('/eventsAfter/{contractID}/{since}/{limit?}', { - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required(), - since: Joi.string().regex(POSITIVE_INTEGER_REGEX).required(), - limit: Joi.string().regex(POSITIVE_INTEGER_REGEX) - }), - query: Joi.object({ - keyOps: Joi.boolean() - }) - } -}, async function (request) { - const { contractID, since, limit } = request.params - const ip = request.headers['x-real-ip'] || request.info.remoteAddress - try { - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return Boom.badRequest() - } +app.get('/eventsAfter/:contractID/:since/:limit?', + async function (c) { + const contractID = c.req.param('contractID') + const since = c.req.param('since') + const limit = c.req.param('limit') - const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: !!request.query['keyOps'] }) - // "On an HTTP server, make sure to manually close your streams if a request is aborted." - // From: http://knexjs.org/#Interfaces-Streams - // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams - // Plus: https://hapijs.com/api#request-events - // request.on('disconnect', stream.end.bind(stream)) - // NOTE: since rewriting database.js to remove objection.js and knex, - // we're currently returning a Readable stream, which doesn't have - // '.end'. If there are any issues we can try switching to returning a - // Writable stream. Both types however do have .destroy. - request.events.once('disconnect', stream.destroy.bind(stream)) - return stream - } catch (err) { - (err as unknown as { ip: string }).ip = ip - logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) - return err as object[] - } -}) + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + if (!POSITIVE_INTEGER_REGEX.test(since)) throw new HTTPException(400, { message: 'Invalid since' }) + if (limit !== undefined && !POSITIVE_INTEGER_REGEX.test(limit)) throw new HTTPException(400, { message: 'Invalid limit' }) + + const keyOps = c.req.query('keyOps') + const ip = getClientIP(c) + try { + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } + + const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: keyOps === 'true' }) as Readable + // "On an HTTP server, make sure to manually close your streams if a request is aborted." + // From: http://knexjs.org/#Interfaces-Streams + // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams + // Use the request abort signal to destroy the stream when the client disconnects + c.req.raw.signal.addEventListener('abort', () => stream.destroy()) + // Convert the Node Readable stream to a web ReadableStream for the Response + const webStream = Readable.toWeb(stream) as ReadableStream + return new Response(webStream, { + headers: { 'content-type': 'application/octet-stream' } + }) + } catch (err) { + if (err instanceof HTTPException) throw err + ;(err as unknown as { ip: string }).ip = ip + logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) + throw err + } + }) // This endpoint returns to anyone in possession of a contract's SAK all of the // resources that that contract owns (without recursion). This is useful for // APIs and for some UI actions (e.g., to warn users about resources that would // be (cascade) deleted following a delete) -route.GET('/ownResources', { - auth: { - strategies: ['chel-shelter'], - mode: 'required' - } -}, async function (request): Promise { - const billableContractID = request.auth.credentials.billableContractID - const resources = (await sbp('chelonia.db/get', `_private_resources_${billableContractID}`))?.split('\x00') +app.get('/ownResources', + authMiddleware('chel-shelter', 'required'), + async function (c) { + const billableContractID = (c.get('credentials') as AuthCredentials).billableContractID + const resources = (await sbp('chelonia.db/get', `_private_resources_${billableContractID}`))?.split('\x00') - return resources || [] -}) + return c.json(resources || []) + }) if (process.env.NODE_ENV === 'development') { const levelToColor = { @@ -389,19 +376,14 @@ if (process.env.NODE_ENV === 'development') { info: chalk.green, debug: chalk.blue } - route.POST('/log', { - validate: { - payload: Joi.object({ - level: Joi.string().required(), - value: Joi.string().required() - }) - } - }, function (request, h) { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - const ip = request.headers['x-real-ip'] || request.info.remoteAddress - const log = (levelToColor as Record string>)[(request.payload as { level: string }).level] - console.debug(chalk.bold.yellow(`REMOTE LOG (${ip}): `) + log(`[${(request.payload as { level: string }).level}] ${(request.payload as { value: string }).value}`)) - return h.response().code(200) + app.post('/log', async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const body = await c.req.json() as { level: string, value: string } + if (!body.level || !body.value) throw new HTTPException(400, { message: 'level and value are required' }) + const ip = getClientIP(c) + const log = (levelToColor as Record string>)[body.level] + console.debug(chalk.bold.yellow(`REMOTE LOG (${ip}): `) + log(`[${body.level}] ${body.value}`)) + return c.body(null, 200) }) } @@ -409,77 +391,61 @@ if (process.env.NODE_ENV === 'development') { // The following endpoint is disabled because name registrations are handled // through the `shelter-namespace-registration` header when registering a // new contract -route.POST('/name', { - validate: { - payload: Joi.object({ - name: Joi.string().required(), - value: Joi.string().required() - }) - } -}, async function (request, h): Promise { +app.post('/name', async function (c) { try { - const { name, value } = request.payload - if (value.startsWith('_private')) return Boom.badData() - return await sbp('backend/db/registerName', name, value) + const { name, value } = await c.req.json() + if (!name || !value) throw new HTTPException(400) + if (value.startsWith('_private')) throw new HTTPException(422) + return c.json(await sbp('backend/db/registerName', name, value)) } catch (err) { + if (err instanceof HTTPException) throw err logger.error(err, 'POST /name', (err as Error).message) - return err + throw err } }) */ -route.GET('/name/{name}', { - validate: { - params: Joi.object({ - name: Joi.string().regex(NAME_REGEX).required() - }) - } -}, async function (request, h): Promise { - const { name } = request.params +app.get('/name/:name', async function (c) { + const name = c.req.param('name') + if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: 'Invalid name' }) try { const lookupResult = await sbp('backend/db/lookupName', name) return lookupResult - ? h.response(lookupResult).type('text/plain') - : notFoundNoCache(h) + ? c.text(lookupResult) + : notFoundNoCache(c) } catch (err) { logger.error(err, `GET /name/${name}`, (err as Error).message) - return err + throw err } }) -route.GET('/latestHEADinfo/{contractID}', { - cache: { otherwise: 'no-store' }, - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required() - }) - } -}, async function (request, h): Promise { - const { contractID } = request.params +app.get('/latestHEADinfo/:contractID', async function (c) { + const contractID = c.req.param('contractID') + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) try { const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) return Boom.badRequest() + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) const HEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) if (HEADinfo === '') { - return Boom.resourceGone() + throw new HTTPException(410) } if (!HEADinfo) { console.warn(`[backend] latestHEADinfo not found for ${contractID}`) - return notFoundNoCache(h) + return notFoundNoCache(c) } - return HEADinfo + return c.json(HEADinfo, 200, { 'Cache-Control': 'no-store' }) } catch (err) { + if (err instanceof HTTPException) throw err logger.error(err, `GET /latestHEADinfo/${contractID}`, (err as Error).message) - return err + throw err } }) -route.GET('/time', {}, function (_request, h) { - return h - .response(new Date().toISOString()) - .header('cache-control', 'no-store') - .type('text/plain') +app.get('/time', function (c) { + return c.text(new Date().toISOString(), 200, { + 'Cache-Control': 'no-store' + }) }) // TODO: if the browser deletes our cache then not everyone @@ -487,701 +453,669 @@ route.GET('/time', {}, function (_request, h) { // new coordinating server... I don't like that. // API endpoint to check for streams support -route.POST('/streams-test', { - payload: { - parse: false - } -}, -function (request, h) { - if ( - (request.payload as Buffer).byteLength === 2 && - Buffer.from(request.payload as Buffer).toString() === 'ok' - ) { - return h.response().code(204) +app.post('/streams-test', async function (c) { + const raw = await c.req.arrayBuffer() + const buf = Buffer.from(raw) + if (buf.byteLength === 2 && buf.toString() === 'ok') { + return c.body(null, 204) } else { - return Boom.badRequest() + throw new HTTPException(400) } -} -) +}) // Development file upload route. The difference between this and /file is that // this endpoint bypasses checks in /file for well-formedness, and it also // doesn't set or read accounting information. // If accepted, the file will be stored in Chelonia DB. if (process.env.NODE_ENV === 'development') { - route.POST('/dev-file', { - payload: { - output: 'data', - multipart: true, - allow: 'multipart/form-data', - failAction: function (_request, _h, err) { - console.error('failAction error:', err) - return Boom.isBoom(err) ? err : Boom.boomify(err instanceof Error ? err : new Error(err)) - }, - maxBytes: 6 * MEGABYTE, // TODO: make this a configurable setting - timeout: 10 * SECOND // TODO: make this a configurable setting - } - }, async function (request): Promise { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') + app.post('/dev-file', async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { console.log('FILE UPLOAD!') - const { hash, data } = request.payload as ({hash: string, data: string}) - if (!hash) return Boom.badRequest('missing hash') - if (!data) return Boom.badRequest('missing data') + const formData = await c.req.parseBody({ all: true }) + const hash = formData['hash'] as string + const data = formData['data'] as string + if (!hash) throw new HTTPException(400, { message: 'missing hash' }) + if (!data) throw new HTTPException(400, { message: 'missing data' }) const parsed = maybeParseCID(hash) - if (!parsed) return Boom.badRequest('invalid hash') + if (!parsed) throw new HTTPException(400, { message: 'invalid hash' }) const ourHash = createCID(data, parsed.code) if (ourHash !== hash) { console.error(`hash(${hash}) != ourHash(${ourHash})`) - return Boom.badRequest('bad hash!') + throw new HTTPException(400, { message: 'bad hash!' }) } await sbp('chelonia.db/set', hash, data) - return '/file/' + hash + return c.text('/file/' + hash) } catch (err) { + if (err instanceof HTTPException) throw err logger.error(err) - return Boom.internal('File upload failed') + throw new HTTPException(500, { message: 'File upload failed' }) } }) } // File upload route. // If accepted, the file will be stored in Chelonia DB. -route.POST('/file', { - auth: { - strategies: ['chel-shelter'], - mode: 'required' - }, - payload: { - parse: true, - output: 'stream', - multipart: { output: 'annotated' }, - allow: 'multipart/form-data', - failAction: function (_request, _h, err) { - console.error(err, 'failAction error') - return Boom.isBoom(err) ? err : Boom.boomify(err instanceof Error ? err : new Error(err)) - }, - maxBytes: FILE_UPLOAD_MAX_BYTES, - timeout: 10 * SECOND // TODO: make this a configurable setting - } -}, async function (request, h): Promise { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - try { - console.info('FILE UPLOAD!') - const credentials = request.auth.credentials - if (!credentials?.billableContractID) { - return Boom.unauthorized('Uploading files requires ownership information', 'shelter') - } - const manifestMeta = (request.payload as { manifest: Record })['manifest'] - if (typeof manifestMeta !== 'object') return Boom.badRequest('missing manifest') - if (manifestMeta.filename !== 'manifest.json') return Boom.badRequest('wrong manifest filename') - if (!(manifestMeta.payload instanceof Uint8Array)) return Boom.badRequest('wrong manifest format') - const manifest = (() => { - try { - return JSON.parse(Buffer.from(manifestMeta.payload).toString()) - } catch { - throw Boom.badData('Error parsing manifest') +app.post('/file', + authMiddleware('chel-shelter', 'required'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + try { + console.info('FILE UPLOAD!') + const credentials = c.get('credentials') as AuthCredentials + if (!credentials?.billableContractID) { + throw new HTTPException(401, { message: 'Uploading files requires ownership information' }) } - })() - if (typeof manifest !== 'object') return Boom.badData('manifest format is invalid') - if (manifest.version !== '1.0.0') return Boom.badData('unsupported manifest version') - if (manifest.cipher !== 'aes256gcm') return Boom.badData('unsupported cipher') - if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) return Boom.badData('missing chunks') - - // Now that the manifest format looks right, validate the chunks - let ourSize = 0 - const chunks = manifest.chunks.map((chunk: { hash: string; size: number }, i: number) => { - // Validate the chunk information - if ( - !Array.isArray(chunk) || - chunk.length !== 2 || - typeof chunk[0] !== 'number' || - typeof chunk[1] !== 'string' || - !Number.isSafeInteger(chunk[0]) || - chunk[0] <= 0 - ) { - throw Boom.badData('bad chunk description') + + const contentType = c.req.header('content-type') || '' + if (!contentType.includes('multipart/form-data')) { + throw new HTTPException(400, { message: 'Expected multipart/form-data' }) } - if (!(request.payload as unknown[])[i] || !((request.payload as { payload: unknown }[])[i].payload instanceof Uint8Array)) { - throw Boom.badRequest('chunk missing in submitted data') + + // Check content-length before reading body + const contentLength = parseInt(c.req.header('content-length') || '0', 10) + if (contentLength > FILE_UPLOAD_MAX_BYTES) { + throw new HTTPException(413, { message: 'Payload too large' }) } - const ourHash = createCID((request.payload as { payload: Uint8Array }[])[i].payload, multicodes.SHELTER_FILE_CHUNK) - if ((request.payload as { payload: Uint8Array }[])[i].payload.byteLength !== chunk[0]) { - throw Boom.badRequest('bad chunk size') + + const formData = await c.req.formData() + const manifestFile = formData.get('manifest') as File | null + if (!manifestFile) throw new HTTPException(400, { message: 'missing manifest' }) + if (manifestFile.name !== 'manifest.json') throw new HTTPException(400, { message: 'wrong manifest filename' }) + const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()) + + const manifest = (() => { + try { + return JSON.parse(Buffer.from(manifestPayload).toString()) + } catch { + throw new HTTPException(422, { message: 'Error parsing manifest' }) + } + })() + if (typeof manifest !== 'object') throw new HTTPException(422, { message: 'manifest format is invalid' }) + if (manifest.version !== '1.0.0') throw new HTTPException(422, { message: 'unsupported manifest version' }) + if (manifest.cipher !== 'aes256gcm') throw new HTTPException(422, { message: 'unsupported cipher' }) + if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new HTTPException(422, { message: 'missing chunks' }) + + // Collect all chunk files from form data (numbered keys: 0, 1, 2, ...) + const chunkFiles: File[] = [] + for (let i = 0; ; i++) { + const chunkFile = formData.get(String(i)) as File | null + if (!chunkFile) break + chunkFiles.push(chunkFile) } - if (ourHash !== chunk[1]) { - throw Boom.badRequest('bad chunk hash') + + // Now that the manifest format looks right, validate the chunks + let ourSize = 0 + const chunks: [string, Uint8Array][] = await Promise.all(manifest.chunks.map(async (chunk: [number, string], i: number) => { + // Validate the chunk information + if ( + !Array.isArray(chunk) || + chunk.length !== 2 || + typeof chunk[0] !== 'number' || + typeof chunk[1] !== 'string' || + !Number.isSafeInteger(chunk[0]) || + chunk[0] <= 0 + ) { + throw new HTTPException(422, { message: 'bad chunk description' }) + } + if (!chunkFiles[i]) { + throw new HTTPException(400, { message: 'chunk missing in submitted data' }) + } + const chunkPayload = new Uint8Array(await chunkFiles[i].arrayBuffer()) + const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK) + if (chunkPayload.byteLength !== chunk[0]) { + throw new HTTPException(400, { message: 'bad chunk size' }) + } + if (ourHash !== chunk[1]) { + throw new HTTPException(400, { message: 'bad chunk hash' }) + } + // We're done validating the chunk + ourSize += chunk[0] + return [ourHash, chunkPayload] as [string, Uint8Array] + })) + // Finally, verify the size is correct + if (ourSize !== manifest.size) throw new HTTPException(400, { message: 'Mismatched total size' }) + + const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST) + + // Check that we're not overwriting data. At best this is a useless operation + // since there is no need to write things that exist. However, overwriting + // data would also make it ambiguous in terms of ownership. For example, + // someone could upload a file F1 using some existing chunks (from a + // different file F2) and then request to delete their file F1, which would + // result in corrupting F2. + // Ensure that the manifest doesn't exist + if (await sbp('chelonia.db/get', manifestHash)) { + throw new Error(`Manifest ${manifestHash} already exists`) } - // We're done validating the chunk - ourSize += chunk[0] - return [ourHash, (request.payload as { payload: Uint8Array }[])[i].payload] - }) - // Finally, verify the size is correct - if (ourSize !== manifest.size) return Boom.badRequest('Mismatched total size') - - const manifestHash = createCID(manifestMeta.payload, multicodes.SHELTER_FILE_MANIFEST) - - // Check that we're not overwriting data. At best this is a useless operation - // since there is no need to write things that exist. However, overwriting - // data would also make it ambiguous in terms of ownership. For example, - // someone could upload a file F1 using some existing chunks (from a - // different file F2) and then request to delete their file F1, which would - // result in corrupting F2. - // Ensure that the manifest doesn't exist - if (await sbp('chelonia.db/get', manifestHash)) { - throw new Error(`Manifest ${manifestHash} already exists`) - } - // Ensure that the chunks do not exist - await Promise.all(chunks.map(async ([cid]: [string]) => { - const exists = !!(await sbp('chelonia.db/get', cid)) - if (exists) { - throw new Error(`Chunk ${cid} already exists`) + // Ensure that the chunks do not exist + await Promise.all(chunks.map(async ([cid]) => { + const exists = !!(await sbp('chelonia.db/get', cid)) + if (exists) { + throw new Error(`Chunk ${cid} already exists`) + } + })) + // Now, store all chunks and the manifest + await Promise.all(chunks.map(([cid, data]) => sbp('chelonia.db/set', cid, data))) + await sbp('chelonia.db/set', manifestHash, manifestPayload) + // Store attribution information + await sbp('backend/server/saveOwner', credentials.billableContractID, manifestHash) + // Store size information + const size = manifest.size + manifestPayload.byteLength + await sbp('backend/server/updateSize', manifestHash, size) + await sbp('backend/server/updateContractFilesTotalSize', credentials.billableContractID, size) + // Store deletion token + const deletionTokenDgst = c.req.header('shelter-deletion-token-digest') + if (deletionTokenDgst) { + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst) } - })) - // Now, store all chunks and the manifest - await Promise.all(chunks.map(([cid, data]: [string, unknown]) => sbp('chelonia.db/set', cid, data))) - await sbp('chelonia.db/set', manifestHash, manifestMeta.payload) - // Store attribution information - await sbp('backend/server/saveOwner', credentials.billableContractID, manifestHash) - // Store size information - const size = manifest.size + manifestMeta.payload.byteLength - await sbp('backend/server/updateSize', manifestHash, size) - await sbp('backend/server/updateContractFilesTotalSize', credentials.billableContractID, size) - // Store deletion token - const deletionTokenDgst = request.headers['shelter-deletion-token-digest'] - if (deletionTokenDgst) { - await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst) + return c.text(manifestHash) + } catch (err) { + if (err instanceof HTTPException) throw err + logger.error(err, 'POST /file', (err as Error).message) + throw err } - return h.response(manifestHash) - } catch (err) { - logger.error(err, 'POST /file', (err as Error).message) - return err - } -}) + }) // Serve data from Chelonia DB. // Note that a `Last-Modified` header isn't included in the response. -route.GET('/file/{hash}', { - validate: { - params: Joi.object({ - hash: Joi.string().regex(CID_REGEX).required() - }) - } -}, async function (request, h): Promise { - const { hash } = request.params +app.get('/file/:hash', async function (c) { + const hash = c.req.param('hash') + if (!CID_REGEX.test(hash)) throw new HTTPException(400, { message: 'Invalid hash' }) const parsed = maybeParseCID(hash) if (!parsed) { - return Boom.badRequest() + throw new HTTPException(400) } const blobOrString = await sbp('chelonia.db/get', `any:${hash}`) if (blobOrString?.length === 0) { - return Boom.resourceGone() + throw new HTTPException(410) } else if (!blobOrString) { - return notFoundNoCache(h) + return notFoundNoCache(c) } const type = cidLookupTable[parsed.code] || 'application/octet-stream' - return h - .response(blobOrString) - .etag(hash) - .header('Cache-Control', 'public,max-age=31536000,immutable') + return c.body(blobOrString, 200, { + 'ETag': `"${hash}"`, + 'Cache-Control': 'public,max-age=31536000,immutable', // CSP to disable everything -- this only affects direct navigation to the // `/file` URL. // The CSP below prevents any sort of resource loading or script execution // on direct navigation. The `nosniff` header instructs the browser to // honour the provided content-type. - .header('content-security-policy', 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox') - .header('x-content-type-options', 'nosniff') - .type(type) + 'Content-Security-Policy': 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox', + 'X-Content-Type-Options': 'nosniff', + 'Content-Type': type + }) }) -route.POST('/deleteFile/{hash}', { - auth: { - // Allow file deletion, and allow either the bearer of the deletion token or - // the file owner to delete it - strategies: ['chel-shelter', 'chel-bearer'], - mode: 'required' - }, - validate: { - params: Joi.object({ - hash: Joi.string().regex(CID_REGEX).required() - }) - } -}, async function (request, h): Promise { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - const { hash } = request.params - const strategy = request.auth.strategy - const parsed = maybeParseCID(hash) - if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { - return Boom.badRequest() - } - - const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) - if (!owner) { - return Boom.notFound() - } +app.post('/deleteFile/:hash', + authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const hash = c.req.param('hash') + if (!CID_REGEX.test(hash)) throw new HTTPException(400, { message: 'Invalid hash' }) + const strategy = c.get('authStrategy') + const parsed = maybeParseCID(hash) + if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { + throw new HTTPException(400) + } - switch (strategy) { - case 'chel-shelter': { - const ultimateOwner = await lookupUltimateOwner(owner) - // Check that the user making the request is the ultimate owner (i.e., - // that they have permission to delete this file) - if (!ctEq(request.auth.credentials.billableContractID as string, ultimateOwner)) { - return Boom.unauthorized('Invalid shelter auth', 'shelter') - } - break + const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) + if (!owner) { + throw new HTTPException(404) } - case 'chel-bearer': { - const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) - if (!expectedTokenDgst) { - return Boom.notFound() + + const credentials = c.get('credentials') as AuthCredentials + switch (strategy) { + case 'chel-shelter': { + const ultimateOwner = await lookupUltimateOwner(owner) + // Check that the user making the request is the ultimate owner (i.e., + // that they have permission to delete this file) + if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { + throw new HTTPException(401, { message: 'Invalid shelter auth' }) + } + break } - const tokenDgst = blake32Hash(request.auth.credentials.token as string) - // Constant-time comparison - // Check that the token provided matches the deletion token for this file - if (!ctEq(expectedTokenDgst, tokenDgst)) { - return Boom.unauthorized('Invalid token', 'bearer') + case 'chel-bearer': { + const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) + if (!expectedTokenDgst) { + throw new HTTPException(404) + } + const tokenDgst = blake32Hash(credentials.token as string) + // Constant-time comparison + // Check that the token provided matches the deletion token for this file + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: 'Invalid token' }) + } + break } - break + default: + throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) } - default: - return Boom.unauthorized('Missing or invalid auth strategy') - } - // Authentication passed, now proceed to delete the file and its associated - // keys - try { - await sbp('backend/deleteFile', hash, null, true) - return h.response() - } catch (e) { - return errorMapper(e as Error) - } -}) + // Authentication passed, now proceed to delete the file and its associated + // keys + try { + await sbp('backend/deleteFile', hash, null, true) + return c.body(null, 200) + } catch (e) { + errorMapper(e as Error) + } + }) -route.POST('/deleteContract/{hash}', { - auth: { - // Allow file deletion, and allow either the bearer of the deletion token or - // the file owner to delete it - strategies: ['chel-shelter', 'chel-bearer'], - mode: 'required' - } -}, async function (request, h): Promise { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - const { hash } = request.params - const strategy = request.auth.strategy - if (!hash || hash.startsWith('_private')) return Boom.notFound() - - switch (strategy) { - case 'chel-shelter': { - const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) - if (!owner) { - return Boom.notFound() - } +app.post('/deleteContract/:hash', + authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const hash = c.req.param('hash') + const strategy = c.get('authStrategy') + if (!hash || hash.startsWith('_private')) throw new HTTPException(404) + + const credentials = c.get('credentials') as AuthCredentials + switch (strategy) { + case 'chel-shelter': { + const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) + if (!owner) { + throw new HTTPException(404) + } - const ultimateOwner = await lookupUltimateOwner(owner) - // Check that the user making the request is the ultimate owner (i.e., - // that they have permission to delete this file) - if (!ctEq(request.auth.credentials.billableContractID as string, ultimateOwner)) { - return Boom.unauthorized('Invalid shelter auth', 'shelter') - } - break - } - case 'chel-bearer': { - const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) - if (!expectedTokenDgst) { - return Boom.notFound() + const ultimateOwner = await lookupUltimateOwner(owner) + // Check that the user making the request is the ultimate owner (i.e., + // that they have permission to delete this file) + if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { + throw new HTTPException(401, { message: 'Invalid shelter auth' }) + } + break } - const tokenDgst = blake32Hash(request.auth.credentials.token as string) - // Constant-time comparison - // Check that the token provided matches the deletion token for this contract - if (!ctEq(expectedTokenDgst, tokenDgst)) { - return Boom.unauthorized('Invalid token', 'bearer') + case 'chel-bearer': { + const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) + if (!expectedTokenDgst) { + throw new HTTPException(404) + } + const tokenDgst = blake32Hash(credentials.token as string) + // Constant-time comparison + // Check that the token provided matches the deletion token for this contract + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: 'Invalid token' }) + } + break } - break + default: + throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) } - default: - return Boom.unauthorized('Missing or invalid auth strategy') - } - const username = await sbp('chelonia.db/get', `_private_cid2name_${hash}`) - // Authentication passed, now proceed to delete the contract and its associated - // keys - try { - const [id] = sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', hash, null, true]) - if (username) { - const ip = request.headers['x-real-ip'] || request.info.remoteAddress - console.info({ contractID: hash, username, ip, taskId: id }, 'Scheduled deletion on named contract') + const username = await sbp('chelonia.db/get', `_private_cid2name_${hash}`) + // Authentication passed, now proceed to delete the contract and its associated + // keys + try { + const [id] = sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', hash, null, true]) + if (username) { + const ip = getClientIP(c) + console.info({ contractID: hash, username, ip, taskId: id }, 'Scheduled deletion on named contract') + } + // We return the queue ID to allow users to track progress + // TODO: Tracking progress not yet implemented + return c.json({ id }, 202) + } catch (e) { + errorMapper(e as Error) } - // We return the queue ID to allow users to track progress - // TODO: Tracking progress not yet implemented - return h.response({ id }).code(202) - } catch (e) { - return errorMapper(e as Error) - } -}) + }) -route.POST('/kv/{contractID}/{key}', { - auth: { - strategies: ['chel-shelter'], - mode: 'required' - }, - payload: { - parse: false, - maxBytes: 6 * MEGABYTE, // TODO: make this a configurable setting - timeout: 10 * SECOND // TODO: make this a configurable setting - }, - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required(), - key: Joi.string().regex(KV_KEY_REGEX).required() - }) - } -}, function (request, h) { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - const { contractID, key } = request.params +app.post('/kv/:contractID/:key', + authMiddleware('chel-shelter', 'required'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const contractID = c.req.param('contractID') + const key = c.req.param('key') - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return Boom.badRequest() - } + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: 'Invalid key' }) - if (!ctEq(request.auth.credentials.billableContractID as string, contractID)) { - return Boom.unauthorized(null, 'shelter') - } + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } - // Use a queue to prevent race conditions (for example, writing to a contract - // that's being deleted or updated) - return sbp('chelonia/queueInvocation', contractID, async () => { - const existing = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) - - // Some protection against accidental overwriting by implementing the if-match - // header - // If-Match contains a list of ETags or '*' - // If `If-Match` contains a known ETag, allow the request through, otherwise - // return 412 Precondition Failed. - // This is useful to clients to avoid accidentally overwriting existing data - // For example, client A and client B want to write to key 'K', which contains - // an array. Let's say that the array is originally empty (`[]`) and A and B - // want to append `A` and `B` to it, respectively. If both write at the same - // time, the following could happen: - // t = 0: A reads `K`, gets `[]` - // t = 1: B reads `K`, gets `[]` - // t = 2: A writes `['A']` to `K` - // t = 3: B writes `['B']` to `K` <-- ERROR: B should have written `['A', 'B']` - // To avoid this situation, A and B could use `If-Match`, which would have - // given B a 412 response - const expectedEtag = request.headers['if-match'] - if (!expectedEtag) { - return Boom.badRequest('if-match is required') + const credentials = c.get('credentials') as AuthCredentials + if (!ctEq(credentials.billableContractID as string, contractID)) { + throw new HTTPException(401) } - // "Quote" string (to match ETag format) - const cid = existing ? createCID(existing, multicodes.RAW) : '' - if (expectedEtag === '*') { - // pass through - } else { - if (!expectedEtag.split(',').map((v: string) => v.trim()).includes(`"${cid}"`)) { - // We need this `x-cid` because HAPI modifies Etags - return h.response(existing || '').etag(cid).header('x-cid', `"${cid}"`).code(412) + const payloadBuffer = Buffer.from(await c.req.arrayBuffer()) + + // Use a queue to prevent race conditions (for example, writing to a contract + // that's being deleted or updated) + return sbp('chelonia/queueInvocation', contractID, async () => { + const existing = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) + + // Some protection against accidental overwriting by implementing the if-match + // header + const expectedEtag = c.req.header('if-match') + if (!expectedEtag) { + throw new HTTPException(400, { message: 'if-match is required' }) } - } + // "Quote" string (to match ETag format) + const cid = existing ? createCID(existing, multicodes.RAW) : '' - try { - const serializedData = JSON.parse(request.payload.toString()) - const { contracts } = sbp('chelonia/rootState') - // Check that the height is the latest value. Not only should the height be - // the latest, but also enforcing this lets us check that signatures are - // using the latest (cryptograhpic) keys. Since the KV is detached from the - // contract, in isolation it's impossible to know if an old signature is - // just because it was created in the past, or if it's because someone - // is reusing a previously good key that has since been revoked. - if (contracts[contractID].height !== Number(serializedData.height)) { - return h.response(existing || '').etag(cid).header('x-cid', `"${cid}"`).code(409) + if (expectedEtag === '*') { + // pass through + } else { + if (!expectedEtag.split(',').map((v: string) => v.trim()).includes(`"${cid}"`)) { + return new Response(existing || '', { + status: 412, + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` + } + }) + } } - // Check that the signature is valid - sbp('chelonia/parseEncryptedOrUnencryptedDetachedMessage', { - contractID, - serializedData, - meta: key - }) - } catch { - return Boom.badData() - } - const existingSize = existing ? Buffer.from(existing).byteLength : 0 - await sbp('chelonia.db/set', `_private_kv_${contractID}_${key}`, request.payload) - await sbp('backend/server/updateSize', contractID, (request.payload as Buffer).byteLength - existingSize) - await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key) - // No await on broadcast for faster responses - sbp('backend/server/broadcastKV', contractID, key, request.payload.toString()).catch((e: Error) => console.error(e, 'Error broadcasting KV update', contractID, key)) + try { + const serializedData = JSON.parse(payloadBuffer.toString()) + const { contracts } = sbp('chelonia/rootState') + // Check that the height is the latest value + if (contracts[contractID].height !== Number(serializedData.height)) { + return new Response(existing || '', { + status: 409, + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` + } + }) + } + // Check that the signature is valid + sbp('chelonia/parseEncryptedOrUnencryptedDetachedMessage', { + contractID, + serializedData, + meta: key + }) + } catch (parseErr) { + if (parseErr instanceof Response) throw parseErr + throw new HTTPException(422) + } - return h.response().code(204) - }) -}) + const existingSize = existing ? Buffer.from(existing).byteLength : 0 + await sbp('chelonia.db/set', `_private_kv_${contractID}_${key}`, payloadBuffer) + await sbp('backend/server/updateSize', contractID, payloadBuffer.byteLength - existingSize) + await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key) + // No await on broadcast for faster responses + sbp('backend/server/broadcastKV', contractID, key, payloadBuffer.toString()).catch((e: Error) => console.error(e, 'Error broadcasting KV update', contractID, key)) -route.GET('/kv/{contractID}/{key}', { - auth: { - strategies: ['chel-shelter'], - mode: 'required' - }, - cache: { otherwise: 'no-store' }, - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required(), - key: Joi.string().regex(KV_KEY_REGEX).required() + return c.body(null, 204) }) - } -}, async function (request, h): Promise { - const { contractID, key } = request.params + }) - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return Boom.badRequest() - } +app.get('/kv/:contractID/:key', + authMiddleware('chel-shelter', 'required'), + async function (c) { + const contractID = c.req.param('contractID') + const key = c.req.param('key') - if (!ctEq(request.auth.credentials.billableContractID as string, contractID)) { - return Boom.unauthorized(null, 'shelter') - } + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: 'Invalid key' }) - const result = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) - if (!result) { - return notFoundNoCache(h) - } + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } - const cid = createCID(result, multicodes.RAW) - return h.response(result).etag(cid).header('x-cid', `"${cid}"`) -}) + const credentials = c.get('credentials') as AuthCredentials + if (!ctEq(credentials.billableContractID as string, contractID)) { + throw new HTTPException(401) + } + + const result = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) + if (!result) { + return notFoundNoCache(c) + } -route.GET('/serverMessages', { cache: { otherwise: 'no-store' } }, (_request, h) => { + const cid = createCID(result, multicodes.RAW) + return new Response(result, { + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"`, + 'Cache-Control': 'no-store' + } + }) + }) + +app.get('/serverMessages', function (c) { const messages = nconf.get('server:messages') - if (!messages) return [] - return h.response(messages) + if (!messages) return c.json([]) + return c.json(messages, 200, { 'Cache-Control': 'no-store' }) }) // SPA routes -route.GET('/assets/{subpath*}', { - ext: { - onPostHandler: { - method (request, h) { - // since our JS is placed under /assets/ and since service workers - // have their scope limited by where they are, we must add this - // header to allow the service worker to function. Details: - // https://w3c.github.io/ServiceWorker/#service-worker-allowed - if (request.path.includes('assets/js/sw-')) { - // If `response` is an error, then no SW is being served - if (!(request.response instanceof Boom.Boom)) { - console.debug('adding header: Service-Worker-Allowed /') - request.response.header('Service-Worker-Allowed', '/') - } - } - return h.continue - } - } - }, - files: { - relativeTo: staticServeConfig.distAssets - } -}, function (request, h) { - const { subpath } = request.params +app.get('/assets/:subpath{.+}', async function (c) { + const subpath = c.req.param('subpath') const basename = path.basename(subpath) - // In the build config we told our bundler to use the `[name]-[hash]-cached` template - // to name immutable assets. This is useful because `dist/assets/` currently includes - // a few files without hash in their name. - if (basename.includes('-cached')) { - return h.file(subpath, { etagMethod: false }) - .etag(basename) - .header('Cache-Control', 'public,max-age=31536000,immutable') + const filePath = path.join(staticServeConfig.distAssets, subpath) + + try { + const file = await Deno.readFile(filePath) + const headers: Record = {} + + // In the build config we told our bundler to use the `[name]-[hash]-cached` template + // to name immutable assets. This is useful because `dist/assets/` currently includes + // a few files without hash in their name. + if (basename.includes('-cached')) { + headers['ETag'] = `"${basename}"` + headers['Cache-Control'] = 'public,max-age=31536000,immutable' + } + + // since our JS is placed under /assets/ and since service workers + // have their scope limited by where they are, we must add this + // header to allow the service worker to function. Details: + // https://w3c.github.io/ServiceWorker/#service-worker-allowed + if (subpath.includes('js/sw-')) { + console.debug('adding header: Service-Worker-Allowed /') + headers['Service-Worker-Allowed'] = '/' + } + + const ext = path.extname(subpath).toLowerCase() + const mimeTypes: Record = { + '.js': 'application/javascript', + '.mjs': 'application/javascript', + '.css': 'text/css', + '.html': 'text/html', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.ttf': 'font/ttf', + '.otf': 'font/otf', + '.webp': 'image/webp', + '.mp4': 'video/mp4', + '.webm': 'video/webm', + '.map': 'application/json' + } + const contentType = mimeTypes[ext] || 'application/octet-stream' + headers['Content-Type'] = contentType + + return c.body(file, 200, headers) + } catch { + return notFoundNoCache(c) } - // Files like `main.js` or `main.css` should be revalidated before use. Se we use the default headers. - // This should also be suitable for serving unversioned fonts and images. - return h.file(subpath) }) // Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) if (isCheloniaDashboard) { - route.GET('/dashboard/assets/{subpath*}', { - ext: { - onPostHandler: { - method (request, h) { - // since our JS is placed under /assets/ and since service workers - // have their scope limited by where they are, we must add this - // header to allow the service worker to function. Details: - // https://w3c.github.io/ServiceWorker/#service-worker-allowed - if (request.path.includes('assets/js/sw-')) { - // If `response` is an error, then no SW is being served - if (!(request.response instanceof Boom.Boom)) { - console.debug('adding header: Service-Worker-Allowed /') - request.response.header('Service-Worker-Allowed', '/') - } - } - return h.continue - } - } - }, - files: { - relativeTo: staticServeConfig.distAssets - } - }, function (request, h) { - const { subpath } = request.params + app.get('/dashboard/assets/:subpath{.+}', async function (c) { + const subpath = c.req.param('subpath') const basename = path.basename(subpath) - // In the build config we told our bundler to use the `[name]-[hash]-cached` template - // to name immutable assets. This is useful because `dist/assets/` currently includes - // a few files without hash in their name. - if (basename.includes('-cached')) { - return h.file(subpath, { etagMethod: false }) - .etag(basename) - .header('Cache-Control', 'public,max-age=31536000,immutable') + const filePath = path.join(staticServeConfig.distAssets, subpath) + + try { + const file = await Deno.readFile(filePath) + const headers: Record = {} + + if (basename.includes('-cached')) { + headers['ETag'] = `"${basename}"` + headers['Cache-Control'] = 'public,max-age=31536000,immutable' + } + + if (subpath.includes('js/sw-')) { + console.debug('adding header: Service-Worker-Allowed /') + headers['Service-Worker-Allowed'] = '/' + } + + const ext = path.extname(subpath).toLowerCase() + const mimeTypes: Record = { + '.js': 'application/javascript', + '.mjs': 'application/javascript', + '.css': 'text/css', + '.html': 'text/html', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.ttf': 'font/ttf', + '.otf': 'font/otf', + '.webp': 'image/webp', + '.mp4': 'video/mp4', + '.webm': 'video/webm', + '.map': 'application/json' + } + const contentType = mimeTypes[ext] || 'application/octet-stream' + headers['Content-Type'] = contentType + + return c.body(file, 200, headers) + } catch { + return notFoundNoCache(c) } - // Files like `main.js` or `main.css` should be revalidated before use. Se we use the default headers. - // This should also be suitable for serving unversioned fonts and images. - return h.file(subpath) }) } -route.GET(staticServeConfig.routePath, {}, { - file: staticServeConfig.distIndexHtml +// SPA catch-all route +app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', async function (c) { + try { + const file = await Deno.readFile(staticServeConfig.distIndexHtml) + return c.body(file, 200, { 'Content-Type': 'text/html' }) + } catch { + return notFoundNoCache(c) + } }) -route.GET('/', {}, function (_req, h) { - return h.redirect(staticServeConfig.redirect) +app.get('/', function (c) { + return c.redirect(staticServeConfig.redirect) }) -route.POST('/zkpp/register/{name}', { - validate: { - params: Joi.object({ - name: Joi.string().regex(NAME_REGEX).required() - }), - payload: Joi.alternatives([ - { - // b is a hash of a random public key (`g^r`) with secret key `r`, - // which is used by the requester to commit to that particular `r` - b: Joi.string().required() - }, - { - // `r` is the value used to derive `b` (in this case, it's the public - // key `g^r`) - r: Joi.string().required(), - // `s` is an opaque (to the client) value that was earlier returned by - // the server - s: Joi.string().required(), - // `sig` is an opaque (to the client) value returned by the server - // to validate the request (ensuring that (`r`, `s`) come from a - // previous request - sig: Joi.string().required(), - // `Eh` is the Eh = E_{S_A + S_C}(h), where S_A and S_C are salts and - // h = H\_{S_A}(P) - Eh: Joi.string().required() - } - ]) - } -}, async function (req) { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') - const lookupResult = await sbp('backend/db/lookupName', req.params['name']) +app.post('/zkpp/register/:name', async function (c) { + const name = c.req.param('name') + if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: 'Invalid name' }) + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const lookupResult = await sbp('backend/db/lookupName', name) if (lookupResult) { // If the username is already registered, abort - return Boom.conflict() + throw new HTTPException(409) } try { - const { payload } = req as { payload: { b: string, r: string, s: string, sig: string, Eh: string } } - if (payload['b']) { - const result = registrationKey(req.params['name'], payload['b']) + const payload = await c.req.json() as { b?: string, r?: string, s?: string, sig?: string, Eh?: string } + // Validate: must be either { b } or { r, s, sig, Eh } + if (payload.b) { + if (typeof payload.b !== 'string') throw new HTTPException(400) + const result = registrationKey(name, payload.b) if (result) { - return result + return c.json(result) } - } else { - const result = register(req.params['name'], payload['r'], payload['s'], payload['sig'], payload['Eh']) + } else if (payload.r && payload.s && payload.sig && payload.Eh) { + if (typeof payload.r !== 'string' || typeof payload.s !== 'string' || + typeof payload.sig !== 'string' || typeof payload.Eh !== 'string') { + throw new HTTPException(400) + } + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) if (result) { - return result + return c.json(result) } + } else { + throw new HTTPException(400, { message: 'Invalid payload' }) } } catch (e) { - (e as { ip: string }).ip = req.headers['x-real-ip'] || req.info.remoteAddress + if (e instanceof HTTPException) throw e + ;(e as { ip: string }).ip = getClientIP(c) console.error(e, 'Error at POST /zkpp/{name}: ' + (e as Error).message) } - return Boom.internal('internal error') + throw new HTTPException(500, { message: 'internal error' }) }) -route.GET('/zkpp/{contractID}/auth_hash', { - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required() - }), - query: Joi.object({ b: Joi.string().required() }) - } -}, async function (req, h) { +app.get('/zkpp/:contractID/auth_hash', async function (c) { + const contractID = c.req.param('contractID') + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + const b = c.req.query('b') + if (!b) throw new HTTPException(400, { message: 'b is required' }) try { - const challenge = await getChallenge(req.params['contractID'], req.query['b']) + const challenge = await getChallenge(contractID, b) - return challenge || notFoundNoCache(h) + return challenge ? c.json(challenge) : notFoundNoCache(c) } catch (e) { - (e as unknown as { ip: string }).ip = req.headers['x-real-ip'] || req.info.remoteAddress + ;(e as unknown as { ip: string }).ip = getClientIP(c) console.error(e, 'Error at GET /zkpp/{contractID}/auth_hash: ' + (e as Error).message) } - return Boom.internal('internal error') + throw new HTTPException(500, { message: 'internal error' }) }) -route.GET('/zkpp/{contractID}/contract_hash', { - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required() - }), - query: Joi.object({ - r: Joi.string().required(), - s: Joi.string().required(), - sig: Joi.string().required(), - hc: Joi.string().required() - }) - } -}, async function (req) { +app.get('/zkpp/:contractID/contract_hash', async function (c) { + const contractID = c.req.param('contractID') + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + const r = c.req.query('r') + const s = c.req.query('s') + const sig = c.req.query('sig') + const hc = c.req.query('hc') + if (!r || !s || !sig || !hc) throw new HTTPException(400, { message: 'r, s, sig, and hc are required' }) try { - const salt = await getContractSalt(req.params['contractID'], req.query['r'], req.query['s'], req.query['sig'], req.query['hc']) + const salt = await getContractSalt(contractID, r, s, sig, hc) if (salt) { - return salt + return c.json(salt) } } catch (e) { - (e as { ip: string }).ip = req.headers['x-real-ip'] || req.info.remoteAddress + ;(e as { ip: string }).ip = getClientIP(c) console.error(e, 'Error at GET /zkpp/{contractID}/contract_hash: ' + (e as Error).message) } - return Boom.internal('internal error') + throw new HTTPException(500, { message: 'internal error' }) }) -route.POST('/zkpp/{contractID}/updatePasswordHash', { - validate: { - params: Joi.object({ - contractID: Joi.string().regex(CID_REGEX).required() - }), - payload: Joi.object({ - r: Joi.string().required(), - s: Joi.string().required(), - sig: Joi.string().required(), - hc: Joi.string().required(), - Ea: Joi.string().required() - }) - } -}, async function (req) { - if (ARCHIVE_MODE) return Boom.notImplemented('Server in archive mode') +app.post('/zkpp/:contractID/updatePasswordHash', async function (c) { + const contractID = c.req.param('contractID') + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { - const { payload } = req as { payload: { r: string, s: string, sig: string, hc: string, Ea: string } } - const result = await updateContractSalt(req.params['contractID'], payload['r'], payload['s'], payload['sig'], payload['hc'], payload['Ea']) + const payload = await c.req.json() as { r: string, s: string, sig: string, hc: string, Ea: string } + if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { + throw new HTTPException(400, { message: 'r, s, sig, hc, and Ea are required' }) + } + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) if (result) { - return result + return c.json(result) } } catch (e) { - (e as unknown as { ip: string }).ip = req.headers['x-real-ip'] || req.info.remoteAddress + if (e instanceof HTTPException) throw e + ;(e as unknown as { ip: string }).ip = getClientIP(c) console.error(e, 'Error at POST /zkpp/{contractID}/updatePasswordHash: ' + (e as Error).message) } - return Boom.internal('internal error') + throw new HTTPException(500, { message: 'internal error' }) }) diff --git a/src/serve/server.ts b/src/serve/server.ts index ae5b29e..1a950f9 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -5,16 +5,15 @@ import 'npm:@chelonia/lib/chelonia' import { multicodes, parseCID } from 'npm:@chelonia/lib/functions' import 'npm:@chelonia/lib/persistent-actions' import { SERVER } from 'npm:@chelonia/lib/presets' -import Boom from 'npm:@hapi/boom' -import * as Hapi from 'npm:@hapi/hapi' -import Inert from 'npm:@hapi/inert' import sbp from 'npm:@sbp/sbp' import chalk from 'npm:chalk' +import { Hono } from 'npm:hono' +import { cors } from 'npm:hono/cors' +import { createAdaptorServer } from 'npm:@hono/node-server' +import type { Server } from 'node:http' import createWorker from './createWorker.ts' -// import type { SubMessage, UnsubMessage } from './pubsub.ts' // TODO: Use for type checking import { join } from 'node:path' import process from 'node:process' -import authPlugin from './auth.ts' import { CREDITS_WORKER_TASK_TIME_INTERVAL, OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL } from './constants.ts' import { KEYOP_SEGMENT_LENGTH, appendToIndexFactory, initDB, lookupUltimateOwner, removeFromIndexFactory, updateSize } from './database.ts' import { BackendErrorBadData, BackendErrorGone, BackendErrorNotFound } from './errors.ts' @@ -60,50 +59,33 @@ const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? undefined : createWorker(join(import.meta.dirname || '.', import.meta.workerDir || '.', 'creditsWorker.js')) -// Dynamic runtime import to bypass bundling issues with npm: specifier -const hapi = new Hapi.Server({ - // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements - // // v17 doesn't seem to do this anymore so I've re-enabled the logging - // debug: { log: ['error'], request: ['error'] }, - host: nconf.get('server:host'), - port: nconf.get('server:port'), - // See: https://github.com/hapijs/discuss/issues/262#issuecomment-204616831 - routes: { - cors: { - // TODO: figure out if we can live with '*' or if we need to restrict it - origin: ['*'] - // origin: [ - // process.env.API_URL, - // // improve support for browsersync proxy - // ...(process.env.NODE_ENV === 'development' && ['http://localhost:3000']) - // ] - } - } -}) +// Create Hono app +export const app = new Hono() -// See https://stackoverflow.com/questions/26213255/hapi-set-header-before-sending-response -hapi.ext({ - type: 'onPreResponse', - method: function (request, h) { - try { - // Hapi Boom error responses don't have `.header()`, - // but custom headers can be manually added using `.output.headers`. - // See https://hapi.dev/module/boom/api/. - if (!(request.response instanceof Boom.Boom)) { - request.response.header('X-Frame-Options', 'DENY') - } else { - request.response.output.headers['X-Frame-Options'] = 'DENY' - } - } catch (err) { - console.warn(chalk.yellow('[backend] Could not set X-Frame-Options header:', (err as Error).message)) - } - return h.continue - } +// Global middleware: CORS +app.use('*', cors({ origin: '*' })) + +// Global middleware: X-Frame-Options on every response +app.use('*', async (c, next) => { + await next() + c.header('X-Frame-Options', 'DENY') }) +// Dev logging middleware +if (process.env.NODE_ENV === 'development' && !process.env.CI) { + app.use('*', async (c, next) => { + await next() + const ip = c.req.header('x-real-ip') || 'unknown' + console.debug(chalk`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`) + }) +} + +// Create the Node http.Server (without listening yet) via @hono/node-server +const httpServer = createAdaptorServer({ fetch: app.fetch }) as Server + const appendToOrphanedNamesIndex = appendToIndexFactory('_private_orphaned_names_index') -sbp('okTurtles.data/set', SERVER_INSTANCE, hapi) +sbp('okTurtles.data/set', SERVER_INSTANCE, app) sbp('sbp/selectors/register', { 'backend/server/persistState': async function (deserializedHEAD: unknown) { @@ -256,7 +238,12 @@ sbp('sbp/selectors/register', { return updateSize(resourceID, sizeKey, size, true) }, 'backend/server/stop': function () { - return hapi.stop() + return new Promise((resolve, reject) => { + httpServer.close((err) => { + if (err) reject(err) + else resolve() + }) + }) }, async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { const owner = await sbp('chelonia.db/get', `_private_owner_${cid}`) @@ -423,15 +410,7 @@ sbp('sbp/selectors/register', { } }) -if (process.env.NODE_ENV === 'development' && !process.env.CI) { - hapi.events.on('response', (req) => { - const ip = req.headers['x-real-ip'] || req.info.remoteAddress - const statusCode = req.response instanceof Boom.Boom ? req.response.output.statusCode : req.response.statusCode - console.debug(chalk`{grey ${ip}: ${req.method} ${req.path} --> ${statusCode}}`) - }) -} - -sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { +sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { serverHandlers: { connection (socket) { const versionInfo = { @@ -574,22 +553,15 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { sbp('chelonia.persistentActions/load').catch((e: unknown) => { console.error(e, 'Error loading persistent actions') }) - // https://hapi.dev/tutorials/plugins - await hapi.register([ - { plugin: authPlugin }, - { plugin: Inert } - // { - // plugin: require('hapi-pino'), - // options: { - // instance: logger - // } - // } - ]) - // Import routes after plugins are registered + // Import routes (they will register themselves on the Hono app via SERVER_INSTANCE) await import('./routes.ts') - await hapi.start() - console.info('Backend server running at:', hapi.info.uri) - sbp('okTurtles.events/emit', SERVER_RUNNING, hapi) + // Start listening + const host = nconf.get('server:host') || '0.0.0.0' + const port = nconf.get('server:port') || 8000 + httpServer.listen(port, host, () => { + console.info(`Backend server running at: http://${host}:${port}`) + sbp('okTurtles.events/emit', SERVER_RUNNING, app) + }) })() // Recurring task to send messages to push clients (for periodic notifications) From 49829465c14bb982169d4b569bc19cf05bdec609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 19:23:56 -0400 Subject: [PATCH 05/71] Add endpoint tests --- deno.json | 2 +- src/serve/routes-kv.test.ts | 223 +++++++++++++ src/serve/routes-reads.test.ts | 264 +++++++++++++++ src/serve/routes-stateless.test.ts | 136 ++++++++ src/serve/routes-test-helpers.ts | 158 +++++++++ src/serve/routes-writes.test.ts | 500 +++++++++++++++++++++++++++++ src/serve/routes-zkpp.test.ts | 194 +++++++++++ 7 files changed, 1476 insertions(+), 1 deletion(-) create mode 100644 src/serve/routes-kv.test.ts create mode 100644 src/serve/routes-reads.test.ts create mode 100644 src/serve/routes-stateless.test.ts create mode 100644 src/serve/routes-test-helpers.ts create mode 100644 src/serve/routes-writes.test.ts create mode 100644 src/serve/routes-zkpp.test.ts diff --git a/deno.json b/deno.json index f695c5c..9c6defb 100644 --- a/deno.json +++ b/deno.json @@ -5,7 +5,7 @@ "compile": "deno run --allow-env --allow-ffi --allow-sys='hostname' --allow-run --allow-read --allow-write=./dist scripts/compile.ts", "build": "deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir' scripts/dashboard-esbuild.ts && deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir,hostname' scripts/build.ts", "dist": "deno task lint && deno task build && deno task compile", - "test": "deno task lint && deno test --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" + "test": "deno task lint && deno test --no-check --sloppy-imports --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" }, "imports": { "@db/sqlite": "jsr:@db/sqlite@0.13.0", diff --git a/src/serve/routes-kv.test.ts b/src/serve/routes-kv.test.ts new file mode 100644 index 0000000..2f09f75 --- /dev/null +++ b/src/serve/routes-kv.test.ts @@ -0,0 +1,223 @@ +import 'jsr:@db/sqlite' +import { + buildShelterAuthHeader, + buildSignedKvPayload, + createCID, + createTestIdentity, + multicodes, + sbp, + startTestServer, + stopTestServer +} from './routes-test-helpers.ts' + +Deno.test({ + name: 'routes: KV store endpoints', + sanitizeResources: false, + sanitizeOps: false, + async fn (t: Deno.TestContext) { + const baseURL = await startTestServer() + + try { + const owner = createTestIdentity() + + await t.step('setup: register billable entity for owner', async () => { + await sbp('chelonia.db/set', owner.contractID, 'identity-contract-data') + await sbp('chelonia.db/set', `head=${owner.contractID}`, JSON.stringify({ + HEAD: createCID('owner-head', multicodes.SHELTER_CONTRACT_DATA), + previousKeyOp: null, + height: 0 + })) + }) + + await t.step('POST /kv without auth returns 401', async () => { + const cid = createCID('kv-contract', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/kv/${cid}/mykey`, { + method: 'POST', + headers: { 'content-type': 'application/octet-stream', 'if-match': '*' }, + body: 'test' + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /kv with auth but mismatched contractID returns 401', async () => { + const other = createTestIdentity() + const otherAuth = buildShelterAuthHeader(other.contractID, other.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/mykey`, { + method: 'POST', + headers: { + authorization: otherAuth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: 'test' + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /kv without If-Match header returns 400', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/mykey`, { + method: 'POST', + headers: { authorization: auth, 'content-type': 'application/octet-stream' }, + body: 'test' + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /kv with invalid key (_private prefix) returns 400', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/_private_secret`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: 'test' + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /kv with wrong CID type returns 400', async () => { + const fileCID = createCID('not-contract', multicodes.SHELTER_FILE_MANIFEST) + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${fileCID}/mykey`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: 'test' + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /kv with valid signed payload stores value and returns 204', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const payload = buildSignedKvPayload(owner.contractID, 'testkey', 0, { hello: 'world' }, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: payload + }) + await res.body?.cancel() + if (res.status !== 204) throw new Error(`Expected 204 but got ${res.status}`) + }) + + await t.step('GET /kv without auth returns 401', async () => { + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('GET /kv with valid auth returns stored value with ETag', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + headers: { authorization: auth } + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + if (!body) throw new Error('Expected non-empty body') + const etag = res.headers.get('etag') + if (!etag) throw new Error('Expected ETag header') + const xcid = res.headers.get('x-cid') + if (!xcid) throw new Error('Expected x-cid header') + }) + + await t.step('GET /kv with valid auth for nonexistent key returns 404', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/nonexistent`, { + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('POST /kv with mismatched ETag returns 412 with current value', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const payload = buildSignedKvPayload(owner.contractID, 'testkey', 0, { updated: true }, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '"wrong-etag"' + }, + body: payload + }) + if (res.status !== 412) throw new Error(`Expected 412 but got ${res.status}`) + const body = await res.text() + if (!body) throw new Error('Expected response body with current value') + const xcid = res.headers.get('x-cid') + if (!xcid) throw new Error('Expected x-cid header on 412') + }) + + await t.step('POST /kv with matching ETag updates value', async () => { + const auth1 = buildShelterAuthHeader(owner.contractID, owner.SAK) + const getRes = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + headers: { authorization: auth1 } + }) + const xcid = getRes.headers.get('x-cid') + await getRes.body?.cancel() + if (!xcid) throw new Error('Expected x-cid from GET') + + const auth2 = buildShelterAuthHeader(owner.contractID, owner.SAK) + const payload = buildSignedKvPayload(owner.contractID, 'testkey', 0, { updated: true }, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + method: 'POST', + headers: { + authorization: auth2, + 'content-type': 'application/octet-stream', + 'if-match': xcid + }, + body: payload + }) + await res.body?.cancel() + if (res.status !== 204) throw new Error(`Expected 204 but got ${res.status}`) + }) + + await t.step('POST /kv with wrong height returns 409', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const payload = buildSignedKvPayload(owner.contractID, 'testkey', 999, { bad: true }, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: payload + }) + if (res.status !== 409) throw new Error(`Expected 409 but got ${res.status}`) + await res.body?.cancel() + }) + + await t.step('POST /kv with invalid payload returns 422', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { + method: 'POST', + headers: { + authorization: auth, + 'content-type': 'application/octet-stream', + 'if-match': '*' + }, + body: 'not-valid-json' + }) + await res.body?.cancel() + if (res.status !== 422) throw new Error(`Expected 422 but got ${res.status}`) + }) + } finally { + await stopTestServer() + } + } +}) diff --git a/src/serve/routes-reads.test.ts b/src/serve/routes-reads.test.ts new file mode 100644 index 0000000..6312a02 --- /dev/null +++ b/src/serve/routes-reads.test.ts @@ -0,0 +1,264 @@ +import 'jsr:@db/sqlite' +import { + createCID, + multicodes, + sbp, + startTestServer, + stopTestServer +} from './routes-test-helpers.ts' + +Deno.test({ + name: 'routes: state-dependent reads', + sanitizeResources: false, + sanitizeOps: false, + async fn (t: Deno.TestContext) { + const baseURL = await startTestServer() + + try { + const testContractData = 'test-contract-data-content' + const testContractID = createCID(testContractData, multicodes.SHELTER_CONTRACT_DATA) + const testFileContent = '{"version":"1.0.0","cipher":"aes256gcm","chunks":[]}' + const testFileManifestHash = createCID(testFileContent, multicodes.SHELTER_FILE_MANIFEST) + const testChunkContent = 'binary-chunk-data' + const testChunkHash = createCID(testChunkContent, multicodes.SHELTER_FILE_CHUNK) + const testEntryContent = JSON.stringify({ + head: JSON.stringify({ + version: '1.0.0', + previousHEAD: null, + contractID: testContractID, + op: 'c', + manifest: testContractID, + height: 0 + }), + signedMessageData: 'test-signed-data' + }) + const testEntryHash = createCID(testEntryContent, multicodes.SHELTER_CONTRACT_DATA) + + await t.step('setup: seed DB with test data', async () => { + await sbp('backend/db/registerName', 'testuser', testContractID) + await sbp('chelonia.db/set', testContractID, testContractData) + await sbp('chelonia.db/set', testFileManifestHash, testFileContent) + await sbp('chelonia.db/set', testChunkHash, testChunkContent) + await sbp('chelonia.db/set', `head=${testContractID}`, JSON.stringify({ + HEAD: testEntryHash, + previousKeyOp: null, + height: 0 + })) + await sbp('chelonia.db/set', testEntryHash, testEntryContent) + await sbp('chelonia.db/set', `_private_hidx=${testContractID}#0`, JSON.stringify({ + hash: testEntryHash, + date: new Date().toISOString() + })) + }) + + await t.step('GET /name/{name} returns contract ID for registered name', async () => { + const res = await fetch(`${baseURL}/name/testuser`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + if (body !== testContractID) { + throw new Error(`Expected ${testContractID} but got ${body}`) + } + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('text/plain')) { + throw new Error(`Expected text/plain but got ${contentType}`) + } + }) + + await t.step('GET /latestHEADinfo with non-CID param returns 400', async () => { + const res = await fetch(`${baseURL}/latestHEADinfo/not-a-valid-cid`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /latestHEADinfo with wrong CID type returns 400', async () => { + const wrongTypeCID = createCID('test', multicodes.SHELTER_FILE_MANIFEST) + const res = await fetch(`${baseURL}/latestHEADinfo/${wrongTypeCID}`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /latestHEADinfo with unknown contractID returns 404', async () => { + const unknownCID = createCID('unknown-contract', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/latestHEADinfo/${unknownCID}`) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('GET /latestHEADinfo returns HEADinfo for known contract', async () => { + const res = await fetch(`${baseURL}/latestHEADinfo/${testContractID}`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (body.HEAD !== testEntryHash) { + throw new Error(`Expected HEAD ${testEntryHash} but got ${body.HEAD}`) + } + if (body.height !== 0) { + throw new Error(`Expected height 0 but got ${body.height}`) + } + }) + + await t.step('GET /latestHEADinfo has Cache-Control: no-store', async () => { + const res = await fetch(`${baseURL}/latestHEADinfo/${testContractID}`) + await res.body?.cancel() + const cacheControl = res.headers.get('cache-control') + if (!cacheControl || !cacheControl.includes('no-store')) { + throw new Error(`Expected Cache-Control no-store but got ${cacheControl}`) + } + }) + + await t.step('GET /latestHEADinfo returns 410 for deleted contract', async () => { + const deletedContractData = 'deleted-contract-data' + const deletedContractID = createCID(deletedContractData, multicodes.SHELTER_CONTRACT_DATA) + await sbp('chelonia.db/set', `head=${deletedContractID}`, '') + const res = await fetch(`${baseURL}/latestHEADinfo/${deletedContractID}`) + await res.body?.cancel() + if (res.status !== 410) throw new Error(`Expected 410 but got ${res.status}`) + }) + + await t.step('GET /file/{hash} with unknown hash returns 404', async () => { + const unknownHash = createCID('nonexistent-file', multicodes.SHELTER_FILE_MANIFEST) + const res = await fetch(`${baseURL}/file/${unknownHash}`) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('GET /file/{hash} with invalid CID returns 400', async () => { + const res = await fetch(`${baseURL}/file/not-a-valid-cid`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /file/{hash} returns file manifest with correct content-type', async () => { + const res = await fetch(`${baseURL}/file/${testFileManifestHash}`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + if (body !== testFileContent) { + throw new Error(`Expected file content but got ${body}`) + } + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('application/vnd.shelter.filemanifest+json')) { + throw new Error(`Expected filemanifest content-type but got ${contentType}`) + } + }) + + await t.step('GET /file/{hash} returns chunk with correct content-type', async () => { + const res = await fetch(`${baseURL}/file/${testChunkHash}`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + if (body !== testChunkContent) { + throw new Error(`Expected chunk content but got ${body}`) + } + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('application/vnd.shelter.filechunk+octet-stream')) { + throw new Error(`Expected filechunk content-type but got ${contentType}`) + } + }) + + await t.step('GET /file/{hash} has immutable Cache-Control and ETag', async () => { + const res = await fetch(`${baseURL}/file/${testFileManifestHash}`) + await res.body?.cancel() + const cacheControl = res.headers.get('cache-control') + if (!cacheControl || !cacheControl.includes('immutable')) { + throw new Error(`Expected immutable Cache-Control but got ${cacheControl}`) + } + const etag = res.headers.get('etag') + if (!etag) { + throw new Error('Expected ETag header but none found') + } + }) + + await t.step('GET /file/{hash} has CSP and nosniff headers', async () => { + const res = await fetch(`${baseURL}/file/${testFileManifestHash}`) + await res.body?.cancel() + const csp = res.headers.get('content-security-policy') + if (!csp || !csp.includes('default-src \'none\'')) { + throw new Error(`Expected restrictive CSP but got ${csp}`) + } + const nosniff = res.headers.get('x-content-type-options') + if (nosniff !== 'nosniff') { + throw new Error(`Expected nosniff but got ${nosniff}`) + } + }) + + await t.step('GET /file/{hash} returns 410 for deleted file', async () => { + const deletedFileData = 'deleted-file-data' + const deletedFileHash = createCID(deletedFileData, multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', deletedFileHash, '') + const res = await fetch(`${baseURL}/file/${deletedFileHash}`) + await res.body?.cancel() + if (res.status !== 410) throw new Error(`Expected 410 but got ${res.status}`) + }) + + await t.step('GET /file/{hash} returns contract data content-type', async () => { + const res = await fetch(`${baseURL}/file/${testContractID}`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('application/vnd.shelter.contractdata+json')) { + throw new Error(`Expected contractdata content-type but got ${contentType}`) + } + await res.body?.cancel() + }) + + await t.step('GET /eventsAfter with invalid contractID returns 400', async () => { + const res = await fetch(`${baseURL}/eventsAfter/not-a-cid/0`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /eventsAfter with wrong CID type returns 400', async () => { + const wrongTypeCID = createCID('test', multicodes.SHELTER_FILE_MANIFEST) + const res = await fetch(`${baseURL}/eventsAfter/${wrongTypeCID}/0`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /eventsAfter with unknown contractID returns 404', async () => { + const unknownCID = createCID('unknown-events', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/eventsAfter/${unknownCID}/0`) + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + await res.body?.cancel() + }) + + await t.step('GET /eventsAfter returns JSON array with HEADinfo headers for known contract', async () => { + const res = await fetch(`${baseURL}/eventsAfter/${testContractID}/0`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + const parsed = JSON.parse(body) + if (!Array.isArray(parsed)) throw new Error('Expected JSON array response') + const headinfoHead = res.headers.get('shelter-headinfo-head') + if (headinfoHead !== testEntryHash) { + throw new Error(`Expected shelter-headinfo-head ${testEntryHash} but got ${headinfoHead}`) + } + const headinfoHeight = res.headers.get('shelter-headinfo-height') + if (headinfoHeight !== '0') { + throw new Error(`Expected shelter-headinfo-height 0 but got ${headinfoHeight}`) + } + }) + + await t.step('GET /eventsAfter with height beyond contract returns empty array', async () => { + const res = await fetch(`${baseURL}/eventsAfter/${testContractID}/999`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + const parsed = JSON.parse(body) + if (!Array.isArray(parsed)) throw new Error('Expected JSON array response') + if (parsed.length !== 0) throw new Error(`Expected 0 entries but got ${parsed.length}`) + }) + + await t.step('GET /eventsAfter with invalid since param returns 400', async () => { + const res = await fetch(`${baseURL}/eventsAfter/${testContractID}/not-a-number`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /eventsAfter returns 410 for deleted contract', async () => { + const deletedData = 'deleted-events-contract' + const deletedCID = createCID(deletedData, multicodes.SHELTER_CONTRACT_DATA) + await sbp('chelonia.db/set', `head=${deletedCID}`, '') + const res = await fetch(`${baseURL}/eventsAfter/${deletedCID}/0`) + if (res.status !== 410) throw new Error(`Expected 410 but got ${res.status}`) + await res.body?.cancel() + }) + } finally { + await stopTestServer() + } + } +}) diff --git a/src/serve/routes-stateless.test.ts b/src/serve/routes-stateless.test.ts new file mode 100644 index 0000000..e52f048 --- /dev/null +++ b/src/serve/routes-stateless.test.ts @@ -0,0 +1,136 @@ +import 'jsr:@db/sqlite' +import { startTestServer, stopTestServer } from './routes-test-helpers.ts' + +Deno.test({ + name: 'routes: stateless endpoints', + sanitizeResources: false, + sanitizeOps: false, + async fn (t: Deno.TestContext) { + const baseURL = await startTestServer() + + try { + await t.step('GET /time returns ISO timestamp', async () => { + const res = await fetch(`${baseURL}/time`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.text() + const parsed = new Date(body) + if (isNaN(parsed.getTime())) throw new Error(`Response is not a valid ISO date: ${body}`) + const contentType = res.headers.get('content-type') + if (!contentType || !contentType.includes('text/plain')) { + throw new Error(`Expected text/plain content-type but got ${contentType}`) + } + }) + + await t.step('GET /time has Cache-Control: no-store', async () => { + const res = await fetch(`${baseURL}/time`) + await res.body?.cancel() + const cacheControl = res.headers.get('cache-control') + if (!cacheControl || !cacheControl.includes('no-store')) { + throw new Error(`Expected Cache-Control no-store but got ${cacheControl}`) + } + }) + + await t.step('GET /time has X-Frame-Options: DENY', async () => { + const res = await fetch(`${baseURL}/time`) + await res.body?.cancel() + const xfo = res.headers.get('x-frame-options') + if (xfo !== 'DENY') { + throw new Error(`Expected X-Frame-Options DENY but got ${xfo}`) + } + }) + + await t.step('GET /serverMessages returns configured messages', async () => { + const res = await fetch(`${baseURL}/serverMessages`) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!Array.isArray(body)) throw new Error('Expected array response') + if (body.length !== 1) throw new Error(`Expected 1 message but got ${body.length}`) + if (body[0].type !== 'info') throw new Error(`Expected type 'info' but got ${body[0].type}`) + if (body[0].text !== 'test message') throw new Error(`Expected text 'test message' but got ${body[0].text}`) + }) + + await t.step('GET /serverMessages has Cache-Control: no-store', async () => { + const res = await fetch(`${baseURL}/serverMessages`) + await res.body?.cancel() + const cacheControl = res.headers.get('cache-control') + if (!cacheControl || !cacheControl.includes('no-store')) { + throw new Error(`Expected Cache-Control no-store but got ${cacheControl}`) + } + }) + + await t.step('POST /streams-test with "ok" returns 204', async () => { + const res = await fetch(`${baseURL}/streams-test`, { + method: 'POST', + body: 'ok', + headers: { 'content-type': 'application/octet-stream' } + }) + await res.body?.cancel() + if (res.status !== 204) throw new Error(`Expected 204 but got ${res.status}`) + }) + + await t.step('POST /streams-test with wrong body returns 400', async () => { + const res = await fetch(`${baseURL}/streams-test`, { + method: 'POST', + body: 'wrong', + headers: { 'content-type': 'application/octet-stream' } + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /streams-test with empty body returns 400', async () => { + const res = await fetch(`${baseURL}/streams-test`, { + method: 'POST', + body: '', + headers: { 'content-type': 'application/octet-stream' } + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /log with valid payload returns 200', async () => { + const res = await fetch(`${baseURL}/log`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ level: 'info', value: 'test log message' }) + }) + await res.body?.cancel() + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + }) + + await t.step('POST /log with missing level returns 400', async () => { + const res = await fetch(`${baseURL}/log`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ value: 'test log message' }) + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /log with missing value returns 400', async () => { + const res = await fetch(`${baseURL}/log`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ level: 'info' }) + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /name with invalid name format returns 400', async () => { + const res = await fetch(`${baseURL}/name/INVALID_NAME!!`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /name with valid but unregistered name returns 404', async () => { + const res = await fetch(`${baseURL}/name/nonexistentuser`) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + } finally { + await stopTestServer() + } + } +}) diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts new file mode 100644 index 0000000..fea77c7 --- /dev/null +++ b/src/serve/routes-test-helpers.ts @@ -0,0 +1,158 @@ +import { Buffer } from 'node:buffer' +import process from 'node:process' +// @deno-types="npm:@types/nconf" +import nconf from 'npm:nconf' +import sbp from 'npm:@sbp/sbp' +import 'npm:@sbp/okturtles.data' +import 'npm:@sbp/okturtles.events' +import 'npm:@sbp/okturtles.eventqueue' +import { blake32Hash, createCID, multicodes } from 'npm:@chelonia/lib/functions' +import { EDWARDS25519SHA512BATCH, keygen, keyId, serializeKey, sign } from 'npm:@chelonia/crypto' +import { AUTHSALT, CONTRACTSALT, CS, SALT_LENGTH_IN_OCTETS } from 'npm:@chelonia/lib/zkppConstants' +import tweetnacl from 'npm:tweetnacl' +import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' + +export { blake32Hash, createCID, multicodes } from 'npm:@chelonia/lib/functions' +export { EDWARDS25519SHA512BATCH, keygen, keyId, serializeKey, sign } from 'npm:@chelonia/crypto' +export { default as sbp } from 'npm:@sbp/sbp' + +export const nacl = tweetnacl + +const TEST_PORT = 0 + +export function buildSignedKvPayload ( + contractID: string, + key: string, + height: number, + data: unknown, + SAK: ReturnType +) { + const SAKid = keyId(SAK) + const heightStr = String(height) + const serializedMessage = JSON.stringify(data) + const additionalData = key + heightStr + const sig = sign(SAK, blake32Hash(blake32Hash(additionalData) + blake32Hash(serializedMessage))) + return JSON.stringify({ + height: heightStr, + _signedData: [serializedMessage, SAKid, sig] + }) +} + +export function saltsAndEncryptedHashedPassword (p: string, secretKey: Uint8Array, hash: string) { + const nonce = nacl.randomBytes(nacl.secretbox.nonceLength) + const dhKey = nacl.hash(nacl.box.before(Buffer.from(p, 'base64url'), secretKey)) + const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const encryptionKey = nacl.hash(Buffer.from(authSalt + contractSalt)).slice(0, nacl.secretbox.keyLength) + const encryptedHashedPassword = Buffer.concat([nonce, nacl.secretbox(Buffer.from(hash), nonce, encryptionKey)]).toString('base64url') + return [authSalt, contractSalt, encryptedHashedPassword] +} + +export function decryptRegistrationRedemptionToken (p: string, secretKey: Uint8Array, encryptedToken: string) { + const dhKey = nacl.hash(nacl.box.before(Buffer.from(p, 'base64url'), secretKey)) + const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), nacl.hash(Buffer.from(authSalt + contractSalt)).slice(0, nacl.secretbox.keyLength)])).slice(0, nacl.secretbox.keyLength) + const encryptedTokenBuf = Buffer.from(encryptedToken, 'base64url') + const nonce = encryptedTokenBuf.slice(0, nacl.secretbox.nonceLength) + const ciphertext = encryptedTokenBuf.slice(nacl.secretbox.nonceLength) + const decrypted = nacl.secretbox.open(ciphertext, nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt token') + return Buffer.from(decrypted).toString() +} + +export function createTestIdentity () { + const SAK = keygen(EDWARDS25519SHA512BATCH) + const SAKid = keyId(SAK) + const SAKpublic = serializeKey(SAK, false) + const contractData = `identity-${SAKid}-${Date.now()}` + const contractID = createCID(contractData, multicodes.SHELTER_CONTRACT_DATA) + + const rootState = sbp('chelonia/rootState') + rootState[contractID] = { + _vm: { + authorizedKeys: { + [SAKid]: { + id: SAKid, + name: '#sak', + purpose: ['sak'], + ringLevel: 0, + permissions: [], + allowedActions: [], + data: SAKpublic, + _notBeforeHeight: 0, + _notAfterHeight: null + } + } + } + } + rootState.contracts = rootState.contracts || Object.create(null) + rootState.contracts[contractID] = { + type: 'gi.contracts/identity', + HEAD: createCID(contractData + '-head', multicodes.SHELTER_CONTRACT_DATA), + height: 0 + } + + return { contractID, SAK, SAKid } +} + +export function buildShelterAuthHeader (contractID: string, SAK: ReturnType) { + const nonceBytes = new Uint8Array(15) + crypto.getRandomValues(nonceBytes) + const data = `${contractID} ${Date.now()}.${Buffer.from(nonceBytes).toString('base64')}` + return `shelter ${data}.${sign(SAK, data)}` +} + +export async function startTestServer (): Promise { + process.env.NODE_ENV = 'development' + process.env.CI = 'true' + + nconf.defaults({ + server: { + host: '127.0.0.1', + port: TEST_PORT, + appDir: '.', + fileUploadMaxBytes: 31457280, + signup: { + disabled: false, + limit: { disabled: false, minute: 100, hour: 1000, day: 10000 } + }, + logLevel: 'error', + messages: [{ type: 'info', text: 'test message' }], + maxEventsBatchSize: 500, + archiveMode: false + }, + database: { + lruNumItems: 100, + backend: 'mem', + backendOptions: {} + } + }) + + nconf.set('server:host', '127.0.0.1') + nconf.set('server:port', TEST_PORT) + nconf.set('database:backend', 'mem') + nconf.set('server:messages', [{ type: 'info', text: 'test message' }]) + nconf.set('server:archiveMode', false) + + const serverAddress = await new Promise((resolve, reject) => { + sbp('okTurtles.events/on', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { + resolve(hapi.info.uri) + }) + import('./server.ts').catch(reject) + }) + + return serverAddress +} + +export async function stopTestServer (): Promise { + await new Promise((resolve) => { + sbp('okTurtles.events/once', SERVER_EXITING, () => { + sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { + resolve() + }) + }) + sbp('okTurtles.events/emit', SERVER_EXITING) + }) + await sbp('backend/server/stop') +} diff --git a/src/serve/routes-writes.test.ts b/src/serve/routes-writes.test.ts new file mode 100644 index 0000000..070777c --- /dev/null +++ b/src/serve/routes-writes.test.ts @@ -0,0 +1,500 @@ +import 'jsr:@db/sqlite' +import { + blake32Hash, + buildShelterAuthHeader, + createCID, + createTestIdentity, + multicodes, + sbp, + startTestServer, + stopTestServer +} from './routes-test-helpers.ts' + +Deno.test({ + name: 'routes: write endpoints', + sanitizeResources: false, + sanitizeOps: false, + async fn (t: Deno.TestContext) { + const baseURL = await startTestServer() + + try { + const owner = createTestIdentity() + + await t.step('setup: register billable entity for owner', async () => { + await sbp('chelonia.db/set', owner.contractID, 'identity-contract-data') + await sbp('chelonia.db/set', `head=${owner.contractID}`, JSON.stringify({ + HEAD: createCID('owner-head', multicodes.SHELTER_CONTRACT_DATA), + previousKeyOp: null, + height: 0 + })) + }) + + await t.step('POST /dev-file with valid hash and data returns file path', async () => { + const data = 'dev-file-test-content' + const hash = createCID(data, multicodes.SHELTER_FILE_CHUNK) + const form = new FormData() + form.append('hash', hash) + form.append('data', data) + const res = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + const body = await res.text() + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}: ${body}`) + if (body !== `/file/${hash}`) { + throw new Error(`Expected /file/${hash} but got ${body}`) + } + }) + + await t.step('POST /dev-file with missing hash returns 400', async () => { + const form = new FormData() + form.append('data', 'some-data') + const res = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /dev-file with missing data returns 400', async () => { + const form = new FormData() + form.append('hash', createCID('test', multicodes.SHELTER_FILE_CHUNK)) + const res = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /dev-file with mismatched hash returns 400', async () => { + const data = 'actual-data' + const wrongHash = createCID('different-data', multicodes.SHELTER_FILE_CHUNK) + const form = new FormData() + form.append('hash', wrongHash) + form.append('data', data) + const res = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /dev-file with invalid hash returns 400', async () => { + const form = new FormData() + form.append('hash', 'not-a-valid-cid') + form.append('data', 'some-data') + const res = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /dev-file stored file is retrievable via GET /file', async () => { + const data = 'retrievable-dev-file' + const hash = createCID(data, multicodes.SHELTER_FILE_MANIFEST) + const form = new FormData() + form.append('hash', hash) + form.append('data', data) + const uploadRes = await fetch(`${baseURL}/dev-file`, { + method: 'POST', + body: form + }) + if (uploadRes.status !== 200) throw new Error(`Upload failed: ${uploadRes.status}`) + await uploadRes.body?.cancel() + + const getRes = await fetch(`${baseURL}/file/${hash}`) + if (getRes.status !== 200) throw new Error(`GET failed: ${getRes.status}`) + const body = await getRes.text() + if (body !== data) throw new Error(`Expected ${data} but got ${body}`) + }) + + await t.step('GET /ownResources without auth returns 401', async () => { + const res = await fetch(`${baseURL}/ownResources`) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('GET /ownResources with invalid auth returns 401', async () => { + const res = await fetch(`${baseURL}/ownResources`, { + headers: { authorization: 'shelter invalid-token' } + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('GET /ownResources with valid auth returns empty array initially', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/ownResources`, { + headers: { authorization: auth } + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!Array.isArray(body)) throw new Error('Expected array') + }) + + await t.step('GET /ownResources returns owned resources after seeding', async () => { + const resourceID = createCID('owned-resource-1', multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', `_private_owner_${resourceID}`, owner.contractID) + await sbp('chelonia.db/set', `_private_resources_${owner.contractID}`, resourceID) + + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/ownResources`, { + headers: { authorization: auth } + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!Array.isArray(body)) throw new Error('Expected array') + if (!body.includes(resourceID)) { + throw new Error(`Expected resources to include ${resourceID}`) + } + }) + + await t.step('POST /deleteFile without auth returns 401', async () => { + const hash = createCID('some-file', multicodes.SHELTER_FILE_MANIFEST) + const res = await fetch(`${baseURL}/deleteFile/${hash}`, { method: 'POST' }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /deleteFile with wrong CID type returns 400', async () => { + const hash = createCID('test', multicodes.SHELTER_CONTRACT_DATA) + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/deleteFile/${hash}`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /deleteFile with nonexistent file returns 404', async () => { + const hash = createCID('nonexistent-file', multicodes.SHELTER_FILE_MANIFEST) + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/deleteFile/${hash}`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('POST /deleteFile with shelter auth deletes owned file', async () => { + const chunkData = 'chunk-to-delete' + const chunkHash = createCID(chunkData, multicodes.SHELTER_FILE_CHUNK) + await sbp('chelonia.db/set', chunkHash, chunkData) + + const manifestData = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkData.length, + chunks: [[chunkData.length, chunkHash]] + }) + const manifestHash = createCID(manifestData, multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', manifestHash, manifestData) + await sbp('chelonia.db/set', `_private_owner_${manifestHash}`, owner.contractID) + await sbp('chelonia.db/set', `_private_size_${manifestHash}`, String(chunkData.length + manifestData.length)) + + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/deleteFile/${manifestHash}`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status < 200 || res.status > 204) throw new Error(`Expected 2xx but got ${res.status}`) + + const getRes = await fetch(`${baseURL}/file/${manifestHash}`) + await getRes.body?.cancel() + if (getRes.status !== 410) throw new Error(`Expected 410 after deletion but got ${getRes.status}`) + }) + + await t.step('POST /deleteFile with bearer token deletes file', async () => { + const chunkData2 = 'chunk-to-delete-bearer' + const chunkHash2 = createCID(chunkData2, multicodes.SHELTER_FILE_CHUNK) + await sbp('chelonia.db/set', chunkHash2, chunkData2) + + const manifestData2 = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkData2.length, + chunks: [[chunkData2.length, chunkHash2]] + }) + const manifestHash2 = createCID(manifestData2, multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', manifestHash2, manifestData2) + await sbp('chelonia.db/set', `_private_owner_${manifestHash2}`, owner.contractID) + await sbp('chelonia.db/set', `_private_size_${manifestHash2}`, String(chunkData2.length + manifestData2.length)) + + const deletionToken = 'my-secret-deletion-token' + const tokenDigest = blake32Hash(deletionToken) + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash2}`, tokenDigest) + + const res = await fetch(`${baseURL}/deleteFile/${manifestHash2}`, { + method: 'POST', + headers: { authorization: `bearer ${deletionToken}` } + }) + await res.body?.cancel() + if (res.status < 200 || res.status > 204) throw new Error(`Expected 2xx but got ${res.status}`) + }) + + await t.step('POST /deleteFile with wrong bearer token returns 401', async () => { + const chunkData3 = 'chunk-bearer-wrong' + const chunkHash3 = createCID(chunkData3, multicodes.SHELTER_FILE_CHUNK) + await sbp('chelonia.db/set', chunkHash3, chunkData3) + + const manifestData3 = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkData3.length, + chunks: [[chunkData3.length, chunkHash3]] + }) + const manifestHash3 = createCID(manifestData3, multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', manifestHash3, manifestData3) + await sbp('chelonia.db/set', `_private_owner_${manifestHash3}`, owner.contractID) + const tokenDigest3 = blake32Hash('correct-token') + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash3}`, tokenDigest3) + + const res = await fetch(`${baseURL}/deleteFile/${manifestHash3}`, { + method: 'POST', + headers: { authorization: 'bearer wrong-token' } + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /deleteFile with non-owner shelter auth returns 401', async () => { + const nonOwner = createTestIdentity() + const chunkData4 = 'chunk-non-owner' + const chunkHash4 = createCID(chunkData4, multicodes.SHELTER_FILE_CHUNK) + await sbp('chelonia.db/set', chunkHash4, chunkData4) + + const manifestData4 = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkData4.length, + chunks: [[chunkData4.length, chunkHash4]] + }) + const manifestHash4 = createCID(manifestData4, multicodes.SHELTER_FILE_MANIFEST) + await sbp('chelonia.db/set', manifestHash4, manifestData4) + await sbp('chelonia.db/set', `_private_owner_${manifestHash4}`, owner.contractID) + + const auth = buildShelterAuthHeader(nonOwner.contractID, nonOwner.SAK) + const res = await fetch(`${baseURL}/deleteFile/${manifestHash4}`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /deleteContract without auth returns 401', async () => { + const hash = createCID('some-contract', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/deleteContract/${hash}`, { method: 'POST' }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /deleteContract with _private prefix returns 404', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const res = await fetch(`${baseURL}/deleteContract/_private_something`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('POST /deleteContract with nonexistent contract returns 404', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const hash = createCID('nonexistent-contract', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/deleteContract/${hash}`, { + method: 'POST', + headers: { authorization: auth } + }) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('POST /deleteContract with bearer token and matching deletion token returns 202', async () => { + const contractData = 'deletable-contract-data' + const contractCID = createCID(contractData, multicodes.SHELTER_CONTRACT_DATA) + await sbp('chelonia.db/set', contractCID, contractData) + await sbp('chelonia.db/set', `head=${contractCID}`, JSON.stringify({ + HEAD: createCID('del-head', multicodes.SHELTER_CONTRACT_DATA), + previousKeyOp: null, + height: 0 + })) + await sbp('chelonia.db/set', `_private_owner_${contractCID}`, owner.contractID) + + const deletionToken = 'contract-deletion-token' + const tokenDigest = blake32Hash(deletionToken) + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${contractCID}`, tokenDigest) + + const res = await fetch(`${baseURL}/deleteContract/${contractCID}`, { + method: 'POST', + headers: { authorization: `bearer ${deletionToken}` } + }) + const body = await res.json() + if (res.status !== 202) throw new Error(`Expected 202 but got ${res.status}`) + if (!body.id) throw new Error('Expected response to have an id field') + }) + + await t.step('POST /deleteContract with wrong bearer token returns 401', async () => { + const contractData = 'contract-wrong-bearer' + const contractCID = createCID(contractData, multicodes.SHELTER_CONTRACT_DATA) + await sbp('chelonia.db/set', contractCID, contractData) + await sbp('chelonia.db/set', `_private_owner_${contractCID}`, owner.contractID) + const tokenDigest = blake32Hash('the-right-token') + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${contractCID}`, tokenDigest) + + const res = await fetch(`${baseURL}/deleteContract/${contractCID}`, { + method: 'POST', + headers: { authorization: 'bearer wrong-token' } + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /event with invalid payload returns 400', async () => { + const res = await fetch(`${baseURL}/event`, { + method: 'POST', + headers: { 'content-type': 'text/plain' }, + body: '' + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /event with non-JSON payload returns 500', async () => { + const res = await fetch(`${baseURL}/event`, { + method: 'POST', + headers: { 'content-type': 'text/plain' }, + body: 'not-json-at-all' + }) + await res.body?.cancel() + if (res.status !== 500) throw new Error(`Expected 500 but got ${res.status}`) + }) + + await t.step('POST /file without auth returns 401', async () => { + const form = new FormData() + form.append('manifest', new Blob(['{}'], { type: 'application/json' }), 'manifest.json') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + body: form + }) + await res.body?.cancel() + if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) + }) + + await t.step('POST /file with auth but missing manifest returns 400', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const form = new FormData() + form.append('notmanifest', new Blob(['data'], { type: 'application/octet-stream' }), 'something.bin') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /file with wrong manifest filename returns 400', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const form = new FormData() + form.append('manifest', new Blob(['{}'], { type: 'application/vnd.shelter.filemanifest' }), 'wrong.json') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /file with invalid manifest JSON returns 422', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const form = new FormData() + form.append('manifest', new Blob(['not-json'], { type: 'application/vnd.shelter.filemanifest' }), 'manifest.json') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + await res.body?.cancel() + if (res.status !== 422) throw new Error(`Expected 422 but got ${res.status}`) + }) + + await t.step('POST /file with unsupported manifest version returns 422', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const manifest = JSON.stringify({ version: '2.0.0', cipher: 'aes256gcm', chunks: [[1, 'z']] }) + const form = new FormData() + form.append('manifest', new Blob([manifest], { type: 'application/vnd.shelter.filemanifest' }), 'manifest.json') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + await res.body?.cancel() + if (res.status !== 422) throw new Error(`Expected 422 but got ${res.status}`) + }) + + await t.step('POST /file with valid manifest and chunk uploads file', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const chunkContent = new Uint8Array([72, 101, 108, 108, 111]) + const chunkHash = createCID(chunkContent, multicodes.SHELTER_FILE_CHUNK) + const manifest = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkContent.byteLength, + chunks: [[chunkContent.byteLength, chunkHash]] + }) + const form = new FormData() + form.append('manifest', new Blob([manifest], { type: 'application/vnd.shelter.filemanifest' }), 'manifest.json') + form.append('0', new Blob([chunkContent], { type: 'application/octet-stream' }), '0') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + const body = await res.text() + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}: ${body}`) + const manifestHash = createCID(new TextEncoder().encode(manifest), multicodes.SHELTER_FILE_MANIFEST) + if (body !== manifestHash) { + throw new Error(`Expected manifest hash ${manifestHash} but got ${body}`) + } + + const getRes = await fetch(`${baseURL}/file/${manifestHash}`) + if (getRes.status !== 200) throw new Error(`GET file failed: ${getRes.status}`) + await getRes.body?.cancel() + }) + + await t.step('POST /file rejects duplicate upload', async () => { + const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) + const chunkContent = new Uint8Array([72, 101, 108, 108, 111]) + const chunkHash = createCID(chunkContent, multicodes.SHELTER_FILE_CHUNK) + const manifest = JSON.stringify({ + version: '1.0.0', + cipher: 'aes256gcm', + size: chunkContent.byteLength, + chunks: [[chunkContent.byteLength, chunkHash]] + }) + const form = new FormData() + form.append('manifest', new Blob([manifest], { type: 'application/vnd.shelter.filemanifest' }), 'manifest.json') + form.append('0', new Blob([chunkContent], { type: 'application/octet-stream' }), '0') + const res = await fetch(`${baseURL}/file`, { + method: 'POST', + headers: { authorization: auth }, + body: form + }) + await res.body?.cancel() + if (res.status !== 500) throw new Error(`Expected 500 for duplicate but got ${res.status}`) + }) + } finally { + await stopTestServer() + } + } +}) diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts new file mode 100644 index 0000000..ae556ce --- /dev/null +++ b/src/serve/routes-zkpp.test.ts @@ -0,0 +1,194 @@ +import 'jsr:@db/sqlite' +import { Buffer } from 'node:buffer' +import { + createCID, + decryptRegistrationRedemptionToken, + multicodes, + nacl, + saltsAndEncryptedHashedPassword, + sbp, + startTestServer, + stopTestServer +} from './routes-test-helpers.ts' +import { CS } from 'npm:@chelonia/lib/zkppConstants' + +Deno.test({ + name: 'routes: ZKPP endpoints', + sanitizeResources: false, + sanitizeOps: false, + async fn (t: Deno.TestContext) { + const baseURL = await startTestServer() + + try { + await t.step('POST /zkpp/register step 1: returns {s, p, sig}', async () => { + const keyPair = nacl.box.keyPair() + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from( + Buffer.from(keyPair.publicKey).toString('base64url') + ))).toString('base64url') + const res = await fetch(`${baseURL}/zkpp/register/zkppuser1`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ b: publicKeyHash }) + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!body.s) throw new Error('Expected s in response') + if (!body.p) throw new Error('Expected p in response') + if (!body.sig) throw new Error('Expected sig in response') + }) + + await t.step('POST /zkpp/register step 2: completes registration', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const res1 = await fetch(`${baseURL}/zkpp/register/zkppuser2`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ b: publicKeyHash }) + }) + if (res1.status !== 200) throw new Error(`Step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, 'testhash') + const res2 = await fetch(`${baseURL}/zkpp/register/zkppuser2`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + r: publicKey, + s: step1.s, + sig: step1.sig, + Eh: encryptedHashedPassword + }) + }) + if (res2.status !== 200) throw new Error(`Step 2 failed: ${res2.status}`) + const token = await res2.text() + if (!token) throw new Error('Expected registration token') + }) + + await t.step('POST /zkpp/register with invalid name returns 400', async () => { + const res = await fetch(`${baseURL}/zkpp/register/INVALID_NAME!!`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ b: 'test' }) + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /zkpp/register with already registered name returns 409', async () => { + await sbp('backend/db/registerName', 'zkppregistered', createCID('zkpp-contract', multicodes.SHELTER_CONTRACT_DATA)) + const res = await fetch(`${baseURL}/zkpp/register/zkppregistered`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ b: 'test' }) + }) + await res.body?.cancel() + if (res.status !== 409) throw new Error(`Expected 409 but got ${res.status}`) + }) + + await t.step('GET /zkpp/{contractID}/auth_hash with unknown contract returns 404', async () => { + const unknownCID = createCID('zkpp-unknown', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${unknownCID}/auth_hash?b=test`) + await res.body?.cancel() + if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + }) + + await t.step('GET /zkpp/{contractID}/auth_hash with invalid CID returns 400', async () => { + const res = await fetch(`${baseURL}/zkpp/not-a-cid/auth_hash?b=test`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /zkpp/{contractID}/auth_hash with missing b param returns 400', async () => { + const cid = createCID('zkpp-test', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${cid}/auth_hash`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('GET /zkpp/{contractID}/contract_hash with missing params returns 400', async () => { + const cid = createCID('zkpp-test', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${cid}/contract_hash?r=a&s=b`) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('POST /zkpp/{contractID}/updatePasswordHash with missing params returns 400', async () => { + const cid = createCID('zkpp-test', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${cid}/updatePasswordHash`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ r: 'a', s: 'b' }) + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('ZKPP full flow: register, challenge, get contract salt', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + const hash = 'myhash' + const name = 'zkppfullflow' + + const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ b: publicKeyHash }) + }) + if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) + const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ r: publicKey, s: step1.s, sig: step1.sig, Eh: encryptedHashedPassword }) + }) + if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) + const encryptedToken = (await res2.text()).replace(/^"|"$/g, '') + const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) + + const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) + await sbp('backend/db/registerName', name, contractCID) + + const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') + await redeemSaltRegistrationToken(name, contractCID, token) + + const r = 'challenge-r' + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) + if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) + const challenge = await challengeRes.json() + if (!challenge.authSalt) throw new Error('Expected authSalt') + if (!challenge.s) throw new Error('Expected s') + if (!challenge.sig) throw new Error('Expected sig') + if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const saltRes = await fetch( + `${baseURL}/zkpp/${contractCID}/contract_hash?` + + `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + + `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` + ) + if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) + const encryptedSalt = await saltRes.text() + if (!encryptedSalt) throw new Error('Expected encrypted salt response') + + const saltBuf = Buffer.from(encryptedSalt.replace(/^"|"$/g, ''), 'base64url') + const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) + const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt contract salt') + const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) + if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') + }) + } finally { + await stopTestServer() + } + } +}) From a8d2ef243d192299623d3ff5436793f0db7ca74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:04:41 -0400 Subject: [PATCH 06/71] Fixes --- src/serve/routes.ts | 6 ++++-- src/serve/server.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 1158512..d6299f1 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -206,6 +206,7 @@ app.post('/event', const ip = getClientIP(c) try { const payload = await c.req.text() + if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) const namespaceRegistration = c.req.header('shelter-namespace-registration') if (namespaceRegistration && !NAME_REGEX.test(namespaceRegistration)) { throw new HTTPException(400, { message: 'Invalid shelter-namespace-registration header' }) @@ -343,15 +344,16 @@ app.get('/eventsAfter/:contractID/:since/:limit?', // Use the request abort signal to destroy the stream when the client disconnects c.req.raw.signal.addEventListener('abort', () => stream.destroy()) // Convert the Node Readable stream to a web ReadableStream for the Response + const streamHeaders = (stream as { headers?: Record }).headers || {} const webStream = Readable.toWeb(stream) as ReadableStream return new Response(webStream, { - headers: { 'content-type': 'application/octet-stream' } + headers: { 'content-type': 'application/octet-stream', ...streamHeaders } }) } catch (err) { if (err instanceof HTTPException) throw err ;(err as unknown as { ip: string }).ip = ip logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) - throw err + errorMapper(err as Error) } }) diff --git a/src/serve/server.ts b/src/serve/server.ts index 1a950f9..7b39a28 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -559,8 +559,10 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { const host = nconf.get('server:host') || '0.0.0.0' const port = nconf.get('server:port') || 8000 httpServer.listen(port, host, () => { - console.info(`Backend server running at: http://${host}:${port}`) - sbp('okTurtles.events/emit', SERVER_RUNNING, app) + const addr = httpServer.address() as { address: string; port: number } + const uri = `http://${addr.address}:${addr.port}` + console.info('Backend server running at:', uri) + sbp('okTurtles.events/emit', SERVER_RUNNING, { info: { uri } }) }) })() From 88d2651abf70ca4f230656dc36420f75f9e71143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:27:53 -0400 Subject: [PATCH 07/71] Fix build step --- build/main.js | 65067 ++++++-------------------- build/serve/creditsWorker.js | 4 +- build/serve/ownerSizeTotalWorker.js | 4 +- scripts/build.ts | 15 +- 4 files changed, 15038 insertions(+), 50052 deletions(-) diff --git a/build/main.js b/build/main.js index 2cf0783..b7abef3 100644 --- a/build/main.js +++ b/build/main.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/main.js-tmp @@ -850,9 +850,9 @@ var EOL = globalThis.Deno?.build.os === "windows" ? CRLF : LF; var { Deno: Deno2 } = globalThis; var noColor = typeof Deno2?.noColor === "boolean" ? Deno2.noColor : false; var enabled = !noColor; -function code(open, close) { +function code(open2, close) { return { - open: `\x1B[${open.join(";")}m`, + open: `\x1B[${open2.join(";")}m`, close: `\x1B[${close}m`, regexp: new RegExp(`\\x1b\\[${close}m`, "g") }; @@ -3080,9 +3080,15 @@ import { mkdir as mkdir2 } from "node:fs/promises"; import { basename as basename22, dirname as dirname22, join as join22, resolve as resolve22 } from "node:path"; import process2 from "node:process"; import { Readable } from "node:stream"; +import { join as join72 } from "node:path"; import path5 from "node:path"; import process5 from "node:process"; import process6 from "node:process"; +import { createServer as createServerHTTP } from "node:http"; +import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "node:http2"; +import { Http2ServerRequest } from "node:http2"; +import { Readable as Readable2 } from "node:stream"; +import crypto2 from "node:crypto"; import { Buffer as Buffer13 } from "node:buffer"; import { basename as basename52 } from "node:path"; import process7 from "node:process"; @@ -3092,7 +3098,8 @@ import { Buffer as Buffer15 } from "node:buffer"; import { isIP } from "node:net"; import path6 from "node:path"; import process9 from "node:process"; -import { join as join72 } from "node:path"; +import { Readable as Readable3 } from "node:stream"; +import { join as join82 } from "node:path"; import process10 from "node:process"; import { pathToFileURL } from "node:url"; import process11 from "node:process"; @@ -4116,7 +4123,7 @@ import { basename as basename42, dirname as dirname42, join as join62 } from "no import process4 from "node:process"; import process12 from "node:process"; import { notStrictEqual, strictEqual } from "node:assert"; -import { dirname as dirname52, resolve as resolve42 } from "node:path"; +import { dirname as dirname62, resolve as resolve42 } from "node:path"; import { readdirSync, statSync } from "node:fs"; import { format as format42, inspect } from "node:util"; import { readFileSync as readFileSync3 } from "node:fs"; @@ -4124,7 +4131,7 @@ import { fileURLToPath } from "node:url"; import { format as format22 } from "node:util"; import { readFileSync } from "node:fs"; import { normalize as normalize22, resolve as resolve52 } from "node:path"; -import { basename as basename62, dirname as dirname62, extname as extname8, relative as relative22, resolve as resolve72 } from "node:path"; +import { basename as basename62, dirname as dirname72, extname as extname8, relative as relative22, resolve as resolve72 } from "node:path"; import { readFileSync as readFileSync2, statSync as statSync2, writeFile as writeFile3 } from "node:fs"; import { format as format32 } from "node:util"; import { resolve as resolve62 } from "node:path"; @@ -4829,12 +4836,12 @@ var require_async = __commonJS({ } function parseParams(func) { const src2 = stripComments(func.toString()); - let match = src2.match(FN_ARGS); - if (!match) { - match = src2.match(ARROW_FN_ARGS); + let match2 = src2.match(FN_ARGS); + if (!match2) { + match2 = src2.match(ARROW_FN_ARGS); } - if (!match) throw new Error("could not parse args in autoInject\nSource:\n" + src2); - let [, args] = match; + if (!match2) throw new Error("could not parse args in autoInject\nSource:\n" + src2); + let [, args] = match2; return args.replace(/\s/g, "").split(FN_ARG_SPLIT).map((arg) => arg.replace(FN_ARG, "").trim()); } function autoInject(tasks, callback) { @@ -5219,7 +5226,7 @@ var require_async = __commonJS({ return cb[PROMISE_SYMBOL]; }; } - function compose(...args) { + function compose2(...args) { return seq(...args.reverse()); } function mapLimit(coll, limit, iteratee, callback) { @@ -5961,7 +5968,7 @@ var require_async = __commonJS({ autoInject, cargo: cargo$1, cargoQueue: cargo, - compose, + compose: compose2, concat: concat$1, concatLimit: concatLimit$1, concatSeries: concatSeries$1, @@ -6072,7 +6079,7 @@ var require_async = __commonJS({ exports3.autoInject = autoInject; exports3.cargo = cargo$1; exports3.cargoQueue = cargo; - exports3.compose = compose; + exports3.compose = compose2; exports3.concat = concat$1; exports3.concatLimit = concatLimit$1; exports3.concatSeries = concatSeries$1; @@ -6219,11 +6226,11 @@ var require_ini = __commonJS({ for (const line of lines) { if (!line || line.match(/^\s*[;#]/)) continue; - const match = line.match(re); - if (!match) + const match2 = line.match(re); + if (!match2) continue; - if (match[1] !== void 0) { - section = unsafe(match[1]); + if (match2[1] !== void 0) { + section = unsafe(match2[1]); if (section === "__proto__") { p = /* @__PURE__ */ Object.create(null); continue; @@ -6231,12 +6238,12 @@ var require_ini = __commonJS({ p = out[section] = out[section] || /* @__PURE__ */ Object.create(null); continue; } - const keyRaw = unsafe(match[2]); + const keyRaw = unsafe(match2[2]); const isArray = keyRaw.length > 2 && keyRaw.slice(-2) === "[]"; const key = isArray ? keyRaw.slice(0, -2) : keyRaw; if (key === "__proto__") continue; - const valueRaw = match[3] ? unsafe(match[4]) : true; + const valueRaw = match2[3] ? unsafe(match2[4]) : true; const value = valueRaw === "true" || valueRaw === "false" || valueRaw === "null" ? JSON.parse(valueRaw) : valueRaw; if (isArray) { if (!hasOwnProperty.call(p, key)) @@ -7900,8 +7907,8 @@ var require_build2 = __commonJS({ function hasFlagsMatching(arg, ...patterns) { const toCheck = [].concat(...patterns); return toCheck.some(function(pattern) { - const match = arg.match(pattern); - return match && hasAnyFlag(match[1]); + const match2 = arg.match(pattern); + return match2 && hasAnyFlag(match2[1]); }); } function hasAllShortFlags(arg) { @@ -8442,9 +8449,9 @@ var require_conversions = __commonJS({ const g2 = rgb[1]; let b = rgb[2]; const h2 = convert.rgb.hsl(rgb)[0]; - const w4 = 1 / 255 * Math.min(r, Math.min(g2, b)); + const w3 = 1 / 255 * Math.min(r, Math.min(g2, b)); b = 1 - 1 / 255 * Math.max(r, Math.max(g2, b)); - return [h2, w4 * 100, b * 100]; + return [h2, w3 * 100, b * 100]; }; convert.rgb.cmyk = function(rgb) { const r = rgb[0] / 255; @@ -8806,12 +8813,12 @@ var require_conversions = __commonJS({ return "000000".substring(string3.length) + string3; }; convert.hex.rgb = function(args) { - const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); - if (!match) { + const match2 = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i); + if (!match2) { return [0, 0, 0]; } - let colorString = match[0]; - if (match[0].length === 3) { + let colorString = match2[0]; + if (match2[0].length === 3) { colorString = colorString.split("").map((char) => { return char + char; }).join(""); @@ -8879,7 +8886,7 @@ var require_conversions = __commonJS({ const pure = [0, 0, 0]; const hi = h2 % 1 * 6; const v2 = hi % 1; - const w4 = 1 - v2; + const w3 = 1 - v2; let mg = 0; switch (Math.floor(hi)) { case 0: @@ -8888,7 +8895,7 @@ var require_conversions = __commonJS({ pure[2] = 0; break; case 1: - pure[0] = w4; + pure[0] = w3; pure[1] = 1; pure[2] = 0; break; @@ -8899,7 +8906,7 @@ var require_conversions = __commonJS({ break; case 3: pure[0] = 0; - pure[1] = w4; + pure[1] = w3; pure[2] = 1; break; case 4: @@ -8910,7 +8917,7 @@ var require_conversions = __commonJS({ default: pure[0] = 1; pure[1] = 0; - pure[2] = w4; + pure[2] = w3; } mg = (1 - c) * g2; return [ @@ -8948,10 +8955,10 @@ var require_conversions = __commonJS({ return [hcg[0], (v2 - c) * 100, (1 - v2) * 100]; }; convert.hwb.hcg = function(hwb) { - const w4 = hwb[1] / 100; + const w3 = hwb[1] / 100; const b = hwb[2] / 100; const v2 = 1 - b; - const c = v2 - w4; + const c = v2 - w3; let g2 = 0; if (c < 1) { g2 = (v2 - c) / (1 - c); @@ -9063,7 +9070,7 @@ var require_route = __commonJS({ var require_color_convert = __commonJS({ "node_modules/.deno/color-convert@2.0.1/node_modules/color-convert/index.js"(exports2, module14) { var conversions = require_conversions(); - var route2 = require_route(); + var route = require_route(); var convert = {}; var models = Object.keys(conversions); function wrapRaw(fn) { @@ -9108,7 +9115,7 @@ var require_color_convert = __commonJS({ convert[fromModel] = {}; Object.defineProperty(convert[fromModel], "channels", { value: conversions[fromModel].channels }); Object.defineProperty(convert[fromModel], "labels", { value: conversions[fromModel].labels }); - const routes = route2(fromModel); + const routes = route(fromModel); const routeModels = Object.keys(routes); routeModels.forEach((toModel) => { const fn = routes[toModel]; @@ -9537,8 +9544,8 @@ var require_build3 = __commonJS({ // if the full 'source' can render in // the target line, do so. renderInline(source, previousLine) { - const match = source.match(/^ */); - const leadingWhitespace = match ? match[0].length : 0; + const match2 = source.match(/^ */); + const leadingWhitespace = match2 ? match2[0].length : 0; const target = previousLine.text; const targetTextWidth = mixin3.stringWidth(target.trimRight()); if (!previousLine.span) { @@ -9615,11 +9622,11 @@ var require_build3 = __commonJS({ return void 0; }); const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0; - return widths.map((w4, i2) => { - if (w4 === void 0) { + return widths.map((w3, i2) => { + if (w3 === void 0) { return Math.max(unsetWidth, _minWidth2(row[i2])); } - return w4; + return w3; }); } }; @@ -9688,18 +9695,18 @@ var require_build3 = __commonJS({ }); var require_sync = __commonJS({ "node_modules/.deno/escalade@3.2.0/node_modules/escalade/sync/index.js"(exports2, module14) { - var { dirname: dirname72, resolve: resolve82 } = __require2("path"); + var { dirname: dirname82, resolve: resolve82 } = __require2("path"); var { readdirSync: readdirSync2, statSync: statSync3 } = __require2("fs"); module14.exports = function(start, callback) { let dir = resolve82(".", start); let tmp, stats = statSync3(dir); if (!stats.isDirectory()) { - dir = dirname72(dir); + dir = dirname82(dir); } while (true) { tmp = callback(dir, readdirSync2(dir)); if (tmp) return resolve82(dir, tmp); - dir = dirname72(tmp = dir); + dir = dirname82(tmp = dir); if (tmp === dir) break; } }; @@ -9731,9 +9738,9 @@ var require_require_directory = __commonJS({ "node_modules/.deno/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module14) { "use strict"; var fs = __require2("fs"); - var join92 = __require2("path").join; + var join10 = __require2("path").join; var resolve82 = __require2("path").resolve; - var dirname72 = __require2("path").dirname; + var dirname82 = __require2("path").dirname; var defaultOptions4 = { extensions: ["js", "json", "coffee"], recurse: true, @@ -9766,9 +9773,9 @@ var require_require_directory = __commonJS({ options2[prop] = defaultOptions4[prop]; } } - path8 = !path8 ? dirname72(m3.filename) : resolve82(dirname72(m3.filename), path8); + path8 = !path8 ? dirname82(m3.filename) : resolve82(dirname82(m3.filename), path8); fs.readdirSync(path8).forEach(function(filename) { - var joined = join92(path8, filename), files, key, obj; + var joined = join10(path8, filename), files, key, obj; if (fs.statSync(joined).isDirectory() && options2.recurse) { files = requireDirectory(m3, joined, options2); if (Object.keys(files).length) { @@ -9937,7 +9944,7 @@ var require_build4 = __commonJS({ function argumentTypeError2(observedType, allowedTypes, position) { throw new YError2(`Invalid ${positionName2[position] || "manyith"} argument. Expected ${allowedTypes.join(" or ")} but received ${observedType}.`); } - function isPromise2(maybePromise) { + function isPromise3(maybePromise) { return !!maybePromise && !!maybePromise.then && typeof maybePromise.then === "function"; } function assertNotStrictEqual2(actual, expected, shim5, message) { @@ -9990,16 +9997,16 @@ var require_build4 = __commonJS({ if (middleware.applyBeforeValidation !== beforeValidation) { return acc; } - if (isPromise2(acc)) { + if (isPromise3(acc)) { return acc.then((initialObj) => Promise.all([ initialObj, middleware(initialObj, yargs) ])).then(([initialObj, middlewareObj]) => Object.assign(initialObj, middlewareObj)); } else { const result = middleware(acc, yargs); - if (beforeValidation && isPromise2(result)) + if (beforeValidation && isPromise3(result)) throw beforeValidationError; - return isPromise2(result) ? result.then((middlewareObj) => Object.assign(acc, middlewareObj)) : Object.assign(acc, result); + return isPromise3(result) ? result.then((middlewareObj) => Object.assign(acc, middlewareObj)) : Object.assign(acc, result); } }, argv); } @@ -10187,13 +10194,13 @@ var require_build4 = __commonJS({ yargs2._postProcess(innerArgv, populateDoubleDash); innerArgv = applyMiddleware2(innerArgv, yargs2, middlewares, false); let handlerResult; - if (isPromise2(innerArgv)) { + if (isPromise3(innerArgv)) { handlerResult = innerArgv.then((argv) => commandHandler.handler(argv)); } else { handlerResult = commandHandler.handler(innerArgv); } const handlerFinishCommand = yargs2.getHandlerFinishCommand(); - if (isPromise2(handlerResult)) { + if (isPromise3(handlerResult)) { yargs2.getUsageInstance().cacheHelpMessage(); handlerResult.then((value) => { if (handlerFinishCommand) { @@ -10950,7 +10957,7 @@ compdef _{{app_name}}_yargs_completions {{app_name}} assertNotStrictEqual2(completionFunction, null, shim5); if (isSyncCompletionFunction2(completionFunction)) { const result = completionFunction(current, argv2); - if (isPromise2(result)) { + if (isPromise3(result)) { return result.then((list) => { shim5.process.nextTick(() => { done(list); @@ -10969,7 +10976,7 @@ compdef _{{app_name}}_yargs_completions {{app_name}} } } if (completionFunction) { - return isPromise2(argv) ? argv.then(runCompletionFunction) : runCompletionFunction(argv); + return isPromise3(argv) ? argv.then(runCompletionFunction) : runCompletionFunction(argv); } const handlers = command3.getCommandHandlers(); for (let i2 = 0, ii = args.length; i2 < ii; ++i2) { @@ -12362,7 +12369,7 @@ ${customMsgs.join("\n")}` : ""; return self2._postProcess(argv, populateDoubleDash, _calledFromCommand); }; self2._postProcess = function(argv, populateDoubleDash, calledFromCommand = false) { - if (isPromise2(argv)) + if (isPromise3(argv)) return argv; if (calledFromCommand) return argv; @@ -12484,7 +12491,7 @@ ${customMsgs.join("\n")}` : ""; Yargs: Yargs$1, argsert: argsert2, globalMiddlewareFactory: globalMiddlewareFactory2, - isPromise: isPromise2, + isPromise: isPromise3, objFilter: objFilter2, parseCommand: parseCommand2, Parser: Parser$1, @@ -12675,7 +12682,7 @@ var require_env = __commonJS({ var require_secure_keys = __commonJS({ "node_modules/.deno/secure-keys@1.0.0/node_modules/secure-keys/index.js"(exports2, module14) { "use strict"; - var crypto2 = __require2("crypto"); + var crypto3 = __require2("crypto"); var json = { stringify: function(obj, replacer, spacing) { return JSON.stringify(obj, replacer || null, spacing || 2); @@ -12719,7 +12726,7 @@ var require_secure_keys = __commonJS({ }; function cipherConvert(contents, opts) { var encs = opts.encs; - var cipher = crypto2.createCipher(opts.alg, opts.secret); + var cipher = crypto3.createCipher(opts.alg, opts.secret); return cipher.update(contents, encs.input, encs.output) + cipher.final(encs.output); } } @@ -17189,10 +17196,10 @@ var require_util = __commonJS({ } console.log(msg); } - function testSpeed(hashFn, N11, M2) { + function testSpeed(hashFn, N10, M2) { let startMs = (/* @__PURE__ */ new Date()).getTime(); - const input = new Uint8Array(N11); - for (let i2 = 0; i2 < N11; i2++) { + const input = new Uint8Array(N10); + for (let i2 = 0; i2 < N10; i2++) { input[i2] = i2 % 256; } const genMs = (/* @__PURE__ */ new Date()).getTime(); @@ -17205,7 +17212,7 @@ var require_util = __commonJS({ startMs = hashMs; console.log("Hashed in " + ms + "ms: " + hashHex.substring(0, 20) + "..."); console.log( - Math.round(N11 / (1 << 20) / (ms / 1e3) * 100) / 100 + " MB PER SECOND" + Math.round(N10 / (1 << 20) / (ms / 1e3) * 100) / 100 + " MB PER SECOND" ); } } @@ -19283,8 +19290,8 @@ var init_esm4 = __esm({ esm_default("okTurtles.data/delete", listenKey(event)); } }, - "okTurtles.events/setErrorHandler": function(errorHandler) { - this.errorHandler = errorHandler; + "okTurtles.events/setErrorHandler": function(errorHandler2) { + this.errorHandler = errorHandler2; } }); } @@ -20081,7 +20088,7 @@ var require_scrypt_async = __commonJS({ function scrypt3(password, salt, logN, r, dkLen, interruptStep, callback, encoding) { "use strict"; function SHA256(m3) { - var K3 = [ + var K2 = [ 1116352408, 1899447441, 3049323471, @@ -20147,24 +20154,24 @@ var require_scrypt_async = __commonJS({ 3204031479, 3329325298 ]; - var h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762, h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225, w4 = new Array(64); + var h0 = 1779033703, h1 = 3144134277, h2 = 1013904242, h3 = 2773480762, h4 = 1359893119, h5 = 2600822924, h6 = 528734635, h7 = 1541459225, w3 = new Array(64); function blocks(p3) { var off = 0, len = p3.length; while (len >= 64) { var a = h0, b = h1, c = h2, d = h3, e2 = h4, f = h5, g2 = h6, h8 = h7, u2, i3, j, t1, t2; for (i3 = 0; i3 < 16; i3++) { j = off + i3 * 4; - w4[i3] = (p3[j] & 255) << 24 | (p3[j + 1] & 255) << 16 | (p3[j + 2] & 255) << 8 | p3[j + 3] & 255; + w3[i3] = (p3[j] & 255) << 24 | (p3[j + 1] & 255) << 16 | (p3[j + 2] & 255) << 8 | p3[j + 3] & 255; } for (i3 = 16; i3 < 64; i3++) { - u2 = w4[i3 - 2]; + u2 = w3[i3 - 2]; t1 = (u2 >>> 17 | u2 << 32 - 17) ^ (u2 >>> 19 | u2 << 32 - 19) ^ u2 >>> 10; - u2 = w4[i3 - 15]; + u2 = w3[i3 - 15]; t2 = (u2 >>> 7 | u2 << 32 - 7) ^ (u2 >>> 18 | u2 << 32 - 18) ^ u2 >>> 3; - w4[i3] = (t1 + w4[i3 - 7] | 0) + (t2 + w4[i3 - 16] | 0) | 0; + w3[i3] = (t1 + w3[i3 - 7] | 0) + (t2 + w3[i3 - 16] | 0) | 0; } for (i3 = 0; i3 < 64; i3++) { - t1 = (((e2 >>> 6 | e2 << 32 - 6) ^ (e2 >>> 11 | e2 << 32 - 11) ^ (e2 >>> 25 | e2 << 32 - 25)) + (e2 & f ^ ~e2 & g2) | 0) + (h8 + (K3[i3] + w4[i3] | 0) | 0) | 0; + t1 = (((e2 >>> 6 | e2 << 32 - 6) ^ (e2 >>> 11 | e2 << 32 - 11) ^ (e2 >>> 25 | e2 << 32 - 25)) + (e2 & f ^ ~e2 & g2) | 0) + (h8 + (K2[i3] + w3[i3] | 0) | 0) | 0; t2 = ((a >>> 2 | a << 32 - 2) ^ (a >>> 13 | a << 32 - 13) ^ (a >>> 22 | a << 32 - 22)) + (a & b ^ a & c ^ b & c) | 0; h8 = g2; g2 = f; @@ -20264,8 +20271,8 @@ var require_scrypt_async = __commonJS({ } return dk; } - function salsaXOR(tmp2, B5, bin, bout) { - var j0 = tmp2[0] ^ B5[bin++], j1 = tmp2[1] ^ B5[bin++], j2 = tmp2[2] ^ B5[bin++], j3 = tmp2[3] ^ B5[bin++], j4 = tmp2[4] ^ B5[bin++], j5 = tmp2[5] ^ B5[bin++], j6 = tmp2[6] ^ B5[bin++], j7 = tmp2[7] ^ B5[bin++], j8 = tmp2[8] ^ B5[bin++], j9 = tmp2[9] ^ B5[bin++], j10 = tmp2[10] ^ B5[bin++], j11 = tmp2[11] ^ B5[bin++], j12 = tmp2[12] ^ B5[bin++], j13 = tmp2[13] ^ B5[bin++], j14 = tmp2[14] ^ B5[bin++], j15 = tmp2[15] ^ B5[bin++], u2, i2; + function salsaXOR(tmp2, B4, bin, bout) { + var j0 = tmp2[0] ^ B4[bin++], j1 = tmp2[1] ^ B4[bin++], j2 = tmp2[2] ^ B4[bin++], j3 = tmp2[3] ^ B4[bin++], j4 = tmp2[4] ^ B4[bin++], j5 = tmp2[5] ^ B4[bin++], j6 = tmp2[6] ^ B4[bin++], j7 = tmp2[7] ^ B4[bin++], j8 = tmp2[8] ^ B4[bin++], j9 = tmp2[9] ^ B4[bin++], j10 = tmp2[10] ^ B4[bin++], j11 = tmp2[11] ^ B4[bin++], j12 = tmp2[12] ^ B4[bin++], j13 = tmp2[13] ^ B4[bin++], j14 = tmp2[14] ^ B4[bin++], j15 = tmp2[15] ^ B4[bin++], u2, i2; var x0 = j0, x1 = j1, x22 = j2, x3 = j3, x4 = j4, x5 = j5, x6 = j6, x7 = j7, x8 = j8, x9 = j9, x10 = j10, x11 = j11, x12 = j12, x13 = j13, x14 = j14, x15 = j15; for (i2 = 0; i2 < 8; i2 += 2) { u2 = x0 + x12; @@ -20333,22 +20340,22 @@ var require_scrypt_async = __commonJS({ u2 = x14 + x13; x15 ^= u2 << 18 | u2 >>> 32 - 18; } - B5[bout++] = tmp2[0] = x0 + j0 | 0; - B5[bout++] = tmp2[1] = x1 + j1 | 0; - B5[bout++] = tmp2[2] = x22 + j2 | 0; - B5[bout++] = tmp2[3] = x3 + j3 | 0; - B5[bout++] = tmp2[4] = x4 + j4 | 0; - B5[bout++] = tmp2[5] = x5 + j5 | 0; - B5[bout++] = tmp2[6] = x6 + j6 | 0; - B5[bout++] = tmp2[7] = x7 + j7 | 0; - B5[bout++] = tmp2[8] = x8 + j8 | 0; - B5[bout++] = tmp2[9] = x9 + j9 | 0; - B5[bout++] = tmp2[10] = x10 + j10 | 0; - B5[bout++] = tmp2[11] = x11 + j11 | 0; - B5[bout++] = tmp2[12] = x12 + j12 | 0; - B5[bout++] = tmp2[13] = x13 + j13 | 0; - B5[bout++] = tmp2[14] = x14 + j14 | 0; - B5[bout++] = tmp2[15] = x15 + j15 | 0; + B4[bout++] = tmp2[0] = x0 + j0 | 0; + B4[bout++] = tmp2[1] = x1 + j1 | 0; + B4[bout++] = tmp2[2] = x22 + j2 | 0; + B4[bout++] = tmp2[3] = x3 + j3 | 0; + B4[bout++] = tmp2[4] = x4 + j4 | 0; + B4[bout++] = tmp2[5] = x5 + j5 | 0; + B4[bout++] = tmp2[6] = x6 + j6 | 0; + B4[bout++] = tmp2[7] = x7 + j7 | 0; + B4[bout++] = tmp2[8] = x8 + j8 | 0; + B4[bout++] = tmp2[9] = x9 + j9 | 0; + B4[bout++] = tmp2[10] = x10 + j10 | 0; + B4[bout++] = tmp2[11] = x11 + j11 | 0; + B4[bout++] = tmp2[12] = x12 + j12 | 0; + B4[bout++] = tmp2[13] = x13 + j13 | 0; + B4[bout++] = tmp2[14] = x14 + j14 | 0; + B4[bout++] = tmp2[15] = x15 + j15 | 0; } function blockCopy(dst, di, src2, si, len) { while (len--) dst[di++] = src2[si++]; @@ -20356,15 +20363,15 @@ var require_scrypt_async = __commonJS({ function blockXOR(dst, di, src2, si, len) { while (len--) dst[di++] ^= src2[si++]; } - function blockMix(tmp2, B5, bin, bout, r2) { - blockCopy(tmp2, 0, B5, bin + (2 * r2 - 1) * 16, 16); + function blockMix(tmp2, B4, bin, bout, r2) { + blockCopy(tmp2, 0, B4, bin + (2 * r2 - 1) * 16, 16); for (var i2 = 0; i2 < 2 * r2; i2 += 2) { - salsaXOR(tmp2, B5, bin + i2 * 16, bout + i2 * 8); - salsaXOR(tmp2, B5, bin + i2 * 16 + 16, bout + i2 * 8 + r2 * 16); + salsaXOR(tmp2, B4, bin + i2 * 16, bout + i2 * 8); + salsaXOR(tmp2, B4, bin + i2 * 16 + 16, bout + i2 * 8 + r2 * 16); } } - function integerify(B5, bi, r2) { - return B5[bi + (2 * r2 - 1) * 16]; + function integerify(B4, bi, r2) { + return B4[bi + (2 * r2 - 1) * 16]; } function stringToUTF8Bytes(s) { var arr = []; @@ -20454,8 +20461,8 @@ var require_scrypt_async = __commonJS({ throw new Error("scrypt: invalid r"); if (logN < 1 || logN > 31) throw new Error("scrypt: logN must be between 1 and 31"); - var N11 = 1 << logN >>> 0, XY, V, B4, tmp; - if (r * p >= 1 << 30 || r > MAX_UINT / 128 / p || r > MAX_UINT / 256 || N11 > MAX_UINT / 128 / r) + var N10 = 1 << logN >>> 0, XY, V, B3, tmp; + if (r * p >= 1 << 30 || r > MAX_UINT / 128 / p || r > MAX_UINT / 256 || N10 > MAX_UINT / 128 / r) throw new Error("scrypt: parameters are too large"); if (typeof password === "string") password = stringToUTF8Bytes(password); @@ -20463,19 +20470,19 @@ var require_scrypt_async = __commonJS({ salt = stringToUTF8Bytes(salt); if (typeof Int32Array !== "undefined") { XY = new Int32Array(64 * r); - V = new Int32Array(32 * N11 * r); + V = new Int32Array(32 * N10 * r); tmp = new Int32Array(16); } else { XY = []; V = []; tmp = new Array(16); } - B4 = PBKDF2_HMAC_SHA256_OneIter(password, salt, p * 128 * r); + B3 = PBKDF2_HMAC_SHA256_OneIter(password, salt, p * 128 * r); var xi = 0, yi = 32 * r; function smixStart(pos) { for (var i2 = 0; i2 < 32 * r; i2++) { var j = pos + i2 * 4; - XY[xi + i2] = (B4[j + 3] & 255) << 24 | (B4[j + 2] & 255) << 16 | (B4[j + 1] & 255) << 8 | (B4[j + 0] & 255) << 0; + XY[xi + i2] = (B3[j + 3] & 255) << 24 | (B3[j + 2] & 255) << 16 | (B3[j + 1] & 255) << 8 | (B3[j + 0] & 255) << 0; } } function smixStep1(start, end) { @@ -20488,10 +20495,10 @@ var require_scrypt_async = __commonJS({ } function smixStep2(start, end) { for (var i2 = start; i2 < end; i2 += 2) { - var j = integerify(XY, xi, r) & N11 - 1; + var j = integerify(XY, xi, r) & N10 - 1; blockXOR(XY, xi, V, j * (32 * r), 32 * r); blockMix(tmp, XY, xi, yi, r); - j = integerify(XY, yi, r) & N11 - 1; + j = integerify(XY, yi, r) & N10 - 1; blockXOR(XY, yi, V, j * (32 * r), 32 * r); blockMix(tmp, XY, yi, xi, r); } @@ -20499,10 +20506,10 @@ var require_scrypt_async = __commonJS({ function smixFinish(pos) { for (var i2 = 0; i2 < 32 * r; i2++) { var j = XY[xi + i2]; - B4[pos + i2 * 4 + 0] = j >>> 0 & 255; - B4[pos + i2 * 4 + 1] = j >>> 8 & 255; - B4[pos + i2 * 4 + 2] = j >>> 16 & 255; - B4[pos + i2 * 4 + 3] = j >>> 24 & 255; + B3[pos + i2 * 4 + 0] = j >>> 0 & 255; + B3[pos + i2 * 4 + 1] = j >>> 8 & 255; + B3[pos + i2 * 4 + 2] = j >>> 16 & 255; + B3[pos + i2 * 4 + 3] = j >>> 24 & 255; } } var nextTick = typeof setImmediate !== "undefined" ? setImmediate : setTimeout; @@ -20519,7 +20526,7 @@ var require_scrypt_async = __commonJS({ })(); } function getResult(enc) { - var result = PBKDF2_HMAC_SHA256_OneIter(password, B4, dkLen); + var result = PBKDF2_HMAC_SHA256_OneIter(password, B3, dkLen); if (enc === "base64") return bytesToBase64(result); else if (enc === "hex") @@ -20532,16 +20539,16 @@ var require_scrypt_async = __commonJS({ function calculateSync() { for (var i2 = 0; i2 < p; i2++) { smixStart(i2 * 128 * r); - smixStep1(0, N11); - smixStep2(0, N11); + smixStep1(0, N10); + smixStep2(0, N10); smixFinish(i2 * 128 * r); } callback(getResult(encoding)); } function calculateAsync(i2) { smixStart(i2 * 128 * r); - interruptedFor(0, N11, interruptStep * 2, smixStep1, function() { - interruptedFor(0, N11, interruptStep * 2, smixStep2, function() { + interruptedFor(0, N10, interruptStep * 2, smixStep1, function() { + interruptedFor(0, N10, interruptStep * 2, smixStep2, function() { smixFinish(i2 * 128 * r); if (i2 + 1 < p) { nextTick(function() { @@ -21859,7 +21866,7 @@ var require_nacl_fast = __commonJS({ crypto_box_beforenm(k, y, x3); return crypto_box_open_afternm(m3, c, d, n, k); } - var K3 = [ + var K2 = [ 1116352408, 3609767458, 1899447441, @@ -22066,8 +22073,8 @@ var require_nacl_fast = __commonJS({ b += l >>> 16; c += h2 & 65535; d += h2 >>> 16; - h2 = K3[i2 * 2]; - l = K3[i2 * 2 + 1]; + h2 = K2[i2 * 2]; + l = K2[i2 * 2 + 1]; a += l & 65535; b += l >>> 16; c += h2 & 65535; @@ -22764,22 +22771,22 @@ var require_nacl_fast = __commonJS({ randombytes = fn; }; (function() { - var crypto2 = typeof self !== "undefined" ? self.crypto || self.msCrypto : null; - if (crypto2 && crypto2.getRandomValues) { + var crypto3 = typeof self !== "undefined" ? self.crypto || self.msCrypto : null; + if (crypto3 && crypto3.getRandomValues) { var QUOTA = 65536; nacl4.setPRNG(function(x3, n) { var i2, v2 = new Uint8Array(n); for (i2 = 0; i2 < n; i2 += QUOTA) { - crypto2.getRandomValues(v2.subarray(i2, i2 + Math.min(n - i2, QUOTA))); + crypto3.getRandomValues(v2.subarray(i2, i2 + Math.min(n - i2, QUOTA))); } for (i2 = 0; i2 < n; i2++) x3[i2] = v2[i2]; cleanup(v2); }); } else if (typeof __require2 !== "undefined") { - crypto2 = __require2("crypto"); - if (crypto2 && crypto2.randomBytes) { + crypto3 = __require2("crypto"); + if (crypto3 && crypto3.randomBytes) { nacl4.setPRNG(function(x3, n) { - var i2, v2 = crypto2.randomBytes(n); + var i2, v2 = crypto3.randomBytes(n); for (i2 = 0; i2 < n; i2++) x3[i2] = v2[i2]; cleanup(v2); }); @@ -24417,9 +24424,9 @@ async function* g(a, s, r) { o2.push(`${f}: ${p}`); }); e2.parts || !e2.body ? o2.push("") : o2.push("", ""); - let B4 = d.encode(o2.join(`\r + let B3 = d.encode(o2.join(`\r `)); - o2.length = 0, await u(B4).pipeTo(r, i), yield; + o2.length = 0, await u(B3).pipeTo(r, i), yield; } if (e2.body) { if (e2.body instanceof ArrayBuffer || ArrayBuffer.isView(e2.body)) await u(e2.body).pipeTo(r, i); @@ -24507,8 +24514,8 @@ var R; var S; var init_decrypt = __esm({ "node_modules/.deno/@apeleghq+rfc8188@1.0.8/node_modules/@apeleghq/rfc8188/dist/decrypt.mjs"() { - v = async (n, T2, w4, L) => { - let u2 = await globalThis.crypto.subtle.importKey("raw", T2, "HKDF", false, ["deriveKey", "deriveBits"]), d = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: n.cek_info, salt: w4 }, u2, n.params, false, L), A2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: n.nonce_info, salt: w4 }, u2, n.nonce_length << 3); + v = async (n, T2, w3, L) => { + let u2 = await globalThis.crypto.subtle.importKey("raw", T2, "HKDF", false, ["deriveKey", "deriveBits"]), d = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: n.cek_info, salt: w3 }, u2, n.params, false, L), A2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: n.nonce_info, salt: w3 }, u2, n.nonce_length << 3); return [d, function* () { let s = new ArrayBuffer(n.nonce_length), e2 = new DataView(s), y = new Uint8Array(s), i2 = new Uint8Array(A2), b = 4294967295, f = (n.nonce_length >> 2) - 1, l = new Array(f).fill(0); for (; ; ) { @@ -24529,8 +24536,8 @@ var init_decrypt = __esm({ B = (n) => ArrayBuffer.isView(n) ? new Uint8Array(n.buffer).subarray(n.byteOffset, n.byteOffset + n.byteLength) : new Uint8Array(n); m2 = B; o = { salt: {}, recordSize: {}, keyIdLen: {}, keyId: {}, payload: {}, done: {} }; - R = (n, T2, w4, L) => { - let u2 = new Uint8Array(16), d, A2, E3, s = 0, e2 = 0, y = new Uint8Array(256), i2 = o.salt, b = new TransformStream({ start: () => { + R = (n, T2, w3, L) => { + let u2 = new Uint8Array(16), d, A2, E2, s = 0, e2 = 0, y = new Uint8Array(256), i2 = o.salt, b = new TransformStream({ start: () => { }, transform: async (f, l) => { let a = m2(f), t = 0; for (; t < f.byteLength; ) switch (i2) { @@ -24558,10 +24565,10 @@ var init_decrypt = __esm({ case o.keyId: { let r = a.subarray(t, t + y[0] - e2); if (y.set(r, 1 + e2), e2 += r.byteLength, t += r.byteLength, e2 === y[0]) { - let g2 = await w4(y.subarray(1, 1 + y[0])); - w4 = void 0; + let g2 = await w3(y.subarray(1, 1 + y[0])); + w3 = void 0; let h2 = await I(n, g2, u2, ["decrypt"]); - A2 = h2[0], E3 = h2[1], d = new Uint8Array(s), e2 = 0, i2 = o.payload; + A2 = h2[0], E2 = h2[1], d = new Uint8Array(s), e2 = 0, i2 = o.payload; continue; } break; @@ -24569,7 +24576,7 @@ var init_decrypt = __esm({ case o.payload: { let r = a.subarray(t, t + s - e2); if (d.set(r, e2), e2 += r.byteLength, t += r.byteLength, e2 === s) { - let h2 = E3.next().value, c = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: h2, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), p = c.byteLength - 1; + let h2 = E2.next().value, c = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: h2, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), p = c.byteLength - 1; for (; p > 0 && c[p] === 0; p--) ; if (c[p] === 2) { if (t !== f.byteLength) throw new Error("Unexpected terminal padding delimiter"); @@ -24589,7 +24596,7 @@ var init_decrypt = __esm({ return; case o.payload: { if (e2 < 1 + n.tag_length) throw new Error("Unexpected end of data"); - let a = E3.next().value, t = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: a, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), r = t.byteLength - 1; + let a = E2.next().value, t = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: a, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), r = t.byteLength - 1; for (; r > 0 && t[r] === 0; r--) ; if (t[r] !== 2) throw new Error("Unexpected non-terminal padding delimiter"); f.enqueue(t.buffer.slice(0, r)), t.fill(0); @@ -24604,9 +24611,15 @@ var init_decrypt = __esm({ S = R; } }); +var x2; var e; var init_encodings = __esm({ "node_modules/.deno/@apeleghq+rfc8188@1.0.8/node_modules/@apeleghq/rfc8188/dist/encodings.mjs"() { + x2 = { params: { name: "AES-GCM", length: 128 }, get cek_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 49, 50, 56, 103, 99, 109, 0]); + }, get nonce_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); + }, block_size: 16, tag_length: 16, nonce_length: 12 }; e = { params: { name: "AES-GCM", length: 256 }, get cek_info() { return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 50, 53, 54, 103, 99, 109, 0]); }, get nonce_info() { @@ -27705,10 +27718,10 @@ var init_internals = __esm({ }; const actionsOpV = msg.reduce(reducer, []); return Promise.allSettled(actionsOpV.map((action) => callSideEffect(action))).then((results) => { - const errors = results.filter((r) => r.status === "rejected").map((r) => r.reason); - if (errors.length > 0) { - console.error("Side-effect errors", contractID, errors); - throw new AggregateError(errors, `Error at side effects for ${contractID}`); + const errors2 = results.filter((r) => r.status === "rejected").map((r) => r.reason); + if (errors2.length > 0) { + console.error("Side-effect errors", contractID, errors2); + throw new AggregateError(errors2, `Error at side effects for ${contractID}`); } }); }, @@ -29530,1407 +29543,6 @@ var init_chelonia = __esm({ esm_default("sbp/domains/lock", ["chelonia"]); } }); -var require_assertError = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/assertError.js"(exports2, module14) { - "use strict"; - module14.exports = class AssertError extends Error { - name = "AssertError"; - constructor(message, ctor) { - super(message || "Unknown error"); - if (typeof Error.captureStackTrace === "function") { - Error.captureStackTrace(this, ctor); - } - } - }; - } -}); -var require_stringify = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/stringify.js"(exports2, module14) { - "use strict"; - module14.exports = function(...args) { - try { - return JSON.stringify(...args); - } catch (err) { - return "[Cannot display object: " + err.message + "]"; - } - }; - } -}); -var require_assert = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/assert.js"(exports2, module14) { - "use strict"; - var AssertError = require_assertError(); - var Stringify = require_stringify(); - var assert2 = module14.exports = function(condition, ...args) { - if (condition) { - return; - } - if (args.length === 1 && args[0] instanceof Error) { - throw args[0]; - } - const msgs = args.filter((arg) => arg !== "").map((arg) => { - return typeof arg === "string" ? arg : arg instanceof Error ? arg.message : Stringify(arg); - }); - throw new AssertError(msgs.join(" "), assert2); - }; - } -}); -var require_reach = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/reach.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var internals = {}; - module14.exports = function(obj, chain, options2) { - if (chain === false || chain === null || chain === void 0) { - return obj; - } - options2 = options2 || {}; - if (typeof options2 === "string") { - options2 = { separator: options2 }; - } - const isChainArray = Array.isArray(chain); - Assert(!isChainArray || !options2.separator, "Separator option is not valid for array-based chain"); - const path8 = isChainArray ? chain : chain.split(options2.separator || "."); - let ref = obj; - for (let i2 = 0; i2 < path8.length; ++i2) { - let key = path8[i2]; - const type = options2.iterables && internals.iterables(ref); - if (Array.isArray(ref) || type === "set") { - const number3 = Number(key); - if (Number.isInteger(number3)) { - key = number3 < 0 ? ref.length + number3 : number3; - } - } - if (!ref || typeof ref === "function" && options2.functions === false || // Defaults to true - !type && ref[key] === void 0) { - Assert(!options2.strict || i2 + 1 === path8.length, "Missing segment", key, "in reach path ", chain); - Assert(typeof ref === "object" || options2.functions === true || typeof ref !== "function", "Invalid segment", key, "in reach path ", chain); - ref = options2.default; - break; - } - if (!type) { - ref = ref[key]; - } else if (type === "set") { - ref = [...ref][key]; - } else { - ref = ref.get(key); - } - } - return ref; - }; - internals.iterables = function(ref) { - if (ref instanceof Set) { - return "set"; - } - if (ref instanceof Map) { - return "map"; - } - }; - } -}); -var require_types = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/types.js"(exports2, module14) { - "use strict"; - var internals = {}; - exports2 = module14.exports = { - array: Array.prototype, - buffer: Buffer && Buffer.prototype, - // $lab:coverage:ignore$ - date: Date.prototype, - error: Error.prototype, - generic: Object.prototype, - map: Map.prototype, - promise: Promise.prototype, - regex: RegExp.prototype, - set: Set.prototype, - url: URL.prototype, - weakMap: WeakMap.prototype, - weakSet: WeakSet.prototype - }; - internals.typeMap = /* @__PURE__ */ new Map([ - ["[object Error]", exports2.error], - ["[object Map]", exports2.map], - ["[object Promise]", exports2.promise], - ["[object Set]", exports2.set], - ["[object URL]", exports2.url], - ["[object WeakMap]", exports2.weakMap], - ["[object WeakSet]", exports2.weakSet] - ]); - exports2.getInternalProto = function(obj) { - if (Array.isArray(obj)) { - return exports2.array; - } - if (Buffer && obj instanceof Buffer) { - return exports2.buffer; - } - if (obj instanceof Date) { - return exports2.date; - } - if (obj instanceof RegExp) { - return exports2.regex; - } - if (obj instanceof Error) { - return exports2.error; - } - const objName = Object.prototype.toString.call(obj); - return internals.typeMap.get(objName) || exports2.generic; - }; - } -}); -var require_utils = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/utils.js"(exports2) { - "use strict"; - exports2.keys = function(obj, options2 = {}) { - return options2.symbols !== false ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj); - }; - } -}); -var require_clone = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/clone.js"(exports2, module14) { - "use strict"; - var Reach = require_reach(); - var Types = require_types(); - var Utils = require_utils(); - var internals = { - needsProtoHack: /* @__PURE__ */ new Set([Types.set, Types.map, Types.weakSet, Types.weakMap]), - structuredCloneExists: typeof structuredClone === "function" - }; - module14.exports = internals.clone = function(obj, options2 = {}, _seen = null) { - if (typeof obj !== "object" || obj === null) { - return obj; - } - let clone2 = internals.clone; - let seen = _seen; - if (options2.shallow) { - if (options2.shallow !== true) { - return internals.cloneWithShallow(obj, options2); - } - clone2 = (value) => value; - } else if (seen) { - const lookup = seen.get(obj); - if (lookup) { - return lookup; - } - } else { - seen = /* @__PURE__ */ new Map(); - } - const baseProto = Types.getInternalProto(obj); - switch (baseProto) { - case Types.buffer: - return Buffer?.from(obj); - case Types.date: - return new Date(obj.getTime()); - case Types.regex: - case Types.url: - return new baseProto.constructor(obj); - } - const newObj = internals.base(obj, baseProto, options2); - if (newObj === obj) { - return obj; - } - if (seen) { - seen.set(obj, newObj); - } - if (baseProto === Types.set) { - for (const value of obj) { - newObj.add(clone2(value, options2, seen)); - } - } else if (baseProto === Types.map) { - for (const [key, value] of obj) { - newObj.set(key, clone2(value, options2, seen)); - } - } - const keys = Utils.keys(obj, options2); - for (const key of keys) { - if (key === "__proto__") { - continue; - } - if (baseProto === Types.array && key === "length") { - newObj.length = obj.length; - continue; - } - if (internals.structuredCloneExists && baseProto === Types.error && key === "stack") { - continue; - } - const descriptor = Object.getOwnPropertyDescriptor(obj, key); - if (descriptor) { - if (descriptor.get || descriptor.set) { - Object.defineProperty(newObj, key, descriptor); - } else if (descriptor.enumerable) { - newObj[key] = clone2(obj[key], options2, seen); - } else { - Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone2(obj[key], options2, seen) }); - } - } else { - Object.defineProperty(newObj, key, { - enumerable: true, - writable: true, - configurable: true, - value: clone2(obj[key], options2, seen) - }); - } - } - return newObj; - }; - internals.cloneWithShallow = function(source, options2) { - const keys = options2.shallow; - options2 = Object.assign({}, options2); - options2.shallow = false; - const seen = /* @__PURE__ */ new Map(); - for (const key of keys) { - const ref = Reach(source, key); - if (typeof ref === "object" || typeof ref === "function") { - seen.set(ref, ref); - } - } - return internals.clone(source, options2, seen); - }; - internals.base = function(obj, baseProto, options2) { - if (options2.prototype === false) { - if (internals.needsProtoHack.has(baseProto)) { - return new baseProto.constructor(); - } - return baseProto === Types.array ? [] : {}; - } - const proto3 = Object.getPrototypeOf(obj); - if (proto3 && proto3.isImmutable) { - return obj; - } - if (baseProto === Types.array) { - const newObj = []; - if (proto3 !== baseProto) { - Object.setPrototypeOf(newObj, proto3); - } - return newObj; - } else if (baseProto === Types.error && internals.structuredCloneExists && (proto3 === baseProto || Error.isPrototypeOf(proto3.constructor))) { - const err = structuredClone(obj); - if (Object.getPrototypeOf(err) !== proto3) { - Object.setPrototypeOf(err, proto3); - } - return err; - } - if (internals.needsProtoHack.has(baseProto)) { - const newObj = new proto3.constructor(); - if (proto3 !== baseProto) { - Object.setPrototypeOf(newObj, proto3); - } - return newObj; - } - return Object.create(proto3); - }; - } -}); -var require_merge = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/merge.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Utils = require_utils(); - var internals = {}; - module14.exports = internals.merge = function(target, source, options2) { - Assert(target && typeof target === "object", "Invalid target value: must be an object"); - Assert(source === null || source === void 0 || typeof source === "object", "Invalid source value: must be null, undefined, or an object"); - if (!source) { - return target; - } - options2 = Object.assign({ nullOverride: true, mergeArrays: true }, options2); - if (Array.isArray(source)) { - Assert(Array.isArray(target), "Cannot merge array onto an object"); - if (!options2.mergeArrays) { - target.length = 0; - } - for (let i2 = 0; i2 < source.length; ++i2) { - target.push(Clone(source[i2], { symbols: options2.symbols })); - } - return target; - } - const keys = Utils.keys(source, options2); - for (let i2 = 0; i2 < keys.length; ++i2) { - const key = keys[i2]; - if (key === "__proto__" || !Object.prototype.propertyIsEnumerable.call(source, key)) { - continue; - } - const value = source[key]; - if (value && typeof value === "object") { - if (target[key] === value) { - continue; - } - if (!target[key] || typeof target[key] !== "object" || Array.isArray(target[key]) !== Array.isArray(value) || value instanceof Date || Buffer && Buffer.isBuffer(value) || // $lab:coverage:ignore$ - value instanceof RegExp) { - target[key] = Clone(value, { symbols: options2.symbols }); - } else { - internals.merge(target[key], value, options2); - } - } else { - if (value !== null && value !== void 0) { - target[key] = value; - } else if (options2.nullOverride) { - target[key] = value; - } - } - } - return target; - }; - } -}); -var require_applyToDefaults = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/applyToDefaults.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Merge = require_merge(); - var Reach = require_reach(); - var internals = {}; - module14.exports = function(defaults, source, options2 = {}) { - Assert(defaults && typeof defaults === "object", "Invalid defaults value: must be an object"); - Assert(!source || source === true || typeof source === "object", "Invalid source value: must be true, falsy or an object"); - Assert(typeof options2 === "object", "Invalid options: must be an object"); - if (!source) { - return null; - } - if (options2.shallow) { - return internals.applyToDefaultsWithShallow(defaults, source, options2); - } - const copy2 = Clone(defaults); - if (source === true) { - return copy2; - } - const nullOverride = options2.nullOverride !== void 0 ? options2.nullOverride : false; - return Merge(copy2, source, { nullOverride, mergeArrays: false }); - }; - internals.applyToDefaultsWithShallow = function(defaults, source, options2) { - const keys = options2.shallow; - Assert(Array.isArray(keys), "Invalid keys"); - const seen = /* @__PURE__ */ new Map(); - const merge3 = source === true ? null : /* @__PURE__ */ new Set(); - for (let key of keys) { - key = Array.isArray(key) ? key : key.split("."); - const ref = Reach(defaults, key); - if (ref && typeof ref === "object") { - seen.set(ref, merge3 && Reach(source, key) || ref); - } else if (merge3) { - merge3.add(key); - } - } - const copy2 = Clone(defaults, {}, seen); - if (!merge3) { - return copy2; - } - for (const key of merge3) { - internals.reachCopy(copy2, source, key); - } - const nullOverride = options2.nullOverride !== void 0 ? options2.nullOverride : false; - return Merge(copy2, source, { nullOverride, mergeArrays: false }); - }; - internals.reachCopy = function(dst, src2, path8) { - for (const segment of path8) { - if (!(segment in src2)) { - return; - } - const val = src2[segment]; - if (typeof val !== "object" || val === null) { - return; - } - src2 = val; - } - const value = src2; - let ref = dst; - for (let i2 = 0; i2 < path8.length - 1; ++i2) { - const segment = path8[i2]; - if (typeof ref[segment] !== "object") { - ref[segment] = {}; - } - ref = ref[segment]; - } - ref[path8[path8.length - 1]] = value; - }; - } -}); -var require_bench = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/bench.js"(exports2, module14) { - "use strict"; - var internals = {}; - module14.exports = internals.Bench = class { - constructor() { - this.ts = 0; - this.reset(); - } - reset() { - this.ts = internals.Bench.now(); - } - elapsed() { - return internals.Bench.now() - this.ts; - } - static now() { - const ts = process.hrtime(); - return ts[0] * 1e3 + ts[1] / 1e6; - } - }; - } -}); -var require_ignore = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/ignore.js"(exports2, module14) { - "use strict"; - module14.exports = function() { - }; - } -}); -var require_block = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/block.js"(exports2, module14) { - "use strict"; - var Ignore = require_ignore(); - module14.exports = function() { - return new Promise(Ignore); - }; - } -}); -var require_deepEqual = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/deepEqual.js"(exports2, module14) { - "use strict"; - var Types = require_types(); - var internals = { - mismatched: null - }; - module14.exports = function(obj, ref, options2) { - options2 = Object.assign({ prototype: true }, options2); - return !!internals.isDeepEqual(obj, ref, options2, []); - }; - internals.isDeepEqual = function(obj, ref, options2, seen) { - if (obj === ref) { - return obj !== 0 || 1 / obj === 1 / ref; - } - const type = typeof obj; - if (type !== typeof ref) { - return false; - } - if (obj === null || ref === null) { - return false; - } - if (type === "function") { - if (!options2.deepFunction || obj.toString() !== ref.toString()) { - return false; - } - } else if (type !== "object") { - return obj !== obj && ref !== ref; - } - const instanceType = internals.getSharedType(obj, ref, !!options2.prototype); - switch (instanceType) { - case Types.buffer: - return Buffer && Buffer.prototype.equals.call(obj, ref); - // $lab:coverage:ignore$ - case Types.promise: - return obj === ref; - case Types.regex: - case Types.url: - return obj.toString() === ref.toString(); - case internals.mismatched: - return false; - } - for (let i2 = seen.length - 1; i2 >= 0; --i2) { - if (seen[i2].isSame(obj, ref)) { - return true; - } - } - seen.push(new internals.SeenEntry(obj, ref)); - try { - return !!internals.isDeepEqualObj(instanceType, obj, ref, options2, seen); - } finally { - seen.pop(); - } - }; - internals.getSharedType = function(obj, ref, checkPrototype) { - if (checkPrototype) { - if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) { - return internals.mismatched; - } - return Types.getInternalProto(obj); - } - const type = Types.getInternalProto(obj); - if (type !== Types.getInternalProto(ref)) { - return internals.mismatched; - } - return type; - }; - internals.valueOf = function(obj) { - const objValueOf = obj.valueOf; - if (objValueOf === void 0) { - return obj; - } - try { - return objValueOf.call(obj); - } catch (err) { - return err; - } - }; - internals.hasOwnEnumerableProperty = function(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); - }; - internals.isSetSimpleEqual = function(obj, ref) { - for (const entry of Set.prototype.values.call(obj)) { - if (!Set.prototype.has.call(ref, entry)) { - return false; - } - } - return true; - }; - internals.isDeepEqualObj = function(instanceType, obj, ref, options2, seen) { - const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals; - const { keys, getOwnPropertySymbols } = Object; - if (instanceType === Types.array) { - if (options2.part) { - for (const objValue of obj) { - for (const refValue of ref) { - if (isDeepEqual(objValue, refValue, options2, seen)) { - return true; - } - } - } - } else { - if (obj.length !== ref.length) { - return false; - } - for (let i2 = 0; i2 < obj.length; ++i2) { - if (!isDeepEqual(obj[i2], ref[i2], options2, seen)) { - return false; - } - } - return true; - } - } else if (instanceType === Types.set) { - if (obj.size !== ref.size) { - return false; - } - if (!internals.isSetSimpleEqual(obj, ref)) { - const ref2 = new Set(Set.prototype.values.call(ref)); - for (const objEntry of Set.prototype.values.call(obj)) { - if (ref2.delete(objEntry)) { - continue; - } - let found = false; - for (const refEntry of ref2) { - if (isDeepEqual(objEntry, refEntry, options2, seen)) { - ref2.delete(refEntry); - found = true; - break; - } - } - if (!found) { - return false; - } - } - } - } else if (instanceType === Types.map) { - if (obj.size !== ref.size) { - return false; - } - for (const [key, value] of Map.prototype.entries.call(obj)) { - if (value === void 0 && !Map.prototype.has.call(ref, key)) { - return false; - } - if (!isDeepEqual(value, Map.prototype.get.call(ref, key), options2, seen)) { - return false; - } - } - } else if (instanceType === Types.error) { - if (obj.name !== ref.name || obj.message !== ref.message) { - return false; - } - } - const valueOfObj = valueOf(obj); - const valueOfRef = valueOf(ref); - if ((obj !== valueOfObj || ref !== valueOfRef) && !isDeepEqual(valueOfObj, valueOfRef, options2, seen)) { - return false; - } - const objKeys = keys(obj); - if (!options2.part && objKeys.length !== keys(ref).length && !options2.skip) { - return false; - } - let skipped = 0; - for (const key of objKeys) { - if (options2.skip && options2.skip.includes(key)) { - if (ref[key] === void 0) { - ++skipped; - } - continue; - } - if (!hasOwnEnumerableProperty(ref, key)) { - return false; - } - if (!isDeepEqual(obj[key], ref[key], options2, seen)) { - return false; - } - } - if (!options2.part && objKeys.length - skipped !== keys(ref).length) { - return false; - } - if (options2.symbols !== false) { - const objSymbols = getOwnPropertySymbols(obj); - const refSymbols = new Set(getOwnPropertySymbols(ref)); - for (const key of objSymbols) { - if (!options2.skip?.includes(key)) { - if (hasOwnEnumerableProperty(obj, key)) { - if (!hasOwnEnumerableProperty(ref, key)) { - return false; - } - if (!isDeepEqual(obj[key], ref[key], options2, seen)) { - return false; - } - } else if (hasOwnEnumerableProperty(ref, key)) { - return false; - } - } - refSymbols.delete(key); - } - for (const key of refSymbols) { - if (hasOwnEnumerableProperty(ref, key)) { - return false; - } - } - } - return true; - }; - internals.SeenEntry = class { - constructor(obj, ref) { - this.obj = obj; - this.ref = ref; - } - isSame(obj, ref) { - return this.obj === obj && this.ref === ref; - } - }; - } -}); -var require_escapeRegex = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/escapeRegex.js"(exports2, module14) { - "use strict"; - module14.exports = function(string3) { - return string3.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, "\\$&"); - }; - } -}); -var require_contain = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/contain.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var DeepEqual = require_deepEqual(); - var EscapeRegex = require_escapeRegex(); - var Utils = require_utils(); - var internals = {}; - module14.exports = function(ref, values, options2 = {}) { - if (typeof values !== "object") { - values = [values]; - } - Assert(!Array.isArray(values) || values.length, "Values array cannot be empty"); - if (typeof ref === "string") { - return internals.string(ref, values, options2); - } - if (Array.isArray(ref)) { - return internals.array(ref, values, options2); - } - Assert(typeof ref === "object", "Reference must be string or an object"); - return internals.object(ref, values, options2); - }; - internals.array = function(ref, values, options2) { - if (!Array.isArray(values)) { - values = [values]; - } - if (!ref.length) { - return false; - } - if (options2.only && options2.once && ref.length !== values.length) { - return false; - } - let compare; - const map = /* @__PURE__ */ new Map(); - for (const value of values) { - if (!options2.deep || !value || typeof value !== "object") { - const existing = map.get(value); - if (existing) { - ++existing.allowed; - } else { - map.set(value, { allowed: 1, hits: 0 }); - } - } else { - compare = compare ?? internals.compare(options2); - let found = false; - for (const [key, existing] of map.entries()) { - if (compare(key, value)) { - ++existing.allowed; - found = true; - break; - } - } - if (!found) { - map.set(value, { allowed: 1, hits: 0 }); - } - } - } - let hits = 0; - for (const item of ref) { - let match; - if (!options2.deep || !item || typeof item !== "object") { - match = map.get(item); - } else { - compare = compare ?? internals.compare(options2); - for (const [key, existing] of map.entries()) { - if (compare(key, item)) { - match = existing; - break; - } - } - } - if (match) { - ++match.hits; - ++hits; - if (options2.once && match.hits > match.allowed) { - return false; - } - } - } - if (options2.only && hits !== ref.length) { - return false; - } - for (const match of map.values()) { - if (match.hits === match.allowed) { - continue; - } - if (match.hits < match.allowed && !options2.part) { - return false; - } - } - return !!hits; - }; - internals.object = function(ref, values, options2) { - Assert(options2.once === void 0, "Cannot use option once with object"); - const keys = Utils.keys(ref, options2); - if (!keys.length) { - return false; - } - if (Array.isArray(values)) { - return internals.array(keys, values, options2); - } - const symbols2 = Object.getOwnPropertySymbols(values).filter((sym) => values.propertyIsEnumerable(sym)); - const targets = [...Object.keys(values), ...symbols2]; - const compare = internals.compare(options2); - const set = new Set(targets); - for (const key of keys) { - if (!set.has(key)) { - if (options2.only) { - return false; - } - continue; - } - if (!compare(values[key], ref[key])) { - return false; - } - set.delete(key); - } - if (set.size) { - return options2.part ? set.size < targets.length : false; - } - return true; - }; - internals.string = function(ref, values, options2) { - if (ref === "") { - return values.length === 1 && values[0] === "" || // '' contains '' - !options2.once && !values.some((v2) => v2 !== ""); - } - const map = /* @__PURE__ */ new Map(); - const patterns = []; - for (const value of values) { - Assert(typeof value === "string", "Cannot compare string reference to non-string value"); - if (value) { - const existing = map.get(value); - if (existing) { - ++existing.allowed; - } else { - map.set(value, { allowed: 1, hits: 0 }); - patterns.push(EscapeRegex(value)); - } - } else if (options2.once || options2.only) { - return false; - } - } - if (!patterns.length) { - return true; - } - const regex = new RegExp(`(${patterns.join("|")})`, "g"); - const leftovers = ref.replace(regex, ($0, $1) => { - ++map.get($1).hits; - return ""; - }); - if (options2.only && leftovers) { - return false; - } - let any = false; - for (const match of map.values()) { - if (match.hits) { - any = true; - } - if (match.hits === match.allowed) { - continue; - } - if (match.hits < match.allowed && !options2.part) { - return false; - } - if (options2.once) { - return false; - } - } - return !!any; - }; - internals.compare = function(options2) { - if (!options2.deep) { - return internals.shallow; - } - const hasOnly = options2.only !== void 0; - const hasPart = options2.part !== void 0; - const flags = { - prototype: hasOnly ? options2.only : hasPart ? !options2.part : false, - part: hasOnly ? !options2.only : hasPart ? options2.part : false - }; - return (a, b) => DeepEqual(a, b, flags); - }; - internals.shallow = function(a, b) { - return a === b; - }; - } -}); -var require_escapeHeaderAttribute = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - module14.exports = function(attribute) { - Assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), "Bad attribute value (" + attribute + ")"); - return attribute.replace(/\\/g, "\\\\").replace(/\"/g, '\\"'); - }; - } -}); -var require_escapeHtml = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/escapeHtml.js"(exports2, module14) { - "use strict"; - var internals = {}; - module14.exports = function(input) { - if (!input) { - return ""; - } - let escaped = ""; - for (let i2 = 0; i2 < input.length; ++i2) { - const charCode = input.charCodeAt(i2); - if (internals.isSafe(charCode)) { - escaped += input[i2]; - } else { - escaped += internals.escapeHtmlChar(charCode); - } - } - return escaped; - }; - internals.escapeHtmlChar = function(charCode) { - const namedEscape = internals.namedHtml.get(charCode); - if (namedEscape) { - return namedEscape; - } - if (charCode >= 256) { - return "&#" + charCode + ";"; - } - const hexValue = charCode.toString(16).padStart(2, "0"); - return `&#x${hexValue};`; - }; - internals.isSafe = function(charCode) { - return internals.safeCharCodes.has(charCode); - }; - internals.namedHtml = /* @__PURE__ */ new Map([ - [38, "&"], - [60, "<"], - [62, ">"], - [34, """], - [160, " "], - [162, "¢"], - [163, "£"], - [164, "¤"], - [169, "©"], - [174, "®"] - ]); - internals.safeCharCodes = function() { - const safe = /* @__PURE__ */ new Set(); - for (let i2 = 32; i2 < 123; ++i2) { - if (i2 >= 97 || // a-z - i2 >= 65 && i2 <= 90 || // A-Z - i2 >= 48 && i2 <= 57 || // 0-9 - i2 === 32 || // space - i2 === 46 || // . - i2 === 44 || // , - i2 === 45 || // - - i2 === 58 || // : - i2 === 95) { - safe.add(i2); - } - } - return safe; - }(); - } -}); -var require_escapeJson = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/escapeJson.js"(exports2, module14) { - "use strict"; - var internals = {}; - module14.exports = function(input) { - if (!input) { - return ""; - } - return input.replace(/[<>&\u2028\u2029]/g, internals.escape); - }; - internals.escape = function(char) { - return internals.replacements.get(char); - }; - internals.replacements = /* @__PURE__ */ new Map([ - ["<", "\\u003c"], - [">", "\\u003e"], - ["&", "\\u0026"], - ["\u2028", "\\u2028"], - ["\u2029", "\\u2029"] - ]); - } -}); -var require_flatten = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/flatten.js"(exports2, module14) { - "use strict"; - var internals = {}; - module14.exports = internals.flatten = function(array2, target) { - const result = target || []; - for (const entry of array2) { - if (Array.isArray(entry)) { - internals.flatten(entry, result); - } else { - result.push(entry); - } - } - return result; - }; - } -}); -var require_intersect = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/intersect.js"(exports2, module14) { - "use strict"; - var internals = {}; - module14.exports = function(array1, array2, options2 = {}) { - if (!array1 || !array2) { - return options2.first ? null : []; - } - const common4 = []; - const hash3 = Array.isArray(array1) ? new Set(array1) : array1; - const found = /* @__PURE__ */ new Set(); - for (const value of array2) { - if (internals.has(hash3, value) && !found.has(value)) { - if (options2.first) { - return value; - } - common4.push(value); - found.add(value); - } - } - return options2.first ? null : common4; - }; - internals.has = function(ref, key) { - if (typeof ref.has === "function") { - return ref.has(key); - } - return ref[key] !== void 0; - }; - } -}); -var require_isPromise = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/isPromise.js"(exports2, module14) { - "use strict"; - module14.exports = function(promise) { - return typeof promise?.then === "function"; - }; - } -}); -var require_once = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/once.js"(exports2, module14) { - "use strict"; - var internals = { - wrapped: Symbol("wrapped") - }; - module14.exports = function(method) { - if (method[internals.wrapped]) { - return method; - } - let once = false; - const wrappedFn = function(...args) { - if (!once) { - once = true; - method(...args); - } - }; - wrappedFn[internals.wrapped] = true; - return wrappedFn; - }; - } -}); -var require_reachTemplate = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/reachTemplate.js"(exports2, module14) { - "use strict"; - var Reach = require_reach(); - module14.exports = function(obj, template, options2) { - return template.replace(/{([^{}]+)}/g, ($0, chain) => { - const value = Reach(obj, chain, options2); - return value ?? ""; - }); - }; - } -}); -var require_wait = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/wait.js"(exports2, module14) { - "use strict"; - var internals = { - maxTimer: 2 ** 31 - 1 - // ~25 days - }; - module14.exports = function(timeout, returnValue, options2) { - if (typeof timeout === "bigint") { - timeout = Number(timeout); - } - if (timeout >= Number.MAX_SAFE_INTEGER) { - timeout = Infinity; - } - if (typeof timeout !== "number" && timeout !== void 0) { - throw new TypeError("Timeout must be a number or bigint"); - } - return new Promise((resolve82) => { - const _setTimeout = options2 ? options2.setTimeout : setTimeout; - const activate = () => { - const time3 = Math.min(timeout, internals.maxTimer); - timeout -= time3; - _setTimeout(() => timeout > 0 ? activate() : resolve82(returnValue), time3); - }; - if (timeout !== Infinity) { - activate(); - } - }); - }; - } -}); -var require_lib = __commonJS({ - "node_modules/.deno/@hapi+hoek@11.0.7/node_modules/@hapi/hoek/lib/index.js"(exports2) { - "use strict"; - exports2.applyToDefaults = require_applyToDefaults(); - exports2.assert = require_assert(); - exports2.AssertError = require_assertError(); - exports2.Bench = require_bench(); - exports2.block = require_block(); - exports2.clone = require_clone(); - exports2.contain = require_contain(); - exports2.deepEqual = require_deepEqual(); - exports2.escapeHeaderAttribute = require_escapeHeaderAttribute(); - exports2.escapeHtml = require_escapeHtml(); - exports2.escapeJson = require_escapeJson(); - exports2.escapeRegex = require_escapeRegex(); - exports2.flatten = require_flatten(); - exports2.ignore = require_ignore(); - exports2.intersect = require_intersect(); - exports2.isPromise = require_isPromise(); - exports2.merge = require_merge(); - exports2.once = require_once(); - exports2.reach = require_reach(); - exports2.reachTemplate = require_reachTemplate(); - exports2.stringify = require_stringify(); - exports2.wait = require_wait(); - } -}); -var require_lib2 = __commonJS({ - "node_modules/.deno/@hapi+boom@10.0.1/node_modules/@hapi/boom/lib/index.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var internals = { - codes: /* @__PURE__ */ new Map([ - [100, "Continue"], - [101, "Switching Protocols"], - [102, "Processing"], - [200, "OK"], - [201, "Created"], - [202, "Accepted"], - [203, "Non-Authoritative Information"], - [204, "No Content"], - [205, "Reset Content"], - [206, "Partial Content"], - [207, "Multi-Status"], - [300, "Multiple Choices"], - [301, "Moved Permanently"], - [302, "Moved Temporarily"], - [303, "See Other"], - [304, "Not Modified"], - [305, "Use Proxy"], - [307, "Temporary Redirect"], - [400, "Bad Request"], - [401, "Unauthorized"], - [402, "Payment Required"], - [403, "Forbidden"], - [404, "Not Found"], - [405, "Method Not Allowed"], - [406, "Not Acceptable"], - [407, "Proxy Authentication Required"], - [408, "Request Time-out"], - [409, "Conflict"], - [410, "Gone"], - [411, "Length Required"], - [412, "Precondition Failed"], - [413, "Request Entity Too Large"], - [414, "Request-URI Too Large"], - [415, "Unsupported Media Type"], - [416, "Requested Range Not Satisfiable"], - [417, "Expectation Failed"], - [418, "I'm a teapot"], - [422, "Unprocessable Entity"], - [423, "Locked"], - [424, "Failed Dependency"], - [425, "Too Early"], - [426, "Upgrade Required"], - [428, "Precondition Required"], - [429, "Too Many Requests"], - [431, "Request Header Fields Too Large"], - [451, "Unavailable For Legal Reasons"], - [500, "Internal Server Error"], - [501, "Not Implemented"], - [502, "Bad Gateway"], - [503, "Service Unavailable"], - [504, "Gateway Time-out"], - [505, "HTTP Version Not Supported"], - [506, "Variant Also Negotiates"], - [507, "Insufficient Storage"], - [509, "Bandwidth Limit Exceeded"], - [510, "Not Extended"], - [511, "Network Authentication Required"] - ]) - }; - exports2.Boom = class extends Error { - constructor(messageOrError, options2 = {}) { - if (messageOrError instanceof Error) { - return exports2.boomify(Hoek.clone(messageOrError), options2); - } - const { statusCode = 500, data = null, ctor = exports2.Boom } = options2; - const error2 = new Error(messageOrError ? messageOrError : void 0); - Error.captureStackTrace(error2, ctor); - error2.data = data; - const boom = internals.initialize(error2, statusCode); - Object.defineProperty(boom, "typeof", { value: ctor }); - if (options2.decorate) { - Object.assign(boom, options2.decorate); - } - return boom; - } - static [Symbol.hasInstance](instance) { - if (this === exports2.Boom) { - return exports2.isBoom(instance); - } - return this.prototype.isPrototypeOf(instance); - } - }; - exports2.isBoom = function(err, statusCode) { - return err instanceof Error && !!err.isBoom && (!statusCode || err.output.statusCode === statusCode); - }; - exports2.boomify = function(err, options2) { - Hoek.assert(err instanceof Error, "Cannot wrap non-Error object"); - options2 = options2 || {}; - if (options2.data !== void 0) { - err.data = options2.data; - } - if (options2.decorate) { - Object.assign(err, options2.decorate); - } - if (!err.isBoom) { - return internals.initialize(err, options2.statusCode ?? 500, options2.message); - } - if (options2.override === false || // Defaults to true - !options2.statusCode && !options2.message) { - return err; - } - return internals.initialize(err, options2.statusCode ?? err.output.statusCode, options2.message); - }; - exports2.badRequest = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 400, data, ctor: exports2.badRequest }); - }; - exports2.unauthorized = function(message, scheme, attributes) { - const err = new exports2.Boom(message, { statusCode: 401, ctor: exports2.unauthorized }); - if (!scheme) { - return err; - } - if (typeof scheme !== "string") { - err.output.headers["WWW-Authenticate"] = scheme.join(", "); - return err; - } - let wwwAuthenticate = `${scheme}`; - if (attributes || message) { - err.output.payload.attributes = {}; - } - if (attributes) { - if (typeof attributes === "string") { - wwwAuthenticate += " " + Hoek.escapeHeaderAttribute(attributes); - err.output.payload.attributes = attributes; - } else { - wwwAuthenticate += " " + Object.keys(attributes).map((name) => { - const value = attributes[name] ?? ""; - err.output.payload.attributes[name] = value; - return `${name}="${Hoek.escapeHeaderAttribute(value.toString())}"`; - }).join(", "); - } - } - if (message) { - if (attributes) { - wwwAuthenticate += ","; - } - wwwAuthenticate += ` error="${Hoek.escapeHeaderAttribute(message)}"`; - err.output.payload.attributes.error = message; - } else { - err.isMissing = true; - } - err.output.headers["WWW-Authenticate"] = wwwAuthenticate; - return err; - }; - exports2.paymentRequired = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 402, data, ctor: exports2.paymentRequired }); - }; - exports2.forbidden = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 403, data, ctor: exports2.forbidden }); - }; - exports2.notFound = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 404, data, ctor: exports2.notFound }); - }; - exports2.methodNotAllowed = function(messageOrError, data, allow) { - const err = new exports2.Boom(messageOrError, { statusCode: 405, data, ctor: exports2.methodNotAllowed }); - if (typeof allow === "string") { - allow = [allow]; - } - if (Array.isArray(allow)) { - err.output.headers.Allow = allow.join(", "); - } - return err; - }; - exports2.notAcceptable = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 406, data, ctor: exports2.notAcceptable }); - }; - exports2.proxyAuthRequired = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 407, data, ctor: exports2.proxyAuthRequired }); - }; - exports2.clientTimeout = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 408, data, ctor: exports2.clientTimeout }); - }; - exports2.conflict = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 409, data, ctor: exports2.conflict }); - }; - exports2.resourceGone = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 410, data, ctor: exports2.resourceGone }); - }; - exports2.lengthRequired = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 411, data, ctor: exports2.lengthRequired }); - }; - exports2.preconditionFailed = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 412, data, ctor: exports2.preconditionFailed }); - }; - exports2.entityTooLarge = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 413, data, ctor: exports2.entityTooLarge }); - }; - exports2.uriTooLong = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 414, data, ctor: exports2.uriTooLong }); - }; - exports2.unsupportedMediaType = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 415, data, ctor: exports2.unsupportedMediaType }); - }; - exports2.rangeNotSatisfiable = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 416, data, ctor: exports2.rangeNotSatisfiable }); - }; - exports2.expectationFailed = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 417, data, ctor: exports2.expectationFailed }); - }; - exports2.teapot = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 418, data, ctor: exports2.teapot }); - }; - exports2.badData = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 422, data, ctor: exports2.badData }); - }; - exports2.locked = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 423, data, ctor: exports2.locked }); - }; - exports2.failedDependency = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 424, data, ctor: exports2.failedDependency }); - }; - exports2.tooEarly = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 425, data, ctor: exports2.tooEarly }); - }; - exports2.preconditionRequired = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 428, data, ctor: exports2.preconditionRequired }); - }; - exports2.tooManyRequests = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 429, data, ctor: exports2.tooManyRequests }); - }; - exports2.illegal = function(messageOrError, data) { - return new exports2.Boom(messageOrError, { statusCode: 451, data, ctor: exports2.illegal }); - }; - exports2.internal = function(message, data, statusCode = 500) { - return internals.serverError(message, data, statusCode, exports2.internal); - }; - exports2.notImplemented = function(message, data) { - return internals.serverError(message, data, 501, exports2.notImplemented); - }; - exports2.badGateway = function(message, data) { - return internals.serverError(message, data, 502, exports2.badGateway); - }; - exports2.serverUnavailable = function(message, data) { - return internals.serverError(message, data, 503, exports2.serverUnavailable); - }; - exports2.gatewayTimeout = function(message, data) { - return internals.serverError(message, data, 504, exports2.gatewayTimeout); - }; - exports2.badImplementation = function(message, data) { - const err = internals.serverError(message, data, 500, exports2.badImplementation); - err.isDeveloperError = true; - return err; - }; - internals.initialize = function(err, statusCode, message) { - const numberCode = parseInt(statusCode, 10); - Hoek.assert(!isNaN(numberCode) && numberCode >= 400, "First argument must be a number (400+):", statusCode); - err.isBoom = true; - err.isServer = numberCode >= 500; - if (!err.hasOwnProperty("data")) { - err.data = null; - } - err.output = { - statusCode: numberCode, - payload: {}, - headers: {} - }; - Object.defineProperty(err, "reformat", { value: internals.reformat, configurable: true }); - if (!message && !err.message) { - err.reformat(); - message = err.output.payload.error; - } - if (message) { - const props = Object.getOwnPropertyDescriptor(err, "message") || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(err), "message"); - Hoek.assert(!props || props.configurable && !props.get, "The error is not compatible with boom"); - err.message = message + (err.message ? ": " + err.message : ""); - err.output.payload.message = err.message; - } - err.reformat(); - return err; - }; - internals.reformat = function(debug = false) { - this.output.payload.statusCode = this.output.statusCode; - this.output.payload.error = internals.codes.get(this.output.statusCode) || "Unknown"; - if (this.output.statusCode === 500 && debug !== true) { - this.output.payload.message = "An internal server error occurred"; - } else if (this.message) { - this.output.payload.message = this.message; - } - }; - internals.serverError = function(messageOrError, data, statusCode, ctor) { - if (data instanceof Error && !data.isBoom) { - return exports2.boomify(data, { statusCode, message: messageOrError }); - } - return new exports2.Boom(messageOrError, { statusCode, data, ctor }); - }; - } -}); var require_lru_cache = __commonJS({ "node_modules/.deno/lru-cache@7.14.0/node_modules/lru-cache/index.js"(exports2, module14) { var perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date; @@ -31760,6 +30372,20 @@ var require_lru_cache = __commonJS({ module14.exports = LRUCache; } }); +var BackendErrorNotFound; +var BackendErrorGone; +var BackendErrorBadData; +var BackendErrorConflict; +var init_errors4 = __esm({ + "src/serve/errors.ts"() { + "use strict"; + init_errors3(); + BackendErrorNotFound = ChelErrorGenerator("BackendErrorNotFound"); + BackendErrorGone = ChelErrorGenerator("BackendErrorGone"); + BackendErrorBadData = ChelErrorGenerator("BackendErrorBadData"); + BackendErrorConflict = ChelErrorGenerator("BackendErrorConflict"); + } +}); var SERVER_EXITING; var SERVER_RUNNING; var init_events2 = __esm({ @@ -36482,8 +35108,8 @@ var require_GEOSEARCH_WITH = __commonJS({ const replyWithSet = new Set(replyWith); let index = 0; const distanceIndex = replyWithSet.has(exports2.GEO_REPLY_WITH.DISTANCE) && ++index, hashIndex = replyWithSet.has(exports2.GEO_REPLY_WITH.HASH) && ++index, coordinatesIndex = replyWithSet.has(exports2.GEO_REPLY_WITH.COORDINATES) && ++index; - return reply.map((raw) => { - const unwrapped = raw; + return reply.map((raw2) => { + const unwrapped = raw2; const item = { member: unwrapped[0] }; @@ -47544,8 +46170,8 @@ var require_cache = __commonJS({ */ async handleCache(client, parser3, fn, transformReply, typeMapping) { let reply; - const cacheKey = generateCacheKey(parser3.redisArgs); - let cacheEntry = this.get(cacheKey); + const cacheKey2 = generateCacheKey(parser3.redisArgs); + let cacheEntry = this.get(cacheKey2); if (cacheEntry) { if (cacheEntry instanceof ClientSideCacheEntryValue) { this.#statsCounter.recordHits(1); @@ -47561,7 +46187,7 @@ var require_cache = __commonJS({ const startTime = performance.now(); const promise = fn(); cacheEntry = this.createPromiseEntry(client, promise); - this.set(cacheKey, cacheEntry, parser3.keys); + this.set(cacheKey2, cacheEntry, parser3.keys); try { reply = await promise; const loadTime = performance.now() - startTime; @@ -47570,7 +46196,7 @@ var require_cache = __commonJS({ const loadTime = performance.now() - startTime; this.#statsCounter.recordLoadFailure(loadTime); if (cacheEntry.validate()) { - this.delete(cacheKey); + this.delete(cacheKey2); } throw err; } @@ -47583,8 +46209,8 @@ var require_cache = __commonJS({ } if (cacheEntry.validate()) { cacheEntry = this.createValueEntry(client, val); - this.set(cacheKey, cacheEntry, parser3.keys); - this.emit("cached-key", cacheKey); + this.set(cacheKey2, cacheEntry, parser3.keys); + this.emit("cached-key", cacheKey2); } else { } return structuredClone(val); @@ -47600,12 +46226,12 @@ var require_cache = __commonJS({ } const keySet = this.#keyToCacheKeySetMap.get(key.toString()); if (keySet) { - for (const cacheKey of keySet) { - const entry = this.#cacheKeyToEntryMap.get(cacheKey); + for (const cacheKey2 of keySet) { + const entry = this.#cacheKeyToEntryMap.get(cacheKey2); if (entry) { entry.invalidate(); } - this.#cacheKeyToEntryMap.delete(cacheKey); + this.#cacheKeyToEntryMap.delete(cacheKey2); } this.#keyToCacheKeySetMap.delete(key.toString()); } @@ -47625,33 +46251,33 @@ var require_cache = __commonJS({ } } } - get(cacheKey) { - const val = this.#cacheKeyToEntryMap.get(cacheKey); + get(cacheKey2) { + const val = this.#cacheKeyToEntryMap.get(cacheKey2); if (val && !val.validate()) { - this.delete(cacheKey); + this.delete(cacheKey2); this.#statsCounter.recordEvictions(1); - this.emit("cache-evict", cacheKey); + this.emit("cache-evict", cacheKey2); return void 0; } if (val !== void 0 && this.lru) { - this.#cacheKeyToEntryMap.delete(cacheKey); - this.#cacheKeyToEntryMap.set(cacheKey, val); + this.#cacheKeyToEntryMap.delete(cacheKey2); + this.#cacheKeyToEntryMap.set(cacheKey2, val); } return val; } - delete(cacheKey) { - const entry = this.#cacheKeyToEntryMap.get(cacheKey); + delete(cacheKey2) { + const entry = this.#cacheKeyToEntryMap.get(cacheKey2); if (entry) { entry.invalidate(); - this.#cacheKeyToEntryMap.delete(cacheKey); + this.#cacheKeyToEntryMap.delete(cacheKey2); } } - has(cacheKey) { - return this.#cacheKeyToEntryMap.has(cacheKey); + has(cacheKey2) { + return this.#cacheKeyToEntryMap.has(cacheKey2); } - set(cacheKey, cacheEntry, keys) { + set(cacheKey2, cacheEntry, keys) { let count = this.#cacheKeyToEntryMap.size; - const oldEntry = this.#cacheKeyToEntryMap.get(cacheKey); + const oldEntry = this.#cacheKeyToEntryMap.get(cacheKey2); if (oldEntry) { count--; oldEntry.invalidate(); @@ -47660,13 +46286,13 @@ var require_cache = __commonJS({ this.deleteOldest(); this.#statsCounter.recordEvictions(1); } - this.#cacheKeyToEntryMap.set(cacheKey, cacheEntry); + this.#cacheKeyToEntryMap.set(cacheKey2, cacheEntry); for (const key of keys) { if (!this.#keyToCacheKeySetMap.has(key.toString())) { this.#keyToCacheKeySetMap.set(key.toString(), /* @__PURE__ */ new Set()); } const cacheKeySet = this.#keyToCacheKeySetMap.get(key.toString()); - cacheKeySet.add(cacheKey); + cacheKeySet.add(cacheKey2); } } size() { @@ -47726,17 +46352,17 @@ var require_cache = __commonJS({ enable() { this.#disabled = false; } - get(cacheKey) { + get(cacheKey2) { if (this.#disabled) { return void 0; } - return super.get(cacheKey); + return super.get(cacheKey2); } - has(cacheKey) { + has(cacheKey2) { if (this.#disabled) { return false; } - return super.has(cacheKey); + return super.has(cacheKey2); } onPoolClose() { this.clear(); @@ -48512,11 +47138,11 @@ var require_client = __commonJS({ const commandsWithErrorHandlers = await this.#getHandshakeCommands(); if (asap) commandsWithErrorHandlers.reverse(); - for (const { cmd, errorHandler } of commandsWithErrorHandlers) { + for (const { cmd, errorHandler: errorHandler2 } of commandsWithErrorHandlers) { promises.push(this.#queue.addCommand(cmd, { chainId, asap - }).catch(errorHandler)); + }).catch(errorHandler2)); } return promises; } @@ -49119,7 +47745,7 @@ var require_client = __commonJS({ exports2.default = RedisClient; } }); -var require_lib3 = __commonJS({ +var require_lib = __commonJS({ "node_modules/.deno/cluster-key-slot@1.1.2/node_modules/cluster-key-slot/lib/index.js"(exports2, module14) { var lookup = [ 0, @@ -49451,7 +48077,7 @@ var require_cluster_slots = __commonJS({ var errors_1 = require_errors(); var client_1 = __importDefault(require_client()); var pub_sub_1 = require_pub_sub(); - var cluster_key_slot_1 = __importDefault(require_lib3()); + var cluster_key_slot_1 = __importDefault(require_lib()); var cache_1 = require_cache(); var RedisClusterSlots = class { static #SLOTS = 16384; @@ -50342,7 +48968,7 @@ var require_cluster = __commonJS({ exports2.default = RedisCluster; } }); -var require_utils2 = __commonJS({ +var require_utils = __commonJS({ "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/sentinel/utils.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); @@ -50854,7 +49480,7 @@ var require_sentinel = __commonJS({ var client_1 = __importDefault(require_client()); var commander_1 = require_commander(); var commands_1 = __importDefault(require_commands()); - var utils_1 = require_utils2(); + var utils_1 = require_utils(); var multi_commands_1 = __importDefault(require_multi_commands()); var pub_sub_proxy_1 = require_pub_sub_proxy(); var promises_1 = __require2("node:timers/promises"); @@ -53598,7 +52224,7 @@ var require_commands3 = __commonJS({ }; } }); -var require_lib4 = __commonJS({ +var require_lib2 = __commonJS({ "node_modules/.deno/@redis+bloom@5.9.0/node_modules/@redis/bloom/dist/lib/index.js"(exports2) { "use strict"; var __importDefault = exports2 && exports2.__importDefault || function(mod) { @@ -54353,7 +52979,7 @@ var require_commands4 = __commonJS({ }; } }); -var require_lib5 = __commonJS({ +var require_lib3 = __commonJS({ "node_modules/.deno/@redis+json@5.9.0/node_modules/@redis/json/dist/lib/index.js"(exports2) { "use strict"; var __importDefault = exports2 && exports2.__importDefault || function(mod) { @@ -56173,7 +54799,7 @@ var require_commands5 = __commonJS({ }; } }); -var require_lib6 = __commonJS({ +var require_lib4 = __commonJS({ "node_modules/.deno/@redis+search@5.9.0/node_modules/@redis/search/dist/lib/index.js"(exports2) { "use strict"; var __importDefault = exports2 && exports2.__importDefault || function(mod) { @@ -57085,8 +55711,8 @@ var require_MRANGE_GROUPBY = __commonJS({ }; } exports2.createTransformMRangeGroupByArguments = createTransformMRangeGroupByArguments; - function extractResp3MRangeSources(raw) { - const unwrappedMetadata2 = raw; + function extractResp3MRangeSources(raw2) { + const unwrappedMetadata2 = raw2; if (unwrappedMetadata2 instanceof Map) { return unwrappedMetadata2.get("sources"); } else if (unwrappedMetadata2 instanceof Array) { @@ -57861,7 +56487,7 @@ var require_commands6 = __commonJS({ }; } }); -var require_lib7 = __commonJS({ +var require_lib5 = __commonJS({ "node_modules/.deno/@redis+time-series@5.9.0/node_modules/@redis/time-series/dist/lib/index.js"(exports2) { "use strict"; var __importDefault = exports2 && exports2.__importDefault || function(mod) { @@ -57918,15 +56544,15 @@ var require_dist2 = __commonJS({ Object.defineProperty(exports2, "__esModule", { value: true }); exports2.createSentinel = exports2.createCluster = exports2.createClientPool = exports2.createClient = void 0; var client_1 = require_dist(); - var bloom_1 = __importDefault(require_lib4()); - var json_1 = __importDefault(require_lib5()); - var search_1 = __importDefault(require_lib6()); - var time_series_1 = __importDefault(require_lib7()); + var bloom_1 = __importDefault(require_lib2()); + var json_1 = __importDefault(require_lib3()); + var search_1 = __importDefault(require_lib4()); + var time_series_1 = __importDefault(require_lib5()); __exportStar(require_dist(), exports2); + __exportStar(require_lib2(), exports2); + __exportStar(require_lib3(), exports2); __exportStar(require_lib4(), exports2); __exportStar(require_lib5(), exports2); - __exportStar(require_lib6(), exports2); - __exportStar(require_lib7(), exports2); var modules = { ...bloom_1.default, json: json_1.default, @@ -58163,9 +56789,9 @@ var init_database_router = __esm({ super(); ConfigSchema4.parse(config2); const configCopy = Object.fromEntries(Object.entries(config2).sort((a, b) => b[0].length - a[0].length)); - const errors = this.validateConfig(configCopy); - if (errors.length) { - throw new Error(`[${this.constructor.name}] ${errors.length} error(s) found in your config.`, { cause: errors }); + const errors2 = this.validateConfig(configCopy); + if (errors2.length) { + throw new Error(`[${this.constructor.name}] ${errors2.length} error(s) found in your config.`, { cause: errors2 }); } this.config = configCopy; } @@ -58180,22 +56806,22 @@ var init_database_router = __esm({ return backends["*"]; } validateConfig(config2) { - const errors = []; + const errors2 = []; if (!config2["*"]) { - errors.push({ msg: 'Missing key: "*" (fallback storage is required)' }); + errors2.push({ msg: 'Missing key: "*" (fallback storage is required)' }); } for (const entry of Object.entries(config2)) { const value = entry[1]; if (typeof value?.name !== "string" || typeof value?.options !== "object") { - errors.push({ msg: "entry value must be of type { name: string, options: Object }", entry }); + errors2.push({ msg: "entry value must be of type { name: string, options: Object }", entry }); continue; } if (value.name === "router") { - errors.push({ msg: "Router backends cannot be nested.", entry }); + errors2.push({ msg: "Router backends cannot be nested.", entry }); continue; } } - return errors; + return errors2; } async init() { this.backends = /* @__PURE__ */ Object.create(null); @@ -58284,19 +56910,19 @@ var init_database_router_test = __esm({ name: "DatabaseRouter::validateConfig", async fn(t) { await t.step("should accept a valid config", () => { - const errors = db.validateConfig(validConfig); - if (errors.length !== 0) throw new Error(`Expected 0 errors but got ${errors.length}`); + const errors2 = db.validateConfig(validConfig); + if (errors2.length !== 0) throw new Error(`Expected 0 errors but got ${errors2.length}`); }); await t.step("should reject configs missing a * key", () => { const config2 = omit2(validConfig, ["*"]); - const errors = db.validateConfig(config2); - if (errors.length !== 1) throw new Error(`Expected 1 error but got ${errors.length}`); + const errors2 = db.validateConfig(config2); + if (errors2.length !== 1) throw new Error(`Expected 1 error but got ${errors2.length}`); }); await t.step("should reject config entries missing a name", () => { const config2 = cloneDeep(validConfig); delete config2["*"].name; - const errors = db.validateConfig(config2); - if (errors.length !== 1) throw new Error(`Expected 1 error but got ${errors.length}`); + const errors2 = db.validateConfig(config2); + if (errors2.length !== 1) throw new Error(`Expected 1 error but got ${errors2.length}`); }); } }); @@ -58347,7 +56973,6 @@ var init_2 = __esm({ }); } }); -var import_boom; var import_npm_lru_cache; var import_npm_nconf2; var production; @@ -58361,9 +56986,9 @@ var init_database = __esm({ init_db(); init_db(); init_functions(); - import_boom = __toESM(require_lib2()); init_esm(); import_npm_lru_cache = __toESM(require_lru_cache()); + init_errors4(); init_events2(); init_vapid(); init_zkppSalt(); @@ -58378,10 +57003,10 @@ var init_database = __esm({ const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize); const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); if (latestHEADinfo === "") { - throw import_boom.default.resourceGone(`contractID ${contractID} has been deleted!`); + throw new BackendErrorGone(`contractID ${contractID} has been deleted!`); } if (!latestHEADinfo) { - throw import_boom.default.notFound(`contractID ${contractID} doesn't exist!`); + throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`); } let counter = 0; let currentHeight = height; @@ -58468,7 +57093,7 @@ var init_database = __esm({ "backend/db/registerName": async function(name, value) { const exists = await esm_default("backend/db/lookupName", name); if (exists) { - throw import_boom.default.conflict("exists"); + throw new BackendErrorConflict("exists"); } await esm_default("chelonia.db/set", namespaceKey(name), value); await esm_default("chelonia.db/set", `_private_cid2name_${value}`, name); @@ -58563,49082 +57188,15474 @@ var init_database = __esm({ }; } }); -var require_package3 = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/package.json"(exports2, module14) { - module14.exports = { - name: "@hapi/validate", - description: "Object schema validation", - version: "2.0.1", - repository: "git://github.com/hapijs/validate", - main: "lib/index.js", - files: [ - "lib/**/*" - ], - eslintConfig: { - extends: [ - "plugin:@hapi/module" - ] - }, - dependencies: { - "@hapi/hoek": "^11.0.2", - "@hapi/topo": "^6.0.1" - }, - devDependencies: { - "@hapi/bourne": "^3.0.0", - "@hapi/code": "^9.0.3", - "@hapi/eslint-plugin": "*", - "@hapi/lab": "^25.1.2" - }, - scripts: { - test: "lab -t 100 -a @hapi/code -L", - "test-cov-html": "lab -r html -o coverage.html -a @hapi/code" - }, - license: "BSD-3-Clause" - }; - } -}); -var require_schemas = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/schemas.js"(exports2) { - "use strict"; - var Joi2 = require_lib9(); - var internals = {}; - internals.wrap = Joi2.string().min(1).max(2).allow(false); - exports2.preferences = Joi2.object({ - allowUnknown: Joi2.boolean(), - abortEarly: Joi2.boolean(), - context: Joi2.object(), - convert: Joi2.boolean(), - dateFormat: Joi2.valid("date", "iso", "string", "time", "utc"), - errors: { - escapeHtml: Joi2.boolean(), - label: Joi2.valid("path", "key", false), - language: [ - Joi2.string(), - Joi2.object().ref() - ], - render: Joi2.boolean(), - stack: Joi2.boolean(), - wrap: { - label: internals.wrap, - array: internals.wrap - } - }, - messages: Joi2.object(), - noDefaults: Joi2.boolean(), - nonEnumerables: Joi2.boolean(), - presence: Joi2.valid("required", "optional", "forbidden"), - skipFunctions: Joi2.boolean(), - stripUnknown: Joi2.object({ - arrays: Joi2.boolean(), - objects: Joi2.boolean() - }).or("arrays", "objects").allow(true, false) - }).strict(); - } -}); -var require_ref = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/ref.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Reach = require_reach(); - var Common = require_common2(); - var internals = { - symbol: Symbol("ref"), - // Used to internally identify references (shared with other joi versions) - defaults: { - adjust: null, - in: false, - iterables: null, - map: null, - separator: ".", - type: "value" - } - }; - exports2.create = function(key, options2 = {}) { - Assert(typeof key === "string", "Invalid reference key:", key); - Common.assertOptions(options2, ["adjust", "ancestor", "in", "iterables", "map", "prefix", "separator"]); - Assert(!options2.prefix || typeof options2.prefix === "object", "options.prefix must be of type object"); - const ref = Object.assign({}, internals.defaults, options2); - delete ref.prefix; - const separator = ref.separator; - const context = internals.context(key, separator, options2.prefix); - ref.type = context.type; - key = context.key; - if (ref.type === "value") { - if (context.root) { - Assert(!separator || key[0] !== separator, "Cannot specify relative path with root prefix"); - ref.ancestor = "root"; - if (!key) { - key = null; - } - } - if (separator && separator === key) { - key = null; - ref.ancestor = 0; - } else { - if (ref.ancestor !== void 0) { - Assert(!separator || !key || key[0] !== separator, "Cannot combine prefix with ancestor option"); +var compose; +var init_compose = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/compose.js"() { + compose = (middleware, onError, onNotFound) => { + return (context, next) => { + let index = -1; + return dispatch(0); + async function dispatch(i2) { + if (i2 <= index) { + throw new Error("next() called multiple times"); + } + index = i2; + let res; + let isError = false; + let handler; + if (middleware[i2]) { + handler = middleware[i2][0][0]; + context.req.routeIndex = i2; } else { - const [ancestor, slice] = internals.ancestor(key, separator); - if (slice) { - key = key.slice(slice); - if (key === "") { - key = null; + handler = i2 === middleware.length && next || void 0; + } + if (handler) { + try { + res = await handler(context, () => dispatch(i2 + 1)); + } catch (err) { + if (err instanceof Error && onError) { + context.error = err; + res = await onError(err, context); + isError = true; + } else { + throw err; } } - ref.ancestor = ancestor; - } - } - } - ref.path = separator ? key === null ? [] : key.split(separator) : [key]; - return new internals.Ref(ref); - }; - exports2.in = function(key, options2 = {}) { - return exports2.create(key, Object.assign({}, options2, { in: true })); - }; - exports2.isRef = function(ref) { - return ref ? !!ref[Common.symbols.ref] : false; - }; - internals.Ref = class { - constructor(options2) { - Assert(typeof options2 === "object", "Invalid reference construction"); - Common.assertOptions(options2, [ - "adjust", - "ancestor", - "in", - "iterables", - "map", - "path", - "separator", - "type", - // Copied - "depth", - "key", - "root", - "display" - // Overridden - ]); - Assert([false, void 0].includes(options2.separator) || typeof options2.separator === "string" && options2.separator.length === 1, "Invalid separator"); - Assert(!options2.adjust || typeof options2.adjust === "function", "options.adjust must be a function"); - Assert(!options2.map || Array.isArray(options2.map), "options.map must be an array"); - Assert(!options2.map || !options2.adjust, "Cannot set both map and adjust options"); - Object.assign(this, internals.defaults, options2); - Assert(this.type === "value" || this.ancestor === void 0, "Non-value references cannot reference ancestors"); - if (Array.isArray(this.map)) { - this.map = new Map(this.map); - } - this.depth = this.path.length; - this.key = this.path.length ? this.path.join(this.separator) : null; - this.root = this.path[0]; - this.updateDisplay(); - } - resolve(value, state, prefs, local, options2 = {}) { - Assert(!this.in || options2.in, "Invalid in() reference usage"); - if (this.type === "global") { - return this._resolve(prefs.context, state, options2); - } - if (this.type === "local") { - return this._resolve(local, state, options2); - } - if (!this.ancestor) { - return this._resolve(value, state, options2); - } - if (this.ancestor === "root") { - return this._resolve(state.ancestors[state.ancestors.length - 1], state, options2); - } - Assert(this.ancestor <= state.ancestors.length, "Invalid reference exceeds the schema root:", this.display); - return this._resolve(state.ancestors[this.ancestor - 1], state, options2); - } - _resolve(target, state, options2) { - let resolved; - if (this.type === "value" && state.mainstay.shadow && options2.shadow !== false) { - resolved = state.mainstay.shadow.get(this.absolute(state)); - } - if (resolved === void 0) { - resolved = Reach(target, this.path, { iterables: this.iterables, functions: true }); - } - if (this.adjust) { - resolved = this.adjust(resolved); - } - if (this.map) { - const mapped = this.map.get(resolved); - if (mapped !== void 0) { - resolved = mapped; - } - } - return resolved; - } - toString() { - return this.display; - } - absolute(state) { - return [...state.path.slice(0, -this.ancestor), ...this.path]; - } - clone() { - return new internals.Ref(this); - } - updateDisplay() { - const key = this.key !== null ? this.key : ""; - if (this.type !== "value") { - this.display = `ref:${this.type}:${key}`; - return; - } - if (!this.separator) { - this.display = `ref:${key}`; - return; - } - if (!this.ancestor) { - this.display = `ref:${this.separator}${key}`; - return; - } - if (this.ancestor === "root") { - this.display = `ref:root:${key}`; - return; - } - if (this.ancestor === 1) { - this.display = `ref:${key || ".."}`; - return; - } - const lead = new Array(this.ancestor + 1).fill(this.separator).join(""); - this.display = `ref:${lead}${key || ""}`; - } - }; - internals.Ref.prototype[Common.symbols.ref] = true; - internals.context = function(key, separator, prefix = {}) { - key = key.trim(); - if (prefix) { - const globalp = prefix.global === void 0 ? "$" : prefix.global; - if (globalp !== separator && key.startsWith(globalp)) { - return { key: key.slice(globalp.length), type: "global" }; - } - const local = prefix.local === void 0 ? "#" : prefix.local; - if (local !== separator && key.startsWith(local)) { - return { key: key.slice(local.length), type: "local" }; - } - const root = prefix.root === void 0 ? "/" : prefix.root; - if (root !== separator && key.startsWith(root)) { - return { key: key.slice(root.length), type: "value", root: true }; - } - } - return { key, type: "value" }; - }; - internals.ancestor = function(key, separator) { - if (!separator) { - return [1, 0]; - } - if (key[0] !== separator) { - return [1, 0]; - } - if (key[1] !== separator) { - return [0, 1]; - } - let i2 = 2; - while (key[i2] === separator) { - ++i2; - } - return [i2 - 1, i2]; - }; - exports2.toSibling = 0; - exports2.toParent = 1; - exports2.Manager = class { - constructor() { - this.refs = []; - } - register(source, target) { - if (!source) { - return; - } - target = target === void 0 ? exports2.toParent : target; - if (Array.isArray(source)) { - for (const ref of source) { - this.register(ref, target); - } - return; - } - if (Common.isSchema(source)) { - for (const item of source._refs.refs) { - if (item.ancestor - target >= 0) { - this.refs.push({ ancestor: item.ancestor - target, root: item.root }); + } else { + if (context.finalized === false && onNotFound) { + res = await onNotFound(context); } } - return; - } - if (exports2.isRef(source) && source.type === "value" && source.ancestor - target >= 0) { - this.refs.push({ ancestor: source.ancestor - target, root: source.root }); - } - } - clone() { - const copy2 = new exports2.Manager(); - copy2.refs = Clone(this.refs); - return copy2; - } - reset() { - this.refs = []; - } - roots() { - return this.refs.filter((ref) => !ref.ancestor).map((ref) => ref.root); - } - }; - } -}); -var require_template = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/template.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var EscapeHtml = require_escapeHtml(); - var Common = require_common2(); - var Ref = require_ref(); - var internals = { - symbol: Symbol("template"), - opens: new Array(1e3).join("\0"), - closes: new Array(1e3).join(""), - dateFormat: { - date: Date.prototype.toDateString, - iso: Date.prototype.toISOString, - string: Date.prototype.toString, - time: Date.prototype.toTimeString, - utc: Date.prototype.toUTCString - } - }; - module14.exports = exports2 = internals.Template = class { - constructor(source, options2) { - Assert(typeof source === "string", "Template source must be a string"); - Assert(!source.includes("\0") && !source.includes(""), "Template source cannot contain reserved control characters"); - this.source = source; - this.rendered = source; - this._template = null; - this._settings = Clone(options2); - this._parse(); - } - _parse() { - if (!this.source.includes("{")) { - return; - } - const encoded = internals.encode(this.source); - const parts = internals.split(encoded); - const processed = []; - const head = parts.shift(); - if (head) { - processed.push(head); - } - for (const part of parts) { - const raw = part[0] !== "{"; - const ender = raw ? "}" : "}}"; - const end = part.indexOf(ender); - let variable = part.slice(raw ? 0 : 1, end); - const wrapped = variable[0] === ":"; - if (wrapped) { - variable = variable.slice(1); - } - const dynamic = this._ref(internals.decode(variable), { raw, wrapped }); - processed.push(dynamic); - const rest = part.slice(end + ender.length); - if (rest) { - processed.push(internals.decode(rest)); - } - } - this._template = processed; - } - static date(date3, prefs) { - return internals.dateFormat[prefs.dateFormat].call(date3); - } - isDynamic() { - return !!this._template; - } - static isTemplate(template) { - return template ? !!template[Common.symbols.template] : false; - } - render(value, state, prefs, local, options2 = {}) { - if (!this.isDynamic()) { - return this.rendered; - } - const parts = []; - for (const part of this._template) { - if (typeof part === "string") { - parts.push(part); - } else { - const rendered = part.ref.resolve(value, state, prefs, local, options2); - const string3 = internals.stringify(rendered, prefs, options2.errors); - const result = part.raw || options2.errors?.escapeHtml === false ? string3 : EscapeHtml(string3); - parts.push(internals.wrap(result, part.wrapped && prefs.errors.wrap.label)); + if (res && (context.finalized === false || isError)) { + context.res = res; } + return context; } - return parts.join(""); - } - _ref(content, { raw, wrapped }) { - const ref = Ref.create(content, this._settings); - return { ref, raw, wrapped: wrapped || ref.type === "local" && ref.key === "label" }; - } - toString() { - return this.source; - } - }; - internals.Template.prototype[Common.symbols.template] = true; - internals.Template.prototype.isImmutable = true; - internals.encode = function(string3) { - return string3.replace(/\\(\{+)/g, ($0, $1) => { - return internals.opens.slice(0, $1.length); - }).replace(/\\(\}+)/g, ($0, $1) => { - return internals.closes.slice(0, $1.length); - }); - }; - internals.decode = function(string3) { - return string3.replace(/\u0000/g, "{").replace(/\u0001/g, "}"); - }; - internals.split = function(string3) { - const parts = []; - let current = ""; - for (let i2 = 0; i2 < string3.length; ++i2) { - const char = string3[i2]; - if (char === "{") { - let next = ""; - while (i2 + 1 < string3.length && string3[i2 + 1] === "{") { - next += "{"; - ++i2; - } - parts.push(current); - current = next; - } else { - current += char; - } - } - parts.push(current); - return parts; - }; - internals.wrap = function(value, ends) { - if (!ends) { - return value; - } - if (ends.length === 1) { - return `${ends}${value}${ends}`; - } - return `${ends[0]}${value}${ends[1]}`; - }; - internals.stringify = function(value, prefs, options2) { - const type = typeof value; - if (value === null) { - return "null"; - } - if (value === void 0) { - return ""; - } - if (type === "string") { - return value; - } - if (type === "number" || type === "function" || type === "symbol") { - return value.toString(); - } - if (type !== "object") { - return JSON.stringify(value); - } - if (value instanceof Date) { - return internals.Template.date(value, prefs); - } - if (value instanceof Map) { - const pairs = []; - for (const [key, sym] of value.entries()) { - pairs.push(`${key.toString()} -> ${sym.toString()}`); - } - value = pairs; - } - if (!Array.isArray(value)) { - return value.toString(); - } - let partial2 = ""; - for (const item of value) { - partial2 = partial2 + (partial2.length ? ", " : "") + internals.stringify(item, prefs, options2); - } - return internals.wrap(partial2, prefs.errors.wrap.array); + }; }; } }); -var require_messages = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/messages.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Template = require_template(); - exports2.compile = function(messages, target) { - if (typeof messages === "string") { - Assert(!target, "Cannot set single message string"); - return new Template(messages); - } - if (Template.isTemplate(messages)) { - Assert(!target, "Cannot set single message template"); - return messages; - } - Assert(typeof messages === "object" && !Array.isArray(messages), "Invalid message options"); - target = target ? Clone(target) : {}; - for (let code2 in messages) { - const message = messages[code2]; - if (code2 === "root" || Template.isTemplate(message)) { - target[code2] = message; - continue; - } - if (typeof message === "string") { - target[code2] = new Template(message); - continue; - } - Assert(typeof message === "object" && !Array.isArray(message), "Invalid message for", code2); - const language = code2; - target[language] = target[language] || {}; - for (code2 in message) { - const localized = message[code2]; - if (code2 === "root" || Template.isTemplate(localized)) { - target[language][code2] = localized; - continue; - } - Assert(typeof localized === "string", "Invalid message for", code2, "in", language); - target[language][code2] = new Template(localized); - } - } - return target; - }; - exports2.merge = function(base2, extended) { - if (!base2) { - return exports2.compile(extended); - } - if (!extended) { - return base2; - } - if (typeof extended === "string") { - return new Template(extended); - } - if (Template.isTemplate(extended)) { - return extended; +var HTTPException; +var init_http_exception = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/http-exception.js"() { + HTTPException = class extends Error { + res; + status; + /** + * Creates an instance of `HTTPException`. + * @param status - HTTP status code for the exception. Defaults to 500. + * @param options - Additional options for the exception. + */ + constructor(status = 500, options2) { + super(options2?.message, { cause: options2?.cause }); + this.res = options2?.res; + this.status = status; } - const target = Clone(base2); - for (let code2 in extended) { - const message = extended[code2]; - if (code2 === "root" || Template.isTemplate(message)) { - target[code2] = message; - continue; - } - if (typeof message === "string") { - target[code2] = new Template(message); - continue; - } - Assert(typeof message === "object" && !Array.isArray(message), "Invalid message for", code2); - const language = code2; - target[language] = target[language] || {}; - for (code2 in message) { - const localized = message[code2]; - if (code2 === "root" || Template.isTemplate(localized)) { - target[language][code2] = localized; - continue; - } - Assert(typeof localized === "string", "Invalid message for", code2, "in", language); - target[language][code2] = new Template(localized); + /** + * Returns the response object associated with the exception. + * If a response object is not provided, a new response is created with the error message and status code. + * @returns The response object. + */ + getResponse() { + if (this.res) { + const newResponse = new Response(this.res.body, { + status: this.status, + headers: this.res.headers + }); + return newResponse; } + return new Response(this.message, { + status: this.status + }); } - return target; }; } }); -var require_common2 = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/common.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var AssertError = require_assertError(); - var Pkg = require_package3(); - var Messages; - var Schemas; - var internals = { - isoDate: /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/ - }; - exports2.version = Pkg.version; - exports2.defaults = { - abortEarly: true, - allowUnknown: false, - context: null, - convert: true, - dateFormat: "iso", - errors: { - escapeHtml: false, - label: "path", - language: null, - render: true, - stack: false, - wrap: { - label: '"', - array: "[]" - } - }, - messages: {}, - nonEnumerables: false, - noDefaults: false, - presence: "optional", - skipFunctions: false, - stripUnknown: false - }; - exports2.symbols = { - any: Symbol.for("@hapi/joi/schema"), - // Used to internally identify any-based types (shared with other joi versions) - arraySingle: Symbol("arraySingle"), - deepDefault: Symbol("deepDefault"), - errors: Symbol("errors"), - literal: Symbol("literal"), - override: Symbol("override"), - parent: Symbol("parent"), - prefs: Symbol("prefs"), - ref: Symbol("ref"), - template: Symbol("template"), - values: Symbol("values") - }; - exports2.assertOptions = function(options2, keys, name = "Options") { - Assert(options2 && typeof options2 === "object" && !Array.isArray(options2), "Options must be of type object"); - const unknownKeys = Object.keys(options2).filter((k) => !keys.includes(k)); - Assert(unknownKeys.length === 0, `${name} contain unknown keys: ${unknownKeys}`); - }; - exports2.checkPreferences = function(prefs) { - Schemas = Schemas || require_schemas(); - const result = Schemas.preferences.validate(prefs); - if (result.error) { - throw new AssertError([result.error.details[0].message]); - } - }; - exports2.compare = function(a, b, operator) { - switch (operator) { - case "=": - return a === b; - case ">": - return a > b; - case "<": - return a < b; - case ">=": - return a >= b; - case "<=": - return a <= b; - } - }; - exports2.default = function(value, defaultValue) { - return value === void 0 ? defaultValue : value; - }; - exports2.isIsoDate = function(date3) { - return internals.isoDate.test(date3); - }; - exports2.isNumber = function(value) { - return typeof value === "number" && !isNaN(value); - }; - exports2.isResolvable = function(obj) { - if (!obj) { - return false; - } - return obj[exports2.symbols.ref] || obj[exports2.symbols.template]; - }; - exports2.isSchema = function(schema, options2 = {}) { - const any = schema && schema[exports2.symbols.any]; - if (!any) { - return false; - } - return true; - }; - exports2.limit = function(value) { - return Number.isSafeInteger(value) && value >= 0; - }; - exports2.preferences = function(target, source) { - Messages = Messages || require_messages(); - target = target || {}; - source = source || {}; - const merged = Object.assign({}, target, source); - if (source.errors && target.errors) { - merged.errors = Object.assign({}, target.errors, source.errors); - merged.errors.wrap = Object.assign({}, target.errors.wrap, source.errors.wrap); - } - if (source.messages) { - merged.messages = Messages.compile(source.messages, target.messages); +var GET_MATCH_RESULT; +var init_constants2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/request/constants.js"() { + GET_MATCH_RESULT = /* @__PURE__ */ Symbol(); + } +}); +async function parseFormData(request, options2) { + const formData = await request.formData(); + if (formData) { + return convertFormDataToBodyData(formData, options2); + } + return {}; +} +function convertFormDataToBodyData(formData, options2) { + const form = /* @__PURE__ */ Object.create(null); + formData.forEach((value, key) => { + const shouldParseAllValues = options2.all || key.endsWith("[]"); + if (!shouldParseAllValues) { + form[key] = value; + } else { + handleParsingAllValues(form, key, value); + } + }); + if (options2.dot) { + Object.entries(form).forEach(([key, value]) => { + const shouldParseDotValues = key.includes("."); + if (shouldParseDotValues) { + handleParsingNestedValues(form, key, value); + delete form[key]; } - delete merged[exports2.symbols.prefs]; - return merged; - }; - exports2.tryWithPath = function(fn, key, options2 = {}) { - try { - return fn(); - } catch (err) { - if (err.path !== void 0) { - err.path = key + "." + err.path; + }); + } + return form; +} +var parseBody; +var handleParsingAllValues; +var handleParsingNestedValues; +var init_body = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/body.js"() { + init_request(); + parseBody = async (request, options2 = /* @__PURE__ */ Object.create(null)) => { + const { all = false, dot = false } = options2; + const headers = request instanceof HonoRequest ? request.raw.headers : request.headers; + const contentType = headers.get("Content-Type"); + if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) { + return parseFormData(request, { all, dot }); + } + return {}; + }; + handleParsingAllValues = (form, key, value) => { + if (form[key] !== void 0) { + if (Array.isArray(form[key])) { + ; + form[key].push(value); } else { - err.path = key; - } - if (options2.append) { - err.message = `${err.message} (${err.path})`; + form[key] = [form[key], value]; } - throw err; - } - }; - exports2.validateArg = function(value, label, { assert: assert2, message }) { - if (exports2.isSchema(assert2)) { - const result = assert2.validate(value); - if (!result.error) { - return; + } else { + if (!key.endsWith("[]")) { + form[key] = value; + } else { + form[key] = [value]; } - return result.error.message; - } else if (!assert2(value)) { - return label ? `${label} ${message}` : message; } }; - exports2.verifyFlat = function(args, method) { - for (const arg of args) { - Assert(!Array.isArray(arg), "Method no longer accepts array arguments:", method); + handleParsingNestedValues = (form, key, value) => { + if (/(?:^|\.)__proto__\./.test(key)) { + return; } + let nestedForm = form; + const keys = key.split("."); + keys.forEach((key2, index) => { + if (index === keys.length - 1) { + nestedForm[key2] = value; + } else { + if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) { + nestedForm[key2] = /* @__PURE__ */ Object.create(null); + } + nestedForm = nestedForm[key2]; + } + }); }; } }); -var require_compile = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/compile.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Common = require_common2(); - var Ref = require_ref(); - var internals = {}; - exports2.schema = function(Joi2, config2, options2 = {}) { - Common.assertOptions(options2, ["appendPath", "override"]); - try { - return internals.schema(Joi2, config2, options2); - } catch (err) { - if (options2.appendPath && err.path !== void 0) { - err.message = `${err.message} (${err.path})`; +var splitPath; +var splitRoutingPath; +var extractGroupsFromPath; +var replaceGroupMarks; +var patternCache; +var getPattern; +var tryDecode; +var tryDecodeURI; +var getPath; +var getPathNoStrict; +var mergePath; +var checkOptionalParameter; +var _decodeURI; +var _getQueryParam; +var getQueryParam; +var getQueryParams; +var decodeURIComponent_; +var init_url = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/url.js"() { + splitPath = (path8) => { + const paths = path8.split("/"); + if (paths[0] === "") { + paths.shift(); + } + return paths; + }; + splitRoutingPath = (routePath) => { + const { groups, path: path8 } = extractGroupsFromPath(routePath); + const paths = splitPath(path8); + return replaceGroupMarks(paths, groups); + }; + extractGroupsFromPath = (path8) => { + const groups = []; + path8 = path8.replace(/\{[^}]+\}/g, (match2, index) => { + const mark = `@${index}`; + groups.push([mark, match2]); + return mark; + }); + return { groups, path: path8 }; + }; + replaceGroupMarks = (paths, groups) => { + for (let i2 = groups.length - 1; i2 >= 0; i2--) { + const [mark] = groups[i2]; + for (let j = paths.length - 1; j >= 0; j--) { + if (paths[j].includes(mark)) { + paths[j] = paths[j].replace(mark, groups[i2][1]); + break; + } } - throw err; } + return paths; }; - internals.schema = function(Joi2, config2, options2) { - Assert(config2 !== void 0, "Invalid undefined schema"); - if (Array.isArray(config2)) { - Assert(config2.length, "Invalid empty array schema"); - if (config2.length === 1) { - config2 = config2[0]; - } - } - const valid = (base2, ...values) => { - if (options2.override !== false) { - return base2.valid(Joi2.override, ...values); - } - return base2.valid(...values); - }; - if (internals.simple(config2)) { - return valid(Joi2, config2); + patternCache = {}; + getPattern = (label, next) => { + if (label === "*") { + return "*"; } - if (typeof config2 === "function") { - return Joi2.custom(config2); - } - Assert(typeof config2 === "object", "Invalid schema content:", typeof config2); - if (Common.isResolvable(config2)) { - return valid(Joi2, config2); - } - if (Common.isSchema(config2)) { - return config2; - } - if (Array.isArray(config2)) { - for (const item of config2) { - if (!internals.simple(item)) { - return Joi2.alternatives().try(...config2); + const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); + if (match2) { + const cacheKey2 = `${label}#${next}`; + if (!patternCache[cacheKey2]) { + if (match2[2]) { + patternCache[cacheKey2] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey2, match2[1], new RegExp(`^${match2[2]}(?=/${next})`)] : [label, match2[1], new RegExp(`^${match2[2]}$`)]; + } else { + patternCache[cacheKey2] = [label, match2[1], true]; } } - return valid(Joi2, ...config2); - } - if (config2 instanceof RegExp) { - return Joi2.string().regex(config2); - } - if (config2 instanceof Date) { - return valid(Joi2.date(), config2); - } - Assert(Object.getPrototypeOf(config2) === Object.getPrototypeOf({}), "Schema can only contain plain objects"); - return Joi2.object().keys(config2); - }; - exports2.ref = function(id, options2) { - return Ref.isRef(id) ? id : Ref.create(id, options2); - }; - exports2.compile = function(root, schema) { - const any = schema && schema[Common.symbols.any]; - if (any) { - Assert(any.version === Common.version, "Cannot mix different versions of joi schemas:", any.version, Common.version); - return schema; + return patternCache[cacheKey2]; } - return exports2.schema(root, schema, { appendPath: true }); - }; - internals.simple = function(value) { - return value === null || ["boolean", "string", "number"].includes(typeof value); + return null; }; - exports2.when = function(schema, condition, options2) { - if (options2 === void 0) { - Assert(condition && typeof condition === "object", "Missing options"); - options2 = condition; - condition = Ref.create("."); - } - if (Array.isArray(options2)) { - options2 = { switch: options2 }; - } - Common.assertOptions(options2, ["is", "not", "then", "otherwise", "switch", "break"]); - if (Common.isSchema(condition)) { - Assert(options2.is === void 0, '"is" can not be used with a schema condition'); - Assert(options2.not === void 0, '"not" can not be used with a schema condition'); - Assert(options2.switch === void 0, '"switch" can not be used with a schema condition'); - return internals.condition(schema, { is: condition, then: options2.then, otherwise: options2.otherwise, break: options2.break }); - } - Assert(Ref.isRef(condition) || typeof condition === "string", "Invalid condition:", condition); - Assert(options2.not === void 0 || options2.is === void 0, 'Cannot combine "is" with "not"'); - if (options2.switch === void 0) { - let rule2 = options2; - if (options2.not !== void 0) { - rule2 = { is: options2.not, then: options2.otherwise, otherwise: options2.then, break: options2.break }; - } - let is = rule2.is !== void 0 ? schema.$_compile(rule2.is) : schema.$_root.invalid(null, false, 0, "").required(); - Assert(rule2.then !== void 0 || rule2.otherwise !== void 0, 'options must have at least one of "then", "otherwise", or "switch"'); - Assert(rule2.break === void 0 || rule2.then === void 0 || rule2.otherwise === void 0, "Cannot specify then, otherwise, and break all together"); - if (options2.is !== void 0 && !Ref.isRef(options2.is) && !Common.isSchema(options2.is)) { - is = is.required(); - } - return internals.condition(schema, { ref: exports2.ref(condition), is, then: rule2.then, otherwise: rule2.otherwise, break: rule2.break }); - } - Assert(Array.isArray(options2.switch), '"switch" must be an array'); - Assert(options2.is === void 0, 'Cannot combine "switch" with "is"'); - Assert(options2.not === void 0, 'Cannot combine "switch" with "not"'); - Assert(options2.then === void 0, 'Cannot combine "switch" with "then"'); - const rule = { - ref: exports2.ref(condition), - switch: [], - break: options2.break - }; - for (let i2 = 0; i2 < options2.switch.length; ++i2) { - const test = options2.switch[i2]; - const last = i2 === options2.switch.length - 1; - Common.assertOptions(test, last ? ["is", "then", "otherwise"] : ["is", "then"]); - Assert(test.is !== void 0, 'Switch statement missing "is"'); - Assert(test.then !== void 0, 'Switch statement missing "then"'); - const item = { - is: schema.$_compile(test.is), - then: schema.$_compile(test.then) - }; - if (!Ref.isRef(test.is) && !Common.isSchema(test.is)) { - item.is = item.is.required(); - } - if (last) { - Assert(options2.otherwise === void 0 || test.otherwise === void 0, 'Cannot specify "otherwise" inside and outside a "switch"'); - const otherwise = options2.otherwise !== void 0 ? options2.otherwise : test.otherwise; - if (otherwise !== void 0) { - Assert(rule.break === void 0, "Cannot specify both otherwise and break"); - item.otherwise = schema.$_compile(otherwise); + tryDecode = (str, decoder) => { + try { + return decoder(str); + } catch { + return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => { + try { + return decoder(match2); + } catch { + return match2; } - } - rule.switch.push(item); + }); } - return rule; }; - internals.condition = function(schema, condition) { - for (const key of ["then", "otherwise"]) { - if (condition[key] === void 0) { - delete condition[key]; - } else { - condition[key] = schema.$_compile(condition[key]); + tryDecodeURI = (str) => tryDecode(str, decodeURI); + getPath = (request) => { + const url2 = request.url; + const start = url2.indexOf("/", url2.indexOf(":") + 4); + let i2 = start; + for (; i2 < url2.length; i2++) { + const charCode = url2.charCodeAt(i2); + if (charCode === 37) { + const queryIndex = url2.indexOf("?", i2); + const hashIndex = url2.indexOf("#", i2); + const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex); + const path8 = url2.slice(start, end); + return tryDecodeURI(path8.includes("%25") ? path8.replace(/%25/g, "%2525") : path8); + } else if (charCode === 63 || charCode === 35) { + break; } } - return condition; + return url2.slice(start, i2); }; - } -}); -var require_annotate = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/annotate.js"(exports2) { - "use strict"; - var Clone = require_clone(); - var Common = require_common2(); - var internals = { - annotations: Symbol("annotations") + getPathNoStrict = (request) => { + const result = getPath(request); + return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result; }; - exports2.error = function(stripColorCodes) { - if (!this._original || typeof this._original !== "object") { - return this.details[0].message; + mergePath = (base2, sub, ...rest) => { + if (rest.length) { + sub = mergePath(sub, ...rest); } - const redFgEscape = stripColorCodes ? "" : "\x1B[31m"; - const redBgEscape = stripColorCodes ? "" : "\x1B[41m"; - const endColor = stripColorCodes ? "" : "\x1B[0m"; - const obj = Clone(this._original); - for (let i2 = this.details.length - 1; i2 >= 0; --i2) { - const pos = i2 + 1; - const error2 = this.details[i2]; - const path8 = error2.path; - let node = obj; - for (let j = 0; ; ++j) { - const seg = path8[j]; - if (Common.isSchema(node)) { - node = node.clone(); - } - if (j + 1 < path8.length && typeof node[seg] !== "string") { - node = node[seg]; - } else { - const refAnnotations = node[internals.annotations] || { errors: {}, missing: {} }; - node[internals.annotations] = refAnnotations; - const cacheKey = seg || error2.context.key; - if (node[seg] !== void 0) { - refAnnotations.errors[cacheKey] = refAnnotations.errors[cacheKey] || []; - refAnnotations.errors[cacheKey].push(pos); + return `${base2?.[0] === "/" ? "" : "/"}${base2}${sub === "/" ? "" : `${base2?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`; + }; + checkOptionalParameter = (path8) => { + if (path8.charCodeAt(path8.length - 1) !== 63 || !path8.includes(":")) { + return null; + } + const segments = path8.split("/"); + const results = []; + let basePath = ""; + segments.forEach((segment) => { + if (segment !== "" && !/\:/.test(segment)) { + basePath += "/" + segment; + } else if (/\:/.test(segment)) { + if (/\?/.test(segment)) { + if (results.length === 0 && basePath === "") { + results.push("/"); } else { - refAnnotations.missing[cacheKey] = pos; + results.push(basePath); } - break; + const optionalSegment = segment.replace("?", ""); + basePath += "/" + optionalSegment; + results.push(basePath); + } else { + basePath += "/" + segment; } } - } - const replacers = { - key: /_\$key\$_([, \d]+)_\$end\$_"/g, - missing: /"_\$miss\$_([^|]+)\|(\d+)_\$end\$_": "__missing__"/g, - arrayIndex: /\s*"_\$idx\$_([, \d]+)_\$end\$_",?\n(.*)/g, - specials: /"\[(NaN|Symbol.*|-?Infinity|function.*|\(.*)]"/g - }; - let message = internals.safeStringify(obj, 2).replace(replacers.key, ($0, $1) => `" ${redFgEscape}[${$1}]${endColor}`).replace(replacers.missing, ($0, $1, $2) => `${redBgEscape}"${$1}"${endColor}${redFgEscape} [${$2}]: -- missing --${endColor}`).replace(replacers.arrayIndex, ($0, $1, $2) => ` -${$2} ${redFgEscape}[${$1}]${endColor}`).replace(replacers.specials, ($0, $1) => $1); - message = `${message} -${redFgEscape}`; - for (let i2 = 0; i2 < this.details.length; ++i2) { - const pos = i2 + 1; - message = `${message} -[${pos}] ${this.details[i2].message}`; - } - message = message + endColor; - return message; + }); + return results.filter((v2, i2, a) => a.indexOf(v2) === i2); }; - internals.safeStringify = function(obj, spaces) { - return JSON.stringify(obj, internals.serializer(), spaces); + _decodeURI = (value) => { + if (!/[%+]/.test(value)) { + return value; + } + if (value.indexOf("+") !== -1) { + value = value.replace(/\+/g, " "); + } + return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value; }; - internals.serializer = function() { - const keys = []; - const stack = []; - const cycleReplacer = (key, value) => { - if (stack[0] === value) { - return "[Circular ~]"; + _getQueryParam = (url2, key, multiple) => { + let encoded; + if (!multiple && key && !/[%+]/.test(key)) { + let keyIndex2 = url2.indexOf("?", 8); + if (keyIndex2 === -1) { + return void 0; } - return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]"; - }; - return function(key, value) { - if (stack.length > 0) { - const thisPos = stack.indexOf(this); - if (~thisPos) { - stack.length = thisPos + 1; - keys.length = thisPos + 1; - keys[thisPos] = key; - } else { - stack.push(this); - keys.push(key); - } - if (~stack.indexOf(value)) { - value = cycleReplacer.call(this, key, value); - } - } else { - stack.push(value); + if (!url2.startsWith(key, keyIndex2 + 1)) { + keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); } - if (value) { - const annotations = value[internals.annotations]; - if (annotations) { - if (Array.isArray(value)) { - const annotated = []; - for (let i2 = 0; i2 < value.length; ++i2) { - if (annotations.errors[i2]) { - annotated.push(`_$idx$_${annotations.errors[i2].sort().join(", ")}_$end$_`); - } - annotated.push(value[i2]); - } - value = annotated; - } else { - for (const errorKey in annotations.errors) { - value[`${errorKey}_$key$_${annotations.errors[errorKey].sort().join(", ")}_$end$_`] = value[errorKey]; - value[errorKey] = void 0; - } - for (const missingKey in annotations.missing) { - value[`_$miss$_${missingKey}|${annotations.missing[missingKey]}_$end$_`] = "__missing__"; - } - } - return value; + while (keyIndex2 !== -1) { + const trailingKeyCode = url2.charCodeAt(keyIndex2 + key.length + 1); + if (trailingKeyCode === 61) { + const valueIndex = keyIndex2 + key.length + 2; + const endIndex = url2.indexOf("&", valueIndex); + return _decodeURI(url2.slice(valueIndex, endIndex === -1 ? void 0 : endIndex)); + } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) { + return ""; } + keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); } - if (value === Infinity || value === -Infinity || Number.isNaN(value) || typeof value === "function" || typeof value === "symbol") { - return "[" + value.toString() + "]"; - } - return value; - }; - }; - } -}); -var require_errors2 = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/errors.js"(exports2) { - "use strict"; - var Annotate = require_annotate(); - var Common = require_common2(); - var Template = require_template(); - exports2.Report = class { - constructor(code2, value, local, flags, messages, state, prefs) { - this.code = code2; - this.flags = flags; - this.messages = messages; - this.path = state.path; - this.prefs = prefs; - this.state = state; - this.value = value; - this.message = null; - this.local = local || {}; - this.local.label = exports2.label(this.flags, this.state, this.prefs, this.messages); - if (this.value !== void 0 && !this.local.hasOwnProperty("value")) { - this.local.value = this.value; - } - if (this.path.length) { - const key = this.path[this.path.length - 1]; - if (typeof key !== "object") { - this.local.key = key; - } + encoded = /[%+]/.test(url2); + if (!encoded) { + return void 0; } } - toString() { - if (this.message) { - return this.message; - } - const code2 = this.code; - if (!this.prefs.errors.render) { - return this.code; + const results = {}; + encoded ??= /[%+]/.test(url2); + let keyIndex = url2.indexOf("?", 8); + while (keyIndex !== -1) { + const nextKeyIndex = url2.indexOf("&", keyIndex + 1); + let valueIndex = url2.indexOf("=", keyIndex); + if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) { + valueIndex = -1; } - const template = this._template(this.prefs.messages) || this._template(this.messages); - if (template === void 0) { - return `Error code "${code2}" is not defined, your custom type is missing the correct messages definition`; - } - this.message = template.render(this.value, this.state, this.prefs, this.local, { errors: this.prefs.errors, messages: [this.prefs.messages, this.messages] }); - if (!this.prefs.errors.label) { - this.message = this.message.replace(/^"" /, "").trim(); + let name = url2.slice( + keyIndex + 1, + valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex + ); + if (encoded) { + name = _decodeURI(name); } - return this.message; - } - _template(messages) { - return exports2.template(this.value, messages, this.code, this.state, this.prefs); - } - }; - exports2.path = function(path8) { - let label = ""; - for (const segment of path8) { - if (typeof segment === "object") { + keyIndex = nextKeyIndex; + if (name === "") { continue; } - if (typeof segment === "string") { - if (label) { - label += "."; + let value; + if (valueIndex === -1) { + value = ""; + } else { + value = url2.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex); + if (encoded) { + value = _decodeURI(value); + } + } + if (multiple) { + if (!(results[name] && Array.isArray(results[name]))) { + results[name] = []; } - label += segment; + ; + results[name].push(value); } else { - label += `[${segment}]`; + results[name] ??= value; } } - return label; + return key ? results[key] : results; }; - exports2.template = function(value, messages, code2, state, prefs) { - if (Template.isTemplate(messages)) { - return code2 !== "root" ? messages : null; - } - let lang = prefs.errors.language; - if (Common.isResolvable(lang)) { - lang = lang.resolve(value, state, prefs); - } - if (lang && messages[lang] && messages[lang][code2] !== void 0) { - return messages[lang][code2]; - } - return messages[code2]; + getQueryParam = _getQueryParam; + getQueryParams = (url2, key) => { + return _getQueryParam(url2, key, true); }; - exports2.label = function(flags, state, prefs, messages) { - if (!prefs.errors.label) { - return ""; - } - let path8 = state.path; - if (prefs.errors.label === "key" && state.path.length > 1) { - path8 = state.path.slice(-1); + decodeURIComponent_ = decodeURIComponent; + } +}); +var tryDecodeURIComponent; +var HonoRequest; +var init_request = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/request.js"() { + init_http_exception(); + init_constants2(); + init_body(); + init_url(); + tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_); + HonoRequest = class { + /** + * `.raw` can get the raw Request object. + * + * @see {@link https://hono.dev/docs/api/request#raw} + * + * @example + * ```ts + * // For Cloudflare Workers + * app.post('/', async (c) => { + * const metadata = c.req.raw.cf?.hostMetadata? + * ... + * }) + * ``` + */ + raw; + #validatedData; + // Short name of validatedData + #matchResult; + routeIndex = 0; + /** + * `.path` can get the pathname of the request. + * + * @see {@link https://hono.dev/docs/api/request#path} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const pathname = c.req.path // `/about/me` + * }) + * ``` + */ + path; + bodyCache = {}; + constructor(request, path8 = "/", matchResult = [[]]) { + this.raw = request; + this.path = path8; + this.#matchResult = matchResult; + this.#validatedData = {}; } - const normalized = exports2.path(path8); - if (normalized) { - return normalized; + param(key) { + return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams(); } - return exports2.template(null, prefs.messages, "root", state, prefs) || exports2.template(null, messages, "root", state, prefs) || "value"; - }; - exports2.process = function(errors, original, prefs) { - if (!errors) { - return null; + #getDecodedParam(key) { + const paramKey = this.#matchResult[0][this.routeIndex][1][key]; + const param = this.#getParamValue(paramKey); + return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param; } - const { override, message, details } = exports2.details(errors); - if (override) { - return override; - } - if (prefs.errors.stack) { - return new exports2.ValidationError(message, details, original); - } - const limit = Error.stackTraceLimit; - Error.stackTraceLimit = 0; - const validationError = new exports2.ValidationError(message, details, original); - Error.stackTraceLimit = limit; - return validationError; - }; - exports2.details = function(errors, options2 = {}) { - let messages = []; - const details = []; - for (const item of errors) { - if (item instanceof Error) { - if (options2.override !== false) { - return { override: item }; - } - const message2 = item.toString(); - messages.push(message2); - details.push({ - message: message2, - type: "override", - context: { error: item } - }); - continue; + #getAllDecodedParams() { + const decoded = {}; + const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]); + for (const key of keys) { + const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]); + if (value !== void 0) { + decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value; + } } - const message = item.toString(); - messages.push(message); - details.push({ - message, - path: item.path.filter((v2) => typeof v2 !== "object"), - type: item.code, - context: item.local - }); + return decoded; } - if (messages.length > 1) { - messages = [...new Set(messages)]; + #getParamValue(paramKey) { + return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey; } - return { message: messages.join(". "), details }; - }; - exports2.ValidationError = class extends Error { - constructor(message, details, original) { - super(message); - this._original = original; - this.details = details; - } - static isError(err) { - return err instanceof exports2.ValidationError; - } - }; - exports2.ValidationError.prototype.isJoi = true; - exports2.ValidationError.prototype.name = "ValidationError"; - exports2.ValidationError.prototype.annotate = Annotate.error; - } -}); -var require_extend = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/extend.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Common = require_common2(); - var Messages = require_messages(); - exports2.type = function(from3, options2) { - const base2 = Object.getPrototypeOf(from3); - const prototype = Clone(base2); - const schema = from3._assign(Object.create(prototype)); - const def = Object.assign({}, options2); - delete def.base; - prototype._definition = def; - const parent = base2._definition || {}; - def.messages = Messages.merge(parent.messages, def.messages); - def.properties = Object.assign({}, parent.properties, def.properties); - schema.type = def.type; - def.flags = Object.assign({}, parent.flags, def.flags); - const terms = Object.assign({}, parent.terms); - if (def.terms) { - for (const name in def.terms) { - const term = def.terms[name]; - Assert(schema.$_terms[name] === void 0, "Invalid term override for", def.type, name); - schema.$_terms[name] = term.init; - terms[name] = term; - } - } - def.terms = terms; - if (!def.args) { - def.args = parent.args; - } - if (def.coerce) { - if (typeof def.coerce === "function") { - def.coerce = { method: def.coerce }; - } - if (def.coerce.from && !Array.isArray(def.coerce.from)) { - def.coerce = { method: def.coerce.method, from: [].concat(def.coerce.from) }; - } - } - def.coerce = def.coerce || parent.coerce; - def.validate = def.validate || parent.validate; - const rules = Object.assign({}, parent.rules); - if (def.rules) { - for (const name in def.rules) { - const rule = def.rules[name]; - Assert(typeof rule === "object", "Invalid rule definition for", def.type, name); - const method = rule.method; - if (method) { - Assert(!prototype[name], "Rule conflict in", def.type, name); - prototype[name] = method; - } - Assert(!rules[name], "Rule conflict in", def.type, name); - rules[name] = rule; - if (rule.alias) { - const aliases = [].concat(rule.alias); - for (const alias of aliases) { - prototype[alias] = rule.method; - } - } - if (rule.args) { - rule.argsByName = /* @__PURE__ */ new Map(); - rule.args = rule.args.map((arg) => { - if (typeof arg === "string") { - arg = { name: arg }; - } - Assert(!rule.argsByName.has(arg.name), "Duplicated argument name", arg.name); - rule.argsByName.set(arg.name, arg); - return arg; - }); - } - } + query(key) { + return getQueryParam(this.url, key); + } + queries(key) { + return getQueryParams(this.url, key); } - def.rules = rules; - if (def.overrides) { - prototype._super = base2; - schema.$_super = {}; - for (const override in def.overrides) { - Assert(base2[override], "Cannot override missing", override); - def.overrides[override][Common.symbols.parent] = base2[override]; - schema.$_super[override] = base2[override].bind(schema); + header(name) { + if (name) { + return this.raw.headers.get(name) ?? void 0; } - Object.assign(prototype, def.overrides); + const headerData = {}; + this.raw.headers.forEach((value, key) => { + headerData[key] = value; + }); + return headerData; } - def.cast = Object.assign({}, parent.cast, def.cast); - def.rebuild = def.rebuild || parent.rebuild; - return schema; - }; - } -}); -var require_modify = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/modify.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Common = require_common2(); - var Ref = require_ref(); - var internals = {}; - exports2.Ids = internals.Ids = class { - constructor() { - this._byId = /* @__PURE__ */ new Map(); - this._byKey = /* @__PURE__ */ new Map(); - this._schemaChain = false; - } - clone() { - const clone2 = new internals.Ids(); - clone2._byId = new Map(this._byId); - clone2._byKey = new Map(this._byKey); - clone2._schemaChain = this._schemaChain; - return clone2; + async parseBody(options2) { + return parseBody(this, options2); } - concat(source) { - if (source._schemaChain) { - this._schemaChain = true; + #cachedBody = (key) => { + const { bodyCache, raw: raw2 } = this; + const cachedBody = bodyCache[key]; + if (cachedBody) { + return cachedBody; } - for (const [id, value] of source._byId.entries()) { - Assert(!this._byKey.has(id), "Schema id conflicts with existing key:", id); - this._byId.set(id, value); - } - for (const [key, value] of source._byKey.entries()) { - Assert(!this._byId.has(key), "Schema key conflicts with existing id:", key); - this._byKey.set(key, value); + const anyCachedKey = Object.keys(bodyCache)[0]; + if (anyCachedKey) { + return bodyCache[anyCachedKey].then((body) => { + if (anyCachedKey === "json") { + body = JSON.stringify(body); + } + return new Response(body)[key](); + }); } + return bodyCache[key] = raw2[key](); + }; + /** + * `.json()` can parse Request body of type `application/json` + * + * @see {@link https://hono.dev/docs/api/request#json} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.json() + * }) + * ``` + */ + json() { + return this.#cachedBody("text").then((text) => JSON.parse(text)); } - reach(path8, behind = []) { - const current = path8[0]; - const node = this._get(current); - Assert(node, "Schema does not contain path", [...behind, ...path8].join(".")); - const forward = path8.slice(1); - if (!forward.length) { - return node.schema; - } - return node.schema._ids.reach(forward, [...behind, current]); + /** + * `.text()` can parse Request body of type `text/plain` + * + * @see {@link https://hono.dev/docs/api/request#text} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.text() + * }) + * ``` + */ + text() { + return this.#cachedBody("text"); } - register(schema, { key } = {}) { - if (!schema || !Common.isSchema(schema)) { - return; - } - if (schema.$_property("schemaChain") || schema._ids._schemaChain) { - this._schemaChain = true; - } - const id = schema._flags.id; - if (id) { - const existing = this._byId.get(id); - Assert(!existing || existing.schema === schema, "Cannot add different schemas with the same id:", id); - Assert(!this._byKey.has(id), "Schema id conflicts with existing key:", id); - this._byId.set(id, { schema, id }); - } - if (key) { - Assert(!this._byKey.has(key), "Schema already contains key:", key); - Assert(!this._byId.has(key), "Schema key conflicts with existing id:", key); - this._byKey.set(key, { schema, id: key }); - } + /** + * `.arrayBuffer()` parse Request body as an `ArrayBuffer` + * + * @see {@link https://hono.dev/docs/api/request#arraybuffer} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.arrayBuffer() + * }) + * ``` + */ + arrayBuffer() { + return this.#cachedBody("arrayBuffer"); } - reset() { - this._byId = /* @__PURE__ */ new Map(); - this._byKey = /* @__PURE__ */ new Map(); - this._schemaChain = false; + /** + * Parses the request body as a `Blob`. + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.blob(); + * }); + * ``` + * @see https://hono.dev/docs/api/request#blob + */ + blob() { + return this.#cachedBody("blob"); } - _get(id) { - return this._byId.get(id) || this._byKey.get(id); + /** + * Parses the request body as `FormData`. + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.formData(); + * }); + * ``` + * @see https://hono.dev/docs/api/request#formdata + */ + formData() { + return this.#cachedBody("formData"); } - }; - exports2.schema = function(schema, options2) { - let obj; - for (const name in schema._flags) { - if (name[0] === "_") { - continue; - } - const result = internals.scan(schema._flags[name], { source: "flags", name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - obj._flags[name] = result; - } + /** + * Adds validated data to the request. + * + * @param target - The target of the validation. + * @param data - The validated data to add. + */ + addValidatedData(target, data) { + this.#validatedData[target] = data; } - for (let i2 = 0; i2 < schema._rules.length; ++i2) { - const rule = schema._rules[i2]; - const result = internals.scan(rule.args, { source: "rules", name: rule.name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - const clone2 = Object.assign({}, rule); - clone2.args = result; - obj._rules[i2] = clone2; - const existingUnique = obj._singleRules.get(rule.name); - if (existingUnique === rule) { - obj._singleRules.set(rule.name, clone2); - } - } + valid(target) { + return this.#validatedData[target]; } - for (const name in schema.$_terms) { - if (name[0] === "_") { - continue; - } - const result = internals.scan(schema.$_terms[name], { source: "terms", name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - obj.$_terms[name] = result; - } + /** + * `.url()` can get the request url strings. + * + * @see {@link https://hono.dev/docs/api/request#url} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const url = c.req.url // `http://localhost:8787/about/me` + * ... + * }) + * ``` + */ + get url() { + return this.raw.url; } - return obj; - }; - internals.scan = function(item, source, options2, _path, _key) { - const path8 = _path || []; - if (item === null || typeof item !== "object") { - return; + /** + * `.method()` can get the method name of the request. + * + * @see {@link https://hono.dev/docs/api/request#method} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const method = c.req.method // `GET` + * }) + * ``` + */ + get method() { + return this.raw.method; } - let clone2; - if (Array.isArray(item)) { - for (let i2 = 0; i2 < item.length; ++i2) { - const key = source.name === "keys" && item[i2].key; - const result = internals.scan(item[i2], source, options2, [i2, ...path8], key); - if (result !== void 0) { - clone2 = clone2 || item.slice(); - clone2[i2] = result; - } - } - return clone2; + get [GET_MATCH_RESULT]() { + return this.#matchResult; } - if (options2.schema !== false && Common.isSchema(item) || options2.ref !== false && Ref.isRef(item)) { - const result = options2.each(item, { ...source, path: path8, key: _key }); - return result; + /** + * `.matchedRoutes()` can return a matched route in the handler + * + * @deprecated + * + * Use matchedRoutes helper defined in "hono/route" instead. + * + * @see {@link https://hono.dev/docs/api/request#matchedroutes} + * + * @example + * ```ts + * app.use('*', async function logger(c, next) { + * await next() + * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => { + * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]') + * console.log( + * method, + * ' ', + * path, + * ' '.repeat(Math.max(10 - path.length, 0)), + * name, + * i === c.req.routeIndex ? '<- respond from here' : '' + * ) + * }) + * }) + * ``` + */ + get matchedRoutes() { + return this.#matchResult[0].map(([[, route]]) => route); } - for (const key in item) { - if (key[0] === "_") { - continue; - } - const result = internals.scan(item[key], source, options2, [key, ...path8], _key); - if (result !== void 0) { - clone2 = clone2 || Object.assign({}, item); - clone2[key] = result; - } + /** + * `routePath()` can retrieve the path registered within the handler + * + * @deprecated + * + * Use routePath helper defined in "hono/route" instead. + * + * @see {@link https://hono.dev/docs/api/request#routepath} + * + * @example + * ```ts + * app.get('/posts/:id', (c) => { + * return c.json({ path: c.req.routePath }) + * }) + * ``` + */ + get routePath() { + return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path; } - return clone2; }; } }); -var require_state = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/state.js"(exports2, module14) { - "use strict"; - var Clone = require_clone(); - var Reach = require_reach(); - var Common = require_common2(); - var internals = { - value: Symbol("value") - }; - module14.exports = internals.State = class { - constructor(path8, ancestors, state) { - this.path = path8; - this.ancestors = ancestors; - this.mainstay = state.mainstay; - this.schemas = state.schemas; - } - localize(path8, ancestors = null, schema = null) { - const state = new internals.State(path8, ancestors, this); - if (schema && state.schemas) { - state.schemas = [internals.schemas(schema), ...state.schemas]; - } - return state; - } - nest(schema) { - const state = new internals.State(this.path, this.ancestors, this); - state.schemas = state.schemas && [internals.schemas(schema), ...state.schemas]; - return state; - } - shadow(value, reason) { - this.mainstay.shadow = this.mainstay.shadow || new internals.Shadow(); - this.mainstay.shadow.set(this.path, value, reason); - } - snapshot() { - if (this.mainstay.shadow) { - this._snapshot = Clone(this.mainstay.shadow.node(this.path)); - } - } - restore() { - if (this.mainstay.shadow) { - this.mainstay.shadow.override(this.path, this._snapshot); - this._snapshot = void 0; - } - } +var HtmlEscapedCallbackPhase; +var raw; +var resolveCallback; +var init_html = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/html.js"() { + HtmlEscapedCallbackPhase = { + Stringify: 1, + BeforeStream: 2, + Stream: 3 }; - internals.schemas = function(schema) { - if (Common.isSchema(schema)) { - return { schema }; - } - return schema; + raw = (value, callbacks) => { + const escapedString = new String(value); + escapedString.isEscaped = true; + escapedString.callbacks = callbacks; + return escapedString; }; - internals.Shadow = class { - constructor() { - this._values = null; - } - set(path8, value, reason) { - if (!path8.length) { - return; - } - if (reason === "strip" && typeof path8[path8.length - 1] === "number") { - return; + resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => { + if (typeof str === "object" && !(str instanceof String)) { + if (!(str instanceof Promise)) { + str = str.toString(); } - this._values = this._values || /* @__PURE__ */ new Map(); - let node = this._values; - for (let i2 = 0; i2 < path8.length; ++i2) { - const segment = path8[i2]; - let next = node.get(segment); - if (!next) { - next = /* @__PURE__ */ new Map(); - node.set(segment, next); - } - node = next; + if (str instanceof Promise) { + str = await str; } - node[internals.value] = value; } - get(path8) { - const node = this.node(path8); - if (node) { - return node[internals.value]; - } + const callbacks = str.callbacks; + if (!callbacks?.length) { + return Promise.resolve(str); } - node(path8) { - if (!this._values) { - return; - } - return Reach(this._values, path8, { iterables: true }); + if (buffer) { + buffer[0] += str; + } else { + buffer = [str]; } - override(path8, node) { - if (!this._values) { - return; - } - const parents = path8.slice(0, -1); - const own = path8[path8.length - 1]; - const parent = Reach(this._values, parents, { iterables: true }); - if (node) { - parent.set(own, node); - return; - } - if (parent) { - parent.delete(own); - } + const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then( + (res) => Promise.all( + res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer)) + ).then(() => buffer[0]) + ); + if (preserveCallbacks) { + return raw(await resStr, callbacks); + } else { + return resStr; } }; } }); -var require_validator = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/validator.js"(exports2) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Common = require_common2(); - var Errors = require_errors2(); - var State = require_state(); - var internals = { - result: Symbol("result") - }; - exports2.entry = function(value, schema, prefs) { - let settings = Common.defaults; - if (prefs) { - settings = Common.preferences(Common.defaults, prefs); - } - const result = internals.entry(value, schema, settings); - const outcome = { value: result.value }; - if (result.error) { - outcome.error = result.error; - } - return outcome; - }; - internals.entry = function(value, schema, prefs) { - const links = schema._ids._schemaChain ? /* @__PURE__ */ new Map() : null; - const mainstay = { links }; - const schemas = schema._ids._schemaChain ? [{ schema }] : null; - const state = new State([], [], { mainstay, schemas }); - const result = exports2.validate(value, schema, state, prefs); - const error2 = Errors.process(result.errors, value, prefs); - return { value: result.value, error: error2, mainstay }; - }; - exports2.validate = function(value, schema, state, prefs, overrides = {}) { - if (schema.$_terms.whens) { - schema = schema._generate(value, state, prefs).schema; - } - if (schema._preferences) { - prefs = internals.prefs(schema, prefs); - } - const createError = (code2, local, localState) => schema.$_createError(code2, value, local, localState || state, prefs); - const helpers = { - original: value, - prefs, - schema, - state, - error: createError, - errorsArray: internals.errorsArray, - message: (messages, local) => schema.$_createError("custom", value, local, state, prefs, { messages }) +var TEXT_PLAIN; +var setDefaultContentType; +var createResponseInstance; +var Context; +var init_context = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/context.js"() { + init_request(); + init_html(); + TEXT_PLAIN = "text/plain; charset=UTF-8"; + setDefaultContentType = (contentType, headers) => { + return { + "Content-Type": contentType, + ...headers }; - const def = schema._definition; - if (def.coerce && value !== void 0 && prefs.convert && (!def.coerce.from || def.coerce.from.includes(typeof value))) { - const coerced = def.coerce.method(value, helpers); - if (coerced) { - if (coerced.errors) { - return internals.finalize(coerced.value, [].concat(coerced.errors), helpers); - } - value = coerced.value; + }; + createResponseInstance = (body, init2) => new Response(body, init2); + Context = class { + #rawRequest; + #req; + /** + * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers. + * + * @see {@link https://hono.dev/docs/api/context#env} + * + * @example + * ```ts + * // Environment object for Cloudflare Workers + * app.get('*', async c => { + * const counter = c.env.COUNTER + * }) + * ``` + */ + env = {}; + #var; + finalized = false; + /** + * `.error` can get the error object from the middleware if the Handler throws an error. + * + * @see {@link https://hono.dev/docs/api/context#error} + * + * @example + * ```ts + * app.use('*', async (c, next) => { + * await next() + * if (c.error) { + * // do something... + * } + * }) + * ``` + */ + error; + #status; + #executionCtx; + #res; + #layout; + #renderer; + #notFoundHandler; + #preparedHeaders; + #matchResult; + #path; + /** + * Creates an instance of the Context class. + * + * @param req - The Request object. + * @param options - Optional configuration options for the context. + */ + constructor(req, options2) { + this.#rawRequest = req; + if (options2) { + this.#executionCtx = options2.executionCtx; + this.env = options2.env; + this.#notFoundHandler = options2.notFoundHandler; + this.#path = options2.path; + this.#matchResult = options2.matchResult; } } - const empty2 = schema._flags.empty; - if (empty2 && empty2.$_match(internals.trim(value, schema), state.nest(empty2), Common.defaults)) { - value = void 0; + /** + * `.req` is the instance of {@link HonoRequest}. + */ + get req() { + this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult); + return this.#req; } - const presence = overrides.presence || schema._flags.presence || (schema._flags._endedSwitch ? null : prefs.presence); - if (value === void 0) { - if (presence === "forbidden") { - return internals.finalize(value, null, helpers); - } - if (presence === "required") { - return internals.finalize(value, [schema.$_createError("any.required", value, null, state, prefs)], helpers); - } - if (presence === "optional") { - if (schema._flags.default !== Common.symbols.deepDefault) { - return internals.finalize(value, null, helpers); - } - value = {}; + /** + * @see {@link https://hono.dev/docs/api/context#event} + * The FetchEvent associated with the current request. + * + * @throws Will throw an error if the context does not have a FetchEvent. + */ + get event() { + if (this.#executionCtx && "respondWith" in this.#executionCtx) { + return this.#executionCtx; + } else { + throw Error("This context has no FetchEvent"); } - } else if (presence === "forbidden") { - return internals.finalize(value, [schema.$_createError("any.unknown", value, null, state, prefs)], helpers); } - const errors = []; - if (schema._valids) { - const match = schema._valids.get(value, state, prefs, schema._flags.insensitive); - if (match) { - if (prefs.convert) { - value = match.value; - } - return internals.finalize(value, null, helpers); - } - if (schema._flags.only) { - const report = schema.$_createError("any.only", value, { valids: schema._valids.values({ display: true }) }, state, prefs); - if (prefs.abortEarly) { - return internals.finalize(value, [report], helpers); - } - errors.push(report); + /** + * @see {@link https://hono.dev/docs/api/context#executionctx} + * The ExecutionContext associated with the current request. + * + * @throws Will throw an error if the context does not have an ExecutionContext. + */ + get executionCtx() { + if (this.#executionCtx) { + return this.#executionCtx; + } else { + throw Error("This context has no ExecutionContext"); } } - if (schema._invalids) { - const match = schema._invalids.get(value, state, prefs, schema._flags.insensitive); - if (match) { - const report = schema.$_createError("any.invalid", value, { invalids: schema._invalids.values({ display: true }) }, state, prefs); - if (prefs.abortEarly) { - return internals.finalize(value, [report], helpers); - } - errors.push(report); - } + /** + * @see {@link https://hono.dev/docs/api/context#res} + * The Response object for the current request. + */ + get res() { + return this.#res ||= createResponseInstance(null, { + headers: this.#preparedHeaders ??= new Headers() + }); } - if (def.validate) { - const base2 = def.validate(value, helpers); - if (base2) { - value = base2.value; - if (base2.errors) { - if (!Array.isArray(base2.errors)) { - errors.push(base2.errors); - return internals.finalize(value, errors, helpers); + /** + * Sets the Response object for the current request. + * + * @param _res - The Response object to set. + */ + set res(_res) { + if (this.#res && _res) { + _res = createResponseInstance(_res.body, _res); + for (const [k, v2] of this.#res.headers.entries()) { + if (k === "content-type") { + continue; } - if (base2.errors.length) { - errors.push(...base2.errors); - return internals.finalize(value, errors, helpers); + if (k === "set-cookie") { + const cookies = this.#res.headers.getSetCookie(); + _res.headers.delete("set-cookie"); + for (const cookie of cookies) { + _res.headers.append("set-cookie", cookie); + } + } else { + _res.headers.set(k, v2); } } } + this.#res = _res; + this.finalized = true; } - if (!schema._rules.length) { - return internals.finalize(value, errors, helpers); - } - return internals.rules(value, errors, helpers); - }; - internals.rules = function(value, errors, helpers) { - const { schema, state, prefs } = helpers; - for (const rule of schema._rules) { - const definition = schema._definition.rules[rule.method]; - if (definition.convert && prefs.convert) { - continue; - } - let ret; - let args = rule.args; - if (rule._resolve.length) { - args = Object.assign({}, args); - for (const key of rule._resolve) { - const resolver = definition.argsByName.get(key); - const resolved = args[key].resolve(value, state, prefs); - const normalized = resolver.normalize ? resolver.normalize(resolved) : resolved; - const invalid = Common.validateArg(normalized, null, resolver); - if (invalid) { - ret = schema.$_createError("any.ref", resolved, { arg: key, ref: args[key], reason: invalid }, state, prefs); - break; - } - args[key] = normalized; - } + /** + * `.render()` can create a response within a layout. + * + * @see {@link https://hono.dev/docs/api/context#render-setrenderer} + * + * @example + * ```ts + * app.get('/', (c) => { + * return c.render('Hello!') + * }) + * ``` + */ + render = (...args) => { + this.#renderer ??= (content) => this.html(content); + return this.#renderer(...args); + }; + /** + * Sets the layout for the response. + * + * @param layout - The layout to set. + * @returns The layout function. + */ + setLayout = (layout) => this.#layout = layout; + /** + * Gets the current layout for the response. + * + * @returns The current layout function. + */ + getLayout = () => this.#layout; + /** + * `.setRenderer()` can set the layout in the custom middleware. + * + * @see {@link https://hono.dev/docs/api/context#render-setrenderer} + * + * @example + * ```tsx + * app.use('*', async (c, next) => { + * c.setRenderer((content) => { + * return c.html( + * + * + *

{content}

+ * + * + * ) + * }) + * await next() + * }) + * ``` + */ + setRenderer = (renderer) => { + this.#renderer = renderer; + }; + /** + * `.header()` can set headers. + * + * @see {@link https://hono.dev/docs/api/context#header} + * + * @example + * ```ts + * app.get('/welcome', (c) => { + * // Set headers + * c.header('X-Message', 'Hello!') + * c.header('Content-Type', 'text/plain') + * + * return c.body('Thank you for coming') + * }) + * ``` + */ + header = (name, value, options2) => { + if (this.finalized) { + this.#res = createResponseInstance(this.#res.body, this.#res); } - ret = ret || definition.validate(value, helpers, args, rule); - const result = internals.rule(ret, rule); - if (result.errors) { - if (prefs.abortEarly) { - return internals.finalize(value, result.errors, helpers); - } - errors.push(...result.errors); + const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers(); + if (value === void 0) { + headers.delete(name); + } else if (options2?.append) { + headers.append(name, value); } else { - value = result.value; + headers.set(name, value); } - } - return internals.finalize(value, errors, helpers); - }; - internals.rule = function(ret, rule) { - if (ret instanceof Errors.Report) { - return { errors: [ret], value: null }; - } - if (Array.isArray(ret) && ret[Common.symbols.errors]) { - return { errors: ret, value: null }; - } - return { errors: null, value: ret }; - }; - internals.finalize = function(value, errors, helpers) { - errors = errors || []; - const { schema, state } = helpers; - if (errors.length) { - const failover = internals.default("failover", void 0, errors, helpers); - if (failover !== void 0) { - value = failover; - errors = []; + }; + status = (status) => { + this.#status = status; + }; + /** + * `.set()` can set the value specified by the key. + * + * @see {@link https://hono.dev/docs/api/context#set-get} + * + * @example + * ```ts + * app.use('*', async (c, next) => { + * c.set('message', 'Hono is hot!!') + * await next() + * }) + * ``` + */ + set = (key, value) => { + this.#var ??= /* @__PURE__ */ new Map(); + this.#var.set(key, value); + }; + /** + * `.get()` can use the value specified by the key. + * + * @see {@link https://hono.dev/docs/api/context#set-get} + * + * @example + * ```ts + * app.get('/', (c) => { + * const message = c.get('message') + * return c.text(`The message is "${message}"`) + * }) + * ``` + */ + get = (key) => { + return this.#var ? this.#var.get(key) : void 0; + }; + /** + * `.var` can access the value of a variable. + * + * @see {@link https://hono.dev/docs/api/context#var} + * + * @example + * ```ts + * const result = c.var.client.oneMethod() + * ``` + */ + // c.var.propName is a read-only + get var() { + if (!this.#var) { + return {}; } + return Object.fromEntries(this.#var); } - if (errors.length && schema._flags.error) { - if (typeof schema._flags.error === "function") { - errors = schema._flags.error(errors); - if (!Array.isArray(errors)) { - errors = [errors]; - } - for (const error2 of errors) { - Assert(error2 instanceof Error || error2 instanceof Errors.Report, "error() must return an Error object"); + #newResponse(data, arg, headers) { + const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers(); + if (typeof arg === "object" && "headers" in arg) { + const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers); + for (const [key, value] of argHeaders) { + if (key.toLowerCase() === "set-cookie") { + responseHeaders.append(key, value); + } else { + responseHeaders.set(key, value); + } } - } else { - errors = [schema._flags.error]; } - } - if (value === void 0) { - const defaulted = internals.default("default", value, errors, helpers); - value = defaulted; - } - if (schema._flags.cast && value !== void 0) { - const caster = schema._definition.cast[schema._flags.cast]; - if (caster.from(value)) { - const casted = caster.to(value, helpers); - value = casted; + if (headers) { + for (const [k, v2] of Object.entries(headers)) { + if (typeof v2 === "string") { + responseHeaders.set(k, v2); + } else { + responseHeaders.delete(k); + for (const v22 of v2) { + responseHeaders.append(k, v22); + } + } + } } + const status = typeof arg === "number" ? arg : arg?.status ?? this.#status; + return createResponseInstance(data, { status, headers: responseHeaders }); } - const result = { value, errors: errors.length ? errors : null }; - if (schema._flags.result) { - result.value = schema._flags.result === "strip" ? void 0 : ( - /* raw */ - helpers.original + newResponse = (...args) => this.#newResponse(...args); + /** + * `.body()` can return the HTTP response. + * You can set headers with `.header()` and set HTTP status code with `.status`. + * This can also be set in `.text()`, `.json()` and so on. + * + * @see {@link https://hono.dev/docs/api/context#body} + * + * @example + * ```ts + * app.get('/welcome', (c) => { + * // Set headers + * c.header('X-Message', 'Hello!') + * c.header('Content-Type', 'text/plain') + * // Set HTTP status code + * c.status(201) + * + * // Return the response body + * return c.body('Thank you for coming') + * }) + * ``` + */ + body = (data, arg, headers) => this.#newResponse(data, arg, headers); + /** + * `.text()` can render text as `Content-Type:text/plain`. + * + * @see {@link https://hono.dev/docs/api/context#text} + * + * @example + * ```ts + * app.get('/say', (c) => { + * return c.text('Hello!') + * }) + * ``` + */ + text = (text, arg, headers) => { + return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse( + text, + arg, + setDefaultContentType(TEXT_PLAIN, headers) ); - state.shadow(value, schema._flags.result); - } - return result; + }; + /** + * `.json()` can render JSON as `Content-Type:application/json`. + * + * @see {@link https://hono.dev/docs/api/context#json} + * + * @example + * ```ts + * app.get('/api', (c) => { + * return c.json({ message: 'Hello!' }) + * }) + * ``` + */ + json = (object2, arg, headers) => { + return this.#newResponse( + JSON.stringify(object2), + arg, + setDefaultContentType("application/json", headers) + ); + }; + html = (html2, arg, headers) => { + const res = (html22) => this.#newResponse(html22, arg, setDefaultContentType("text/html; charset=UTF-8", headers)); + return typeof html2 === "object" ? resolveCallback(html2, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html2); + }; + /** + * `.redirect()` can Redirect, default status code is 302. + * + * @see {@link https://hono.dev/docs/api/context#redirect} + * + * @example + * ```ts + * app.get('/redirect', (c) => { + * return c.redirect('/') + * }) + * app.get('/redirect-permanently', (c) => { + * return c.redirect('/', 301) + * }) + * ``` + */ + redirect = (location, status) => { + const locationString = String(location); + this.header( + "Location", + // Multibyes should be encoded + // eslint-disable-next-line no-control-regex + !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString) + ); + return this.newResponse(null, status ?? 302); + }; + /** + * `.notFound()` can return the Not Found Response. + * + * @see {@link https://hono.dev/docs/api/context#notfound} + * + * @example + * ```ts + * app.get('/notfound', (c) => { + * return c.notFound() + * }) + * ``` + */ + notFound = () => { + this.#notFoundHandler ??= () => createResponseInstance(); + return this.#notFoundHandler(this); + }; }; - internals.prefs = function(schema, prefs) { - const isDefaultOptions = prefs === Common.defaults; - if (isDefaultOptions && schema._preferences[Common.symbols.prefs]) { - return schema._preferences[Common.symbols.prefs]; - } - prefs = Common.preferences(prefs, schema._preferences); - if (isDefaultOptions) { - schema._preferences[Common.symbols.prefs] = prefs; + } +}); +var METHOD_NAME_ALL; +var METHOD_NAME_ALL_LOWERCASE; +var METHODS; +var MESSAGE_MATCHER_IS_ALREADY_BUILT; +var UnsupportedPathError; +var init_router = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router.js"() { + METHOD_NAME_ALL = "ALL"; + METHOD_NAME_ALL_LOWERCASE = "all"; + METHODS = ["get", "post", "put", "delete", "options", "patch"]; + MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built."; + UnsupportedPathError = class extends Error { + }; + } +}); +var COMPOSED_HANDLER; +var init_constants3 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/constants.js"() { + COMPOSED_HANDLER = "__COMPOSED_HANDLER"; + } +}); +var notFoundHandler; +var errorHandler; +var Hono; +var init_hono_base = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/hono-base.js"() { + init_compose(); + init_context(); + init_router(); + init_constants3(); + init_url(); + notFoundHandler = (c) => { + return c.text("404 Not Found", 404); + }; + errorHandler = (err, c) => { + if ("getResponse" in err) { + const res = err.getResponse(); + return c.newResponse(res.body, res); + } + console.error(err); + return c.text("Internal Server Error", 500); + }; + Hono = class _Hono { + get; + post; + put; + delete; + options; + patch; + all; + on; + use; + /* + This class is like an abstract class and does not have a router. + To use it, inherit the class and implement router in the constructor. + */ + router; + getPath; + // Cannot use `#` because it requires visibility at JavaScript runtime. + _basePath = "/"; + #path = "/"; + routes = []; + constructor(options2 = {}) { + const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE]; + allMethods.forEach((method) => { + this[method] = (args1, ...args) => { + if (typeof args1 === "string") { + this.#path = args1; + } else { + this.#addRoute(method, this.#path, args1); + } + args.forEach((handler) => { + this.#addRoute(method, this.#path, handler); + }); + return this; + }; + }); + this.on = (method, path8, ...handlers) => { + for (const p of [path8].flat()) { + this.#path = p; + for (const m3 of [method].flat()) { + handlers.map((handler) => { + this.#addRoute(m3.toUpperCase(), this.#path, handler); + }); + } + } + return this; + }; + this.use = (arg1, ...handlers) => { + if (typeof arg1 === "string") { + this.#path = arg1; + } else { + this.#path = "*"; + handlers.unshift(arg1); + } + handlers.forEach((handler) => { + this.#addRoute(METHOD_NAME_ALL, this.#path, handler); + }); + return this; + }; + const { strict, ...optionsWithoutStrict } = options2; + Object.assign(this, optionsWithoutStrict); + this.getPath = strict ?? true ? options2.getPath ?? getPath : getPathNoStrict; + } + #clone() { + const clone2 = new _Hono({ + router: this.router, + getPath: this.getPath + }); + clone2.errorHandler = this.errorHandler; + clone2.#notFoundHandler = this.#notFoundHandler; + clone2.routes = this.routes; + return clone2; } - return prefs; - }; - internals.default = function(flag, value, errors, helpers) { - const { schema, state, prefs } = helpers; - const source = schema._flags[flag]; - if (prefs.noDefaults || source === void 0) { - return value; + #notFoundHandler = notFoundHandler; + // Cannot use `#` because it requires visibility at JavaScript runtime. + errorHandler = errorHandler; + /** + * `.route()` allows grouping other Hono instance in routes. + * + * @see {@link https://hono.dev/docs/api/routing#grouping} + * + * @param {string} path - base Path + * @param {Hono} app - other Hono instance + * @returns {Hono} routed Hono instance + * + * @example + * ```ts + * const app = new Hono() + * const app2 = new Hono() + * + * app2.get("/user", (c) => c.text("user")) + * app.route("/api", app2) // GET /api/user + * ``` + */ + route(path8, app3) { + const subApp = this.basePath(path8); + app3.routes.map((r) => { + let handler; + if (app3.errorHandler === errorHandler) { + handler = r.handler; + } else { + handler = async (c, next) => (await compose([], app3.errorHandler)(c, () => r.handler(c, next))).res; + handler[COMPOSED_HANDLER] = r.handler; + } + subApp.#addRoute(r.method, r.path, handler); + }); + return this; } - if (!source) { - return source; + /** + * `.basePath()` allows base paths to be specified. + * + * @see {@link https://hono.dev/docs/api/routing#base-path} + * + * @param {string} path - base Path + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * const api = new Hono().basePath('/api') + * ``` + */ + basePath(path8) { + const subApp = this.#clone(); + subApp._basePath = mergePath(this._basePath, path8); + return subApp; } - if (typeof source === "function") { - const args = source.length ? [Clone(state.ancestors[0]), helpers] : []; - try { - return source(...args); - } catch (err) { - errors.push(schema.$_createError(`any.${flag}`, null, { error: err }, state, prefs)); - return; + /** + * `.onError()` handles an error and returns a customized Response. + * + * @see {@link https://hono.dev/docs/api/hono#error-handling} + * + * @param {ErrorHandler} handler - request Handler for error + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * app.onError((err, c) => { + * console.error(`${err}`) + * return c.text('Custom Error Message', 500) + * }) + * ``` + */ + onError = (handler) => { + this.errorHandler = handler; + return this; + }; + /** + * `.notFound()` allows you to customize a Not Found Response. + * + * @see {@link https://hono.dev/docs/api/hono#not-found} + * + * @param {NotFoundHandler} handler - request handler for not-found + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * app.notFound((c) => { + * return c.text('Custom 404 Message', 404) + * }) + * ``` + */ + notFound = (handler) => { + this.#notFoundHandler = handler; + return this; + }; + /** + * `.mount()` allows you to mount applications built with other frameworks into your Hono application. + * + * @see {@link https://hono.dev/docs/api/hono#mount} + * + * @param {string} path - base Path + * @param {Function} applicationHandler - other Request Handler + * @param {MountOptions} [options] - options of `.mount()` + * @returns {Hono} mounted Hono instance + * + * @example + * ```ts + * import { Router as IttyRouter } from 'itty-router' + * import { Hono } from 'hono' + * // Create itty-router application + * const ittyRouter = IttyRouter() + * // GET /itty-router/hello + * ittyRouter.get('/hello', () => new Response('Hello from itty-router')) + * + * const app = new Hono() + * app.mount('/itty-router', ittyRouter.handle) + * ``` + * + * @example + * ```ts + * const app = new Hono() + * // Send the request to another application without modification. + * app.mount('/app', anotherApp, { + * replaceRequest: (req) => req, + * }) + * ``` + */ + mount(path8, applicationHandler, options2) { + let replaceRequest; + let optionHandler; + if (options2) { + if (typeof options2 === "function") { + optionHandler = options2; + } else { + optionHandler = options2.optionHandler; + if (options2.replaceRequest === false) { + replaceRequest = (request) => request; + } else { + replaceRequest = options2.replaceRequest; + } + } } + const getOptions = optionHandler ? (c) => { + const options22 = optionHandler(c); + return Array.isArray(options22) ? options22 : [options22]; + } : (c) => { + let executionContext = void 0; + try { + executionContext = c.executionCtx; + } catch { + } + return [c.env, executionContext]; + }; + replaceRequest ||= (() => { + const mergedPath = mergePath(this._basePath, path8); + const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length; + return (request) => { + const url2 = new URL(request.url); + url2.pathname = url2.pathname.slice(pathPrefixLength) || "/"; + return new Request(url2, request); + }; + })(); + const handler = async (c, next) => { + const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c)); + if (res) { + return res; + } + await next(); + }; + this.#addRoute(METHOD_NAME_ALL, mergePath(path8, "*"), handler); + return this; } - if (typeof source !== "object") { - return source; - } - if (source[Common.symbols.literal]) { - return source.literal; - } - if (Common.isResolvable(source)) { - return source.resolve(value, state, prefs); + #addRoute(method, path8, handler) { + method = method.toUpperCase(); + path8 = mergePath(this._basePath, path8); + const r = { basePath: this._basePath, path: path8, method, handler }; + this.router.add(method, path8, [handler, r]); + this.routes.push(r); } - return Clone(source); - }; - internals.trim = function(value, schema) { - if (typeof value !== "string") { - return value; + #handleError(err, c) { + if (err instanceof Error) { + return this.errorHandler(err, c); + } + throw err; } - const trim = schema.$_getRule("trim"); - if (!trim || !trim.args.enabled) { - return value; + #dispatch(request, executionCtx, env2, method) { + if (method === "HEAD") { + return (async () => new Response(null, await this.#dispatch(request, executionCtx, env2, "GET")))(); + } + const path8 = this.getPath(request, { env: env2 }); + const matchResult = this.router.match(method, path8); + const c = new Context(request, { + path: path8, + matchResult, + env: env2, + executionCtx, + notFoundHandler: this.#notFoundHandler + }); + if (matchResult[0].length === 1) { + let res; + try { + res = matchResult[0][0][0][0](c, async () => { + c.res = await this.#notFoundHandler(c); + }); + } catch (err) { + return this.#handleError(err, c); + } + return res instanceof Promise ? res.then( + (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c)) + ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c); + } + const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler); + return (async () => { + try { + const context = await composed(c); + if (!context.finalized) { + throw new Error( + "Context is not finalized. Did you forget to return a Response object or `await next()`?" + ); + } + return context.res; + } catch (err) { + return this.#handleError(err, c); + } + })(); } - return value.trim(); - }; - internals.errorsArray = function() { - const errors = []; - errors[Common.symbols.errors] = true; - return errors; + /** + * `.fetch()` will be entry point of your app. + * + * @see {@link https://hono.dev/docs/api/hono#fetch} + * + * @param {Request} request - request Object of request + * @param {Env} Env - env Object + * @param {ExecutionContext} - context of execution + * @returns {Response | Promise} response of request + * + */ + fetch = (request, ...rest) => { + return this.#dispatch(request, rest[1], rest[0], request.method); + }; + /** + * `.request()` is a useful method for testing. + * You can pass a URL or pathname to send a GET request. + * app will return a Response object. + * ```ts + * test('GET /hello is ok', async () => { + * const res = await app.request('/hello') + * expect(res.status).toBe(200) + * }) + * ``` + * @see https://hono.dev/docs/api/hono#request + */ + request = (input, requestInit, Env, executionCtx) => { + if (input instanceof Request) { + return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx); + } + input = input.toString(); + return this.fetch( + new Request( + /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, + requestInit + ), + Env, + executionCtx + ); + }; + /** + * `.fire()` automatically adds a global fetch event listener. + * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers. + * @deprecated + * Use `fire` from `hono/service-worker` instead. + * ```ts + * import { Hono } from 'hono' + * import { fire } from 'hono/service-worker' + * + * const app = new Hono() + * // ... + * fire(app) + * ``` + * @see https://hono.dev/docs/api/hono#fire + * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API + * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/ + */ + fire = () => { + addEventListener("fetch", (event) => { + event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method)); + }); + }; }; } }); -var require_values = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/values.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var DeepEqual = require_deepEqual(); - var Common = require_common2(); - var internals = {}; - module14.exports = internals.Values = class { - constructor(values, refs) { - this._values = new Set(values); - this._refs = new Set(refs); - this._lowercase = internals.lowercases(values); - this._override = false; - } - get length() { - return this._values.size + this._refs.size; - } - add(value, refs) { - if (Common.isResolvable(value)) { - if (!this._refs.has(value)) { - this._refs.add(value); - if (refs) { - refs.register(value); - } +function match(method, path8) { + const matchers = this.buildAllMatchers(); + const match2 = (method2, path22) => { + const matcher = matchers[method2] || matchers[METHOD_NAME_ALL]; + const staticMatch = matcher[2][path22]; + if (staticMatch) { + return staticMatch; + } + const match3 = path22.match(matcher[0]); + if (!match3) { + return [[], emptyParam]; + } + const index = match3.indexOf("", 1); + return [matcher[1][index], match3]; + }; + this.match = match2; + return match2(method, path8); +} +var emptyParam; +var init_matcher = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/matcher.js"() { + init_router(); + emptyParam = []; + } +}); +function compareKey(a, b) { + if (a.length === 1) { + return b.length === 1 ? a < b ? -1 : 1 : -1; + } + if (b.length === 1) { + return 1; + } + if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) { + return 1; + } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) { + return -1; + } + if (a === LABEL_REG_EXP_STR) { + return 1; + } else if (b === LABEL_REG_EXP_STR) { + return -1; + } + return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length; +} +var LABEL_REG_EXP_STR; +var ONLY_WILDCARD_REG_EXP_STR; +var TAIL_WILDCARD_REG_EXP_STR; +var PATH_ERROR; +var regExpMetaChars; +var Node; +var init_node = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/node.js"() { + LABEL_REG_EXP_STR = "[^/]+"; + ONLY_WILDCARD_REG_EXP_STR = ".*"; + TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)"; + PATH_ERROR = /* @__PURE__ */ Symbol(); + regExpMetaChars = new Set(".\\+*[^]$()"); + Node = class _Node { + #index; + #varIndex; + #children = /* @__PURE__ */ Object.create(null); + insert(tokens, index, paramMap, context, pathErrorCheckOnly) { + if (tokens.length === 0) { + if (this.#index !== void 0) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; } + this.#index = index; return; } - if (!this.has(value, null, null, false)) { - this._values.add(value); - if (typeof value === "string") { - this._lowercase.set(value.toLowerCase(), value); + const [token, ...restTokens] = tokens; + const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); + let node; + if (pattern) { + const name = pattern[1]; + let regexpStr = pattern[2] || LABEL_REG_EXP_STR; + if (name && pattern[2]) { + if (regexpStr === ".*") { + throw PATH_ERROR; + } + regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:"); + if (/\((?!\?:)/.test(regexpStr)) { + throw PATH_ERROR; + } } - } - } - static merge(target, source, remove) { - target = target || new internals.Values(); - if (source) { - if (source._override) { - return source.clone(); + node = this.#children[regexpStr]; + if (!node) { + if (Object.keys(this.#children).some( + (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR + )) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; + } + node = this.#children[regexpStr] = new _Node(); + if (name !== "") { + node.#varIndex = context.varIndex++; + } } - for (const item of [...source._values, ...source._refs]) { - target.add(item); + if (!pathErrorCheckOnly && name !== "") { + paramMap.push([name, node.#varIndex]); } - } - if (remove) { - for (const item of [...remove._values, ...remove._refs]) { - target.remove(item); + } else { + node = this.#children[token]; + if (!node) { + if (Object.keys(this.#children).some( + (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR + )) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; + } + node = this.#children[token] = new _Node(); } } - return target.length ? target : null; + node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly); } - remove(value) { - if (Common.isResolvable(value)) { - this._refs.delete(value); - return; - } - this._values.delete(value); - if (typeof value === "string") { - this._lowercase.delete(value.toLowerCase()); - } - } - has(value, state, prefs, insensitive) { - return !!this.get(value, state, prefs, insensitive); - } - get(value, state, prefs, insensitive) { - if (!this.length) { - return false; - } - if (this._values.has(value)) { - return { value }; + buildRegExpStr() { + const childKeys = Object.keys(this.#children).sort(compareKey); + const strList = childKeys.map((k) => { + const c = this.#children[k]; + return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr(); + }); + if (typeof this.#index === "number") { + strList.unshift(`#${this.#index}`); } - if (typeof value === "string" && value && insensitive) { - const found = this._lowercase.get(value.toLowerCase()); - if (found) { - return { value: found }; - } + if (strList.length === 0) { + return ""; } - if (!this._refs.size && typeof value !== "object") { - return false; + if (strList.length === 1) { + return strList[0]; } - if (typeof value === "object") { - for (const item of this._values) { - if (DeepEqual(item, value)) { - return { value: item }; - } + return "(?:" + strList.join("|") + ")"; + } + }; + } +}); +var Trie; +var init_trie = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/trie.js"() { + init_node(); + Trie = class { + #context = { varIndex: 0 }; + #root = new Node(); + insert(path8, index, pathErrorCheckOnly) { + const paramAssoc = []; + const groups = []; + for (let i2 = 0; ; ) { + let replaced = false; + path8 = path8.replace(/\{[^}]+\}/g, (m3) => { + const mark = `@\\${i2}`; + groups[i2] = [mark, m3]; + i2++; + replaced = true; + return mark; + }); + if (!replaced) { + break; } } - if (state) { - for (const ref of this._refs) { - const resolved = ref.resolve(value, state, prefs, null, { in: true }); - if (resolved === void 0) { - continue; - } - const items = !ref.in || typeof resolved !== "object" ? [resolved] : Array.isArray(resolved) ? resolved : Object.keys(resolved); - for (const item of items) { - if (typeof item !== typeof value) { - continue; - } - if (insensitive && value && typeof value === "string") { - if (item.toLowerCase() === value.toLowerCase()) { - return { value: item, ref }; - } - } else { - if (DeepEqual(item, value)) { - return { value: item, ref }; - } - } + const tokens = path8.match(/(?::[^\/]+)|(?:\/\*$)|./g) || []; + for (let i2 = groups.length - 1; i2 >= 0; i2--) { + const [mark] = groups[i2]; + for (let j = tokens.length - 1; j >= 0; j--) { + if (tokens[j].indexOf(mark) !== -1) { + tokens[j] = tokens[j].replace(mark, groups[i2][1]); + break; } } } - return false; - } - override() { - this._override = true; + this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly); + return paramAssoc; } - values(options2) { - if (options2 && options2.display) { - const values = []; - for (const item of [...this._values, ...this._refs]) { - if (item !== void 0) { - values.push(item); - } - } - return values; + buildRegExp() { + let regexp = this.#root.buildRegExpStr(); + if (regexp === "") { + return [/^$/, [], []]; } - return Array.from([...this._values, ...this._refs]); - } - clone() { - const set = new internals.Values(this._values, this._refs); - set._override = this._override; - return set; - } - concat(source) { - Assert(!source._override, "Cannot concat override set of values"); - const set = new internals.Values([...this._values, ...source._values], [...this._refs, ...source._refs]); - set._override = this._override; - return set; - } - }; - internals.Values.prototype[Common.symbols.values] = true; - internals.Values.prototype.slice = internals.Values.prototype.clone; - internals.lowercases = function(from3) { - const map = /* @__PURE__ */ new Map(); - if (from3) { - for (const value of from3) { - if (typeof value === "string") { - map.set(value.toLowerCase(), value); + let captureIndex = 0; + const indexReplacementMap = []; + const paramReplacementMap = []; + regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => { + if (handlerIndex !== void 0) { + indexReplacementMap[++captureIndex] = Number(handlerIndex); + return "$()"; } - } + if (paramIndex !== void 0) { + paramReplacementMap[Number(paramIndex)] = ++captureIndex; + return ""; + } + return ""; + }); + return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap]; } - return map; }; } }); -var require_base = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/base.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var DeepEqual = require_deepEqual(); - var Merge = require_merge(); - var Common = require_common2(); - var Compile = require_compile(); - var Errors = require_errors2(); - var Extend = require_extend(); - var Messages = require_messages(); - var Modify = require_modify(); - var Ref = require_ref(); - var Validator = require_validator(); - var Values = require_values(); - var internals = {}; - internals.Base = class { - constructor(type) { - this.type = type; - this.$_root = null; - this._definition = {}; - this._ids = new Modify.Ids(); - this._preferences = null; - this._refs = new Ref.Manager(); - this._cache = null; - this._valids = null; - this._invalids = null; - this._flags = {}; - this._rules = []; - this._singleRules = /* @__PURE__ */ new Map(); - this.$_terms = {}; - this.$_temp = { - // Runtime state (not cloned) - whens: {} - // Runtime cache of generated whens - }; +function buildWildcardRegExp(path8) { + return wildcardRegExpCache[path8] ??= new RegExp( + path8 === "*" ? "" : `^${path8.replace( + /\/\*$|([.\\+*[^\]$()])/g, + (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)" + )}$` + ); +} +function clearWildcardRegExpCache() { + wildcardRegExpCache = /* @__PURE__ */ Object.create(null); +} +function buildMatcherFromPreprocessedRoutes(routes) { + const trie = new Trie(); + const handlerData = []; + if (routes.length === 0) { + return nullMatcher; + } + const routesWithStaticPathFlag = routes.map( + (route) => [!/\*|\/:/.test(route[0]), ...route] + ).sort( + ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length + ); + const staticMap = /* @__PURE__ */ Object.create(null); + for (let i2 = 0, j = -1, len = routesWithStaticPathFlag.length; i2 < len; i2++) { + const [pathErrorCheckOnly, path8, handlers] = routesWithStaticPathFlag[i2]; + if (pathErrorCheckOnly) { + staticMap[path8] = [handlers.map(([h2]) => [h2, /* @__PURE__ */ Object.create(null)]), emptyParam]; + } else { + j++; + } + let paramAssoc; + try { + paramAssoc = trie.insert(path8, j, pathErrorCheckOnly); + } catch (e2) { + throw e2 === PATH_ERROR ? new UnsupportedPathError(path8) : e2; + } + if (pathErrorCheckOnly) { + continue; + } + handlerData[j] = handlers.map(([h2, paramCount]) => { + const paramIndexMap = /* @__PURE__ */ Object.create(null); + paramCount -= 1; + for (; paramCount >= 0; paramCount--) { + const [key, value] = paramAssoc[paramCount]; + paramIndexMap[key] = value; } - // Rules - allow(...values) { - Common.verifyFlat(values, "allow"); - return this._values(values, "_valids"); + return [h2, paramIndexMap]; + }); + } + const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp(); + for (let i2 = 0, len = handlerData.length; i2 < len; i2++) { + for (let j = 0, len2 = handlerData[i2].length; j < len2; j++) { + const map = handlerData[i2][j]?.[1]; + if (!map) { + continue; } - cast(to) { - Assert(to === false || typeof to === "string", "Invalid to value"); - Assert(to === false || this._definition.cast[to], "Type", this.type, "does not support casting to", to); - return this.$_setFlag("cast", to === false ? void 0 : to); + const keys = Object.keys(map); + for (let k = 0, len3 = keys.length; k < len3; k++) { + map[keys[k]] = paramReplacementMap[map[keys[k]]]; } - default(value, options2) { - return this._default("default", value, options2); + } + } + const handlerMap = []; + for (const i2 in indexReplacementMap) { + handlerMap[i2] = handlerData[indexReplacementMap[i2]]; + } + return [regexp, handlerMap, staticMap]; +} +function findMiddleware(middleware, path8) { + if (!middleware) { + return void 0; + } + for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) { + if (buildWildcardRegExp(k).test(path8)) { + return [...middleware[k]]; + } + } + return void 0; +} +var nullMatcher; +var wildcardRegExpCache; +var RegExpRouter; +var init_router2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/router.js"() { + init_router(); + init_url(); + init_matcher(); + init_node(); + init_trie(); + nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)]; + wildcardRegExpCache = /* @__PURE__ */ Object.create(null); + RegExpRouter = class { + name = "RegExpRouter"; + #middleware; + #routes; + constructor() { + this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; + this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; } - empty(schema) { - const obj = this.clone(); - if (schema !== void 0) { - schema = obj.$_compile(schema, { override: false }); + add(method, path8, handler) { + const middleware = this.#middleware; + const routes = this.#routes; + if (!middleware || !routes) { + throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); } - return obj.$_setFlag("empty", schema, { clone: false }); - } - error(err) { - Assert(err, "Missing error"); - Assert(err instanceof Error || typeof err === "function", "Must provide a valid Error object or a function"); - return this.$_setFlag("error", err); - } - failover(value, options2) { - return this._default("failover", value, options2); - } - forbidden() { - return this.presence("forbidden"); - } - id(id) { - if (!id) { - return this.$_setFlag("id", void 0); + if (!middleware[method]) { + ; + [middleware, routes].forEach((handlerMap) => { + handlerMap[method] = /* @__PURE__ */ Object.create(null); + Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => { + handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]]; + }); + }); } - Assert(typeof id === "string", "id must be a non-empty string"); - Assert(/^[^\.]+$/.test(id), "id cannot contain period character"); - return this.$_setFlag("id", id); - } - invalid(...values) { - return this._values(values, "_invalids"); - } - only(mode = true) { - Assert(typeof mode === "boolean", "Invalid mode:", mode); - return this.$_setFlag("only", mode); - } - optional() { - return this.presence("optional"); - } - prefs(prefs) { - Assert(prefs, "Missing preferences"); - Assert(prefs.context === void 0, "Cannot override context"); - Common.checkPreferences(prefs); - const obj = this.clone(); - obj._preferences = Common.preferences(obj._preferences, prefs); - return obj; - } - presence(mode) { - Assert(["optional", "required", "forbidden"].includes(mode), "Unknown presence mode", mode); - return this.$_setFlag("presence", mode); - } - raw(enabled2 = true) { - return this.$_setFlag("result", enabled2 ? "raw" : void 0); - } - required() { - return this.presence("required"); - } - strict(enabled2) { - const obj = this.clone(); - const convert = enabled2 === void 0 ? false : !enabled2; - obj._preferences = Common.preferences(obj._preferences, { convert }); - return obj; - } - strip(enabled2 = true) { - return this.$_setFlag("result", enabled2 ? "strip" : void 0); - } - valid(...values) { - Common.verifyFlat(values, "valid"); - const obj = this.allow(...values); - obj.$_setFlag("only", !!obj._valids, { clone: false }); - return obj; - } - when(condition, options2) { - const obj = this.clone(); - if (!obj.$_terms.whens) { - obj.$_terms.whens = []; - } - const when = Compile.when(obj, condition, options2); - if (!["any", "link"].includes(obj.type)) { - const conditions = when.is ? [when] : when.switch; - for (const item of conditions) { - Assert(!item.then || item.then.type === "any" || item.then.type === obj.type, "Cannot combine", obj.type, "with", item.then?.type); - Assert(!item.otherwise || item.otherwise.type === "any" || item.otherwise.type === obj.type, "Cannot combine", obj.type, "with", item.otherwise?.type); - } - } - obj.$_terms.whens.push(when); - return obj.$_mutateRebuild(); - } - // Helpers - clone() { - const obj = Object.create(Object.getPrototypeOf(this)); - return this._assign(obj); - } - concat(source) { - Assert(Common.isSchema(source), "Invalid schema object"); - Assert(this.type === "any" || source.type === "any" || source.type === this.type, "Cannot merge type", this.type, "with another type:", source.type); - let obj = this.clone(); - if (this.type === "any" && source.type !== "any") { - const tmpObj = source.clone(); - for (const key of Object.keys(obj)) { - if (key !== "type") { - tmpObj[key] = obj[key]; - } - } - obj = tmpObj; - } - obj._ids.concat(source._ids); - obj._refs.register(source, Ref.toSibling); - obj._preferences = obj._preferences ? Common.preferences(obj._preferences, source._preferences) : source._preferences; - obj._valids = Values.merge(obj._valids, source._valids, source._invalids); - obj._invalids = Values.merge(obj._invalids, source._invalids, source._valids); - for (const name of source._singleRules.keys()) { - if (obj._singleRules.has(name)) { - obj._rules = obj._rules.filter((target) => target.name !== name); - obj._singleRules.delete(name); - } - } - for (const test of source._rules) { - if (!source._definition.rules[test.method].multi) { - obj._singleRules.set(test.name, test); - } - obj._rules.push(test); - } - if (obj._flags.empty && source._flags.empty) { - obj._flags.empty = obj._flags.empty.concat(source._flags.empty); - const flags = Object.assign({}, source._flags); - delete flags.empty; - Merge(obj._flags, flags); - } else if (source._flags.empty) { - obj._flags.empty = source._flags.empty; - const flags = Object.assign({}, source._flags); - delete flags.empty; - Merge(obj._flags, flags); - } else { - Merge(obj._flags, source._flags); + if (path8 === "/*") { + path8 = "*"; } - for (const key in source.$_terms) { - const terms = source.$_terms[key]; - if (!terms) { - if (!obj.$_terms[key]) { - obj.$_terms[key] = terms; - } - continue; - } - if (!obj.$_terms[key]) { - obj.$_terms[key] = terms.slice(); - continue; + const paramCount = (path8.match(/\/:/g) || []).length; + if (/\*$/.test(path8)) { + const re = buildWildcardRegExp(path8); + if (method === METHOD_NAME_ALL) { + Object.keys(middleware).forEach((m3) => { + middleware[m3][path8] ||= findMiddleware(middleware[m3], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; + }); + } else { + middleware[method][path8] ||= findMiddleware(middleware[method], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; } - obj.$_terms[key] = obj.$_terms[key].concat(terms); - } - return obj.$_mutateRebuild(); - } - validate(value, options2) { - return Validator.entry(value, this, options2); - } - validateAsync(value, options2) { - const result = this.validate(value, options2); - if (result.error) { - throw result.error; - } - return result.value; - } - // Extensions - $_addRule(options2) { - if (typeof options2 === "string") { - options2 = { name: options2 }; - } - Assert(options2 && typeof options2 === "object", "Invalid options"); - Assert(options2.name && typeof options2.name === "string", "Invalid rule name"); - for (const key in options2) { - Assert(key[0] !== "_", "Cannot set private rule properties"); - } - const rule = Object.assign({}, options2); - rule._resolve = []; - rule.method = rule.method || rule.name; - const definition = this._definition.rules[rule.method]; - const args = rule.args; - Assert(definition, "Unknown rule", rule.method); - const obj = this.clone(); - if (args) { - Assert(Object.keys(args).length === 1 || Object.keys(args).length === this._definition.rules[rule.name].args.length, "Invalid rule definition for", this.type, rule.name); - for (const key in args) { - let arg = args[key]; - if (arg === void 0) { - delete args[key]; - continue; + Object.keys(middleware).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + Object.keys(middleware[m3]).forEach((p) => { + re.test(p) && middleware[m3][p].push([handler, paramCount]); + }); } - if (definition.argsByName) { - const resolver = definition.argsByName.get(key); - if (resolver.ref && Common.isResolvable(arg)) { - rule._resolve.push(key); - obj.$_mutateRegister(arg); - } else { - if (resolver.normalize) { - arg = resolver.normalize(arg); - args[key] = arg; - } - if (resolver.assert) { - const error2 = Common.validateArg(arg, key, resolver); - Assert(!error2, error2, "or reference"); - } - } + }); + Object.keys(routes).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + Object.keys(routes[m3]).forEach( + (p) => re.test(p) && routes[m3][p].push([handler, paramCount]) + ); } - args[key] = arg; - } - } - if (!definition.multi) { - obj._ruleRemove(rule.name); - obj._singleRules.set(rule.name, rule); + }); + return; } - if (definition.priority) { - obj._rules.unshift(rule); - } else { - obj._rules.push(rule); + const paths = checkOptionalParameter(path8) || [path8]; + for (let i2 = 0, len = paths.length; i2 < len; i2++) { + const path22 = paths[i2]; + Object.keys(routes).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + routes[m3][path22] ||= [ + ...findMiddleware(middleware[m3], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || [] + ]; + routes[m3][path22].push([handler, paramCount - len + i2 + 1]); + } + }); } - return obj; - } - $_compile(schema, options2) { - return Compile.schema(this.$_root, schema, options2); } - $_createError(code2, value, local, state, prefs, options2 = {}) { - const flags = options2.flags !== false ? this._flags : {}; - const messages = options2.messages ? Messages.merge(this._definition.messages, options2.messages) : this._definition.messages; - return new Errors.Report(code2, value, local, flags, messages, state, prefs); - } - $_getRule(name) { - return this._singleRules.get(name); - } - $_match(value, state, prefs, overrides) { - prefs = Object.assign({}, prefs); - prefs.abortEarly = true; - prefs._externals = false; - state.snapshot(); - const result = !Validator.validate(value, this, state, prefs, overrides).errors; - state.restore(); - return result; - } - $_modify(options2) { - Common.assertOptions(options2, ["each", "once", "ref", "schema"]); - return Modify.schema(this, options2) || this; - } - $_mutateRebuild() { - this._refs.reset(); - this._ids.reset(); - const each = (item, { source, name, path: path8, key }) => { - const family = this._definition[source][name]?.register; - if (family !== false) { - this.$_mutateRegister(item, { family, key }); + match = match; + buildAllMatchers() { + const matchers = /* @__PURE__ */ Object.create(null); + Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => { + matchers[method] ||= this.#buildMatcher(method); + }); + this.#middleware = this.#routes = void 0; + clearWildcardRegExpCache(); + return matchers; + } + #buildMatcher(method) { + const routes = []; + let hasOwnRoute = method === METHOD_NAME_ALL; + [this.#middleware, this.#routes].forEach((r) => { + const ownRoute = r[method] ? Object.keys(r[method]).map((path8) => [path8, r[method][path8]]) : []; + if (ownRoute.length !== 0) { + hasOwnRoute ||= true; + routes.push(...ownRoute); + } else if (method !== METHOD_NAME_ALL) { + routes.push( + ...Object.keys(r[METHOD_NAME_ALL]).map((path8) => [path8, r[METHOD_NAME_ALL][path8]]) + ); } - }; - this.$_modify({ each }); - if (this._definition.rebuild) { - this._definition.rebuild(this); - } - return this; - } - $_mutateRegister(schema, { family, key } = {}) { - this._refs.register(schema, family); - this._ids.register(schema, { key }); - } - $_property(name) { - return this._definition.properties[name]; - } - $_reach(path8) { - return this._ids.reach(path8); - } - $_rootReferences() { - return this._refs.roots(); - } - $_setFlag(name, value, options2 = {}) { - const flag = this._definition.flags[name] || {}; - if (DeepEqual(value, flag.default)) { - value = void 0; - } - if (DeepEqual(value, this._flags[name])) { - return this; - } - const obj = options2.clone !== false ? this.clone() : this; - if (value !== void 0) { - obj._flags[name] = value; - obj.$_mutateRegister(value); + }); + if (!hasOwnRoute) { + return null; } else { - delete obj._flags[name]; + return buildMatcherFromPreprocessedRoutes(routes); } - return obj; } - $_parent(method, ...args) { - return this[method][Common.symbols.parent].call(this, ...args); - } - $_validate(value, state, prefs) { - return Validator.validate(value, this, state, prefs); - } - // Internals - _assign(target) { - target.type = this.type; - target.$_root = this.$_root; - target.$_temp = Object.assign({}, this.$_temp); - target.$_temp.whens = {}; - target._ids = this._ids.clone(); - target._preferences = this._preferences; - target._valids = this._valids?.clone(); - target._invalids = this._invalids?.clone(); - target._rules = this._rules.slice(); - target._singleRules = Clone(this._singleRules, { shallow: true }); - target._refs = this._refs.clone(); - target._flags = Object.assign({}, this._flags); - target._cache = null; - target.$_terms = {}; - for (const key in this.$_terms) { - target.$_terms[key] = this.$_terms[key] ? this.$_terms[key].slice() : null; - } - target.$_super = {}; - for (const override in this.$_super) { - target.$_super[override] = this._super[override].bind(target); - } - return target; - } - _default(flag, value, options2 = {}) { - Common.assertOptions(options2, "literal"); - Assert(value !== void 0, "Missing", flag, "value"); - Assert(typeof value === "function" || !options2.literal, "Only function value supports literal option"); - if (typeof value === "function" && options2.literal) { - value = { - [Common.symbols.literal]: true, - literal: value - }; - } - const obj = this.$_setFlag(flag, value); - return obj; + }; + } +}); +var init_prepared_router = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/prepared-router.js"() { + init_router(); + init_matcher(); + init_router2(); + } +}); +var init_reg_exp_router = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/index.js"() { + init_router2(); + init_prepared_router(); + } +}); +var SmartRouter; +var init_router3 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/smart-router/router.js"() { + init_router(); + SmartRouter = class { + name = "SmartRouter"; + #routers = []; + #routes = []; + constructor(init2) { + this.#routers = init2.routers; } - _extend(options2) { - Assert(!options2.base, "Cannot extend type with another base"); - return Extend.type(this, options2); + add(method, path8, handler) { + if (!this.#routes) { + throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); + } + this.#routes.push([method, path8, handler]); } - _generate(value, state, prefs) { - if (!this.$_terms.whens) { - return { schema: this }; + match(method, path8) { + if (!this.#routes) { + throw new Error("Fatal error"); } - const whens = []; - const ids = []; - for (let i2 = 0; i2 < this.$_terms.whens.length; ++i2) { - const when = this.$_terms.whens[i2]; - if (when.concat) { - whens.push(when.concat); - ids.push(`${i2}.concat`); - continue; - } - const input = when.ref ? when.ref.resolve(value, state, prefs) : value; - const tests = when.is ? [when] : when.switch; - const before = ids.length; - for (let j = 0; j < tests.length; ++j) { - const { is, then, otherwise } = tests[j]; - const baseId = `${i2}${when.switch ? "." + j : ""}`; - if (is.$_match(input, state.nest(is, `${baseId}.is`), prefs)) { - if (then) { - const localState = state.localize([...state.path, `${baseId}.then`], state.ancestors, state.schemas); - const { schema: generated, id: id2 } = then._generate(value, localState, prefs); - whens.push(generated); - ids.push(`${baseId}.then${id2 ? `(${id2})` : ""}`); - break; - } - } else if (otherwise) { - const localState = state.localize([...state.path, `${baseId}.otherwise`], state.ancestors, state.schemas); - const { schema: generated, id: id2 } = otherwise._generate(value, localState, prefs); - whens.push(generated); - ids.push(`${baseId}.otherwise${id2 ? `(${id2})` : ""}`); - break; + const routers = this.#routers; + const routes = this.#routes; + const len = routers.length; + let i2 = 0; + let res; + for (; i2 < len; i2++) { + const router = routers[i2]; + try { + for (let i22 = 0, len2 = routes.length; i22 < len2; i22++) { + router.add(...routes[i22]); } + res = router.match(method, path8); + } catch (e2) { + if (e2 instanceof UnsupportedPathError) { + continue; + } + throw e2; } - if (when.break && ids.length > before) { - break; - } - } - const id = ids.join(", "); - if (!id) { - return { schema: this }; - } - if (this.$_temp.whens[id]) { - return { schema: this.$_temp.whens[id], id }; - } - let obj = this; - if (this._definition.generate) { - obj = this._definition.generate(this, value, state, prefs); - } - for (const when of whens) { - obj = obj.concat(when); - } - this.$_temp.whens[id] = obj; - return { schema: obj, id }; - } - _ruleRemove(name) { - if (!this._singleRules.has(name)) { - return this; + this.match = router.match.bind(router); + this.#routers = [router]; + this.#routes = void 0; + break; } - this._singleRules.delete(name); - const filtered = []; - for (let i2 = 0; i2 < this._rules.length; ++i2) { - const test = this._rules[i2]; - if (test.name === name) { - continue; - } - filtered.push(test); + if (i2 === len) { + throw new Error("Fatal error"); } - this._rules = filtered; + this.name = `SmartRouter + ${this.activeRouter.name}`; + return res; } - _values(values, key) { - Common.verifyFlat(values, key.slice(1, -1)); - const obj = this.clone(); - const override = values[0] === Common.symbols.override; - if (override) { - values = values.slice(1); - } - if (!obj[key] && values.length) { - obj[key] = new Values(); - } else if (override) { - obj[key] = values.length ? new Values() : null; - obj.$_mutateRebuild(); - } - if (!obj[key]) { - return obj; - } - if (override) { - obj[key].override(); - } - for (const value of values) { - Assert(value !== void 0, "Cannot call allow/valid/invalid with undefined"); - Assert(value !== Common.symbols.override, "Override must be the first value"); - const other = key === "_invalids" ? "_valids" : "_invalids"; - if (obj[other]) { - obj[other].remove(value); - if (!obj[other].length) { - Assert(key === "_valids" || !obj._flags.only, "Setting invalid value", value, "leaves schema rejecting all values due to previous valid rule"); - obj[other] = null; - } - } - obj[key].add(value, obj._refs); + get activeRouter() { + if (this.#routes || this.#routers.length !== 1) { + throw new Error("No active router has been determined yet."); } - return obj; + return this.#routers[0]; } }; - internals.Base.prototype[Common.symbols.any] = { - version: Common.version, - compile: Compile.compile, - root: "$_root" - }; - internals.Base.prototype.isImmutable = true; - internals.Base.prototype.deny = internals.Base.prototype.invalid; - internals.Base.prototype.disallow = internals.Base.prototype.invalid; - internals.Base.prototype.equal = internals.Base.prototype.valid; - internals.Base.prototype.exist = internals.Base.prototype.required; - internals.Base.prototype.not = internals.Base.prototype.invalid; - internals.Base.prototype.options = internals.Base.prototype.prefs; - internals.Base.prototype.preferences = internals.Base.prototype.prefs; - module14.exports = new internals.Base(); - } -}); -var require_any = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/any.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Base = require_base(); - var Common = require_common2(); - module14.exports = Base._extend({ - type: "any", - flags: { - only: { default: false } - }, - terms: { - alterations: { init: null }, - examples: { init: null }, - metas: { init: [] }, - notes: { init: [] }, - shared: { init: null }, - tags: { init: [] }, - whens: { init: null } - }, - rules: { - custom: { - method(method, description) { - Assert(typeof method === "function", "Method must be a function"); - Assert(description === void 0 || description && typeof description === "string", "Description must be a non-empty string"); - return this.$_addRule({ name: "custom", args: { method, description } }); - }, - validate(value, helpers, { method }) { - try { - return method(value, helpers); - } catch (err) { - return helpers.error("any.custom", { error: err }); - } - }, - args: ["method", "description"], - multi: true - }, - messages: { - method(messages) { - return this.prefs({ messages }); - } - }, - shared: { - method(schema) { - Assert(Common.isSchema(schema) && schema._flags.id, "Schema must be a schema with an id"); - const obj = this.clone(); - obj.$_terms.shared = obj.$_terms.shared || []; - obj.$_terms.shared.push(schema); - obj.$_mutateRegister(schema); - return obj; - } - } - }, - messages: { - "any.custom": "{{#label}} failed custom validation because {{#error.message}}", - "any.default": "{{#label}} threw an error when running default method", - "any.failover": "{{#label}} threw an error when running failover method", - "any.invalid": "{{#label}} contains an invalid value", - "any.only": "{{#label}} must be one of {{#valids}}", - "any.ref": "{{#label}} {{#arg}} references {{:#ref}} which {{#reason}}", - "any.required": "{{#label}} is required", - "any.unknown": "{{#label}} is not allowed" - } - }); } }); -var require_alternatives = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/alternatives.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - var Compile = require_compile(); - var Errors = require_errors2(); - var Ref = require_ref(); - var internals = {}; - module14.exports = Any._extend({ - type: "alternatives", - flags: { - match: { default: "any" } - // 'any', 'one', 'all' - }, - terms: { - matches: { init: [], register: Ref.toSibling } - }, - args(schema, ...schemas) { - if (schemas.length === 1) { - if (Array.isArray(schemas[0])) { - return schema.try(...schemas[0]); - } - } - return schema.try(...schemas); - }, - validate(value, helpers) { - const { schema, error: error2, state, prefs } = helpers; - if (schema._flags.match) { - let hits = 0; - let matched; - for (let i2 = 0; i2 < schema.$_terms.matches.length; ++i2) { - const item = schema.$_terms.matches[i2]; - const localState = state.nest(item.schema, `match.${i2}`); - localState.snapshot(); - const result = item.schema.$_validate(value, localState, prefs); - if (!result.errors) { - ++hits; - matched = result.value; - } else { - localState.restore(); +var init_smart_router = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/smart-router/index.js"() { + init_router3(); + } +}); +var emptyParams; +var hasChildren; +var Node2; +var init_node2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/node.js"() { + init_router(); + init_url(); + emptyParams = /* @__PURE__ */ Object.create(null); + hasChildren = (children) => { + for (const _ in children) { + return true; + } + return false; + }; + Node2 = class _Node2 { + #methods; + #children; + #patterns; + #order = 0; + #params = emptyParams; + constructor(method, handler, children) { + this.#children = children || /* @__PURE__ */ Object.create(null); + this.#methods = []; + if (method && handler) { + const m3 = /* @__PURE__ */ Object.create(null); + m3[method] = { handler, possibleKeys: [], score: 0 }; + this.#methods = [m3]; + } + this.#patterns = []; + } + insert(method, path8, handler) { + this.#order = ++this.#order; + let curNode = this; + const parts = splitRoutingPath(path8); + const possibleKeys = []; + for (let i2 = 0, len = parts.length; i2 < len; i2++) { + const p = parts[i2]; + const nextP = parts[i2 + 1]; + const pattern = getPattern(p, nextP); + const key = Array.isArray(pattern) ? pattern[0] : p; + if (key in curNode.#children) { + curNode = curNode.#children[key]; + if (pattern) { + possibleKeys.push(pattern[1]); } + continue; } - if (!hits) { - return { errors: error2("alternatives.any") }; - } - if (schema._flags.match === "one") { - return hits === 1 ? { value: matched } : { errors: error2("alternatives.one") }; + curNode.#children[key] = new _Node2(); + if (pattern) { + curNode.#patterns.push(pattern); + possibleKeys.push(pattern[1]); } - return hits === schema.$_terms.matches.length ? { value } : { errors: error2("alternatives.all") }; + curNode = curNode.#children[key]; } - const errors = []; - for (let i2 = 0; i2 < schema.$_terms.matches.length; ++i2) { - const item = schema.$_terms.matches[i2]; - if (item.schema) { - const localState = state.nest(item.schema, `match.${i2}`); - localState.snapshot(); - const result = item.schema.$_validate(value, localState, prefs); - if (!result.errors) { - return result; - } - localState.restore(); - errors.push({ schema: item.schema, reports: result.errors }); - continue; + curNode.#methods.push({ + [method]: { + handler, + possibleKeys: possibleKeys.filter((v2, i2, a) => a.indexOf(v2) === i2), + score: this.#order } - const input = item.ref ? item.ref.resolve(value, state, prefs) : value; - const tests = item.is ? [item] : item.switch; - for (let j = 0; j < tests.length; ++j) { - const test = tests[j]; - const { is, then, otherwise } = test; - const id = `match.${i2}${item.switch ? "." + j : ""}`; - if (!is.$_match(input, state.nest(is, `${id}.is`), prefs)) { - if (otherwise) { - return otherwise.$_validate(value, state.nest(otherwise, `${id}.otherwise`), prefs); + }); + return curNode; + } + #pushHandlerSets(handlerSets, node, method, nodeParams, params) { + for (let i2 = 0, len = node.#methods.length; i2 < len; i2++) { + const m3 = node.#methods[i2]; + const handlerSet = m3[method] || m3[METHOD_NAME_ALL]; + const processedSet = {}; + if (handlerSet !== void 0) { + handlerSet.params = /* @__PURE__ */ Object.create(null); + handlerSets.push(handlerSet); + if (nodeParams !== emptyParams || params && params !== emptyParams) { + for (let i22 = 0, len2 = handlerSet.possibleKeys.length; i22 < len2; i22++) { + const key = handlerSet.possibleKeys[i22]; + const processed = processedSet[handlerSet.score]; + handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]; + processedSet[handlerSet.score] = true; } - } else if (then) { - return then.$_validate(value, state.nest(then, `${id}.then`), prefs); } } } - return internals.errors(errors, helpers); - }, - rules: { - conditional: { - method(condition, options2) { - Assert(!this._flags._endedSwitch, "Unreachable condition"); - Assert(!this._flags.match, "Cannot combine match mode", this._flags.match, "with conditional rule"); - Assert(options2.break === void 0, "Cannot use break option with alternatives conditional"); - const obj = this.clone(); - const match = Compile.when(obj, condition, options2); - const conditions = match.is ? [match] : match.switch; - for (const item of conditions) { - if (item.then && item.otherwise) { - obj.$_setFlag("_endedSwitch", true, { clone: false }); - break; + } + search(method, path8) { + const handlerSets = []; + this.#params = emptyParams; + const curNode = this; + let curNodes = [curNode]; + const parts = splitPath(path8); + const curNodesQueue = []; + const len = parts.length; + let partOffsets = null; + for (let i2 = 0; i2 < len; i2++) { + const part = parts[i2]; + const isLast = i2 === len - 1; + const tempNodes = []; + for (let j = 0, len2 = curNodes.length; j < len2; j++) { + const node = curNodes[j]; + const nextNode = node.#children[part]; + if (nextNode) { + nextNode.#params = node.#params; + if (isLast) { + if (nextNode.#children["*"]) { + this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params); + } + this.#pushHandlerSets(handlerSets, nextNode, method, node.#params); + } else { + tempNodes.push(nextNode); } } - obj.$_terms.matches.push(match); - return obj.$_mutateRebuild(); - } - }, - match: { - method(mode) { - Assert(["any", "one", "all"].includes(mode), "Invalid alternatives match mode", mode); - if (mode !== "any") { - for (const match of this.$_terms.matches) { - Assert(match.schema, "Cannot combine match mode", mode, "with conditional rules"); + for (let k = 0, len3 = node.#patterns.length; k < len3; k++) { + const pattern = node.#patterns[k]; + const params = node.#params === emptyParams ? {} : { ...node.#params }; + if (pattern === "*") { + const astNode = node.#children["*"]; + if (astNode) { + this.#pushHandlerSets(handlerSets, astNode, method, node.#params); + astNode.#params = params; + tempNodes.push(astNode); + } + continue; + } + const [key, name, matcher] = pattern; + if (!part && !(matcher instanceof RegExp)) { + continue; + } + const child = node.#children[key]; + if (matcher instanceof RegExp) { + if (partOffsets === null) { + partOffsets = new Array(len); + let offset = path8[0] === "/" ? 1 : 0; + for (let p = 0; p < len; p++) { + partOffsets[p] = offset; + offset += parts[p].length + 1; + } + } + const restPathString = path8.substring(partOffsets[i2]); + const m3 = matcher.exec(restPathString); + if (m3) { + params[name] = m3[0]; + this.#pushHandlerSets(handlerSets, child, method, node.#params, params); + if (hasChildren(child.#children)) { + child.#params = params; + const componentCount = m3[0].match(/\//)?.length ?? 0; + const targetCurNodes = curNodesQueue[componentCount] ||= []; + targetCurNodes.push(child); + } + continue; + } + } + if (matcher === true || matcher.test(part)) { + params[name] = part; + if (isLast) { + this.#pushHandlerSets(handlerSets, child, method, params, node.#params); + if (child.#children["*"]) { + this.#pushHandlerSets( + handlerSets, + child.#children["*"], + method, + params, + node.#params + ); + } + } else { + child.#params = params; + tempNodes.push(child); + } } } - return this.$_setFlag("match", mode); - } - }, - try: { - method(...schemas) { - Assert(schemas.length, "Missing alternative schemas"); - Common.verifyFlat(schemas, "try"); - Assert(!this._flags._endedSwitch, "Unreachable condition"); - const obj = this.clone(); - for (const schema of schemas) { - obj.$_terms.matches.push({ schema: obj.$_compile(schema) }); - } - return obj.$_mutateRebuild(); } + const shifted = curNodesQueue.shift(); + curNodes = shifted ? tempNodes.concat(shifted) : tempNodes; } - }, - rebuild(schema) { - const each = (item) => { - if (Common.isSchema(item) && item.type === "array") { - schema.$_setFlag("_arrayItems", true, { clone: false }); - } - }; - schema.$_modify({ each }); - }, - messages: { - "alternatives.all": "{{#label}} does not match all of the required types", - "alternatives.any": "{{#label}} does not match any of the allowed types", - "alternatives.match": "{{#label}} does not match any of the allowed types", - "alternatives.one": "{{#label}} matches more than one allowed type", - "alternatives.types": "{{#label}} must be one of {{#types}}" - } - }); - internals.errors = function(failures, { error: error2, state }) { - if (!failures.length) { - return { errors: error2("alternatives.any") }; + if (handlerSets.length > 1) { + handlerSets.sort((a, b) => { + return a.score - b.score; + }); + } + return [handlerSets.map(({ handler, params }) => [handler, params])]; } - if (failures.length === 1) { - return { errors: failures[0].reports }; + }; + } +}); +var TrieRouter; +var init_router4 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/router.js"() { + init_url(); + init_node2(); + TrieRouter = class { + name = "TrieRouter"; + #node; + constructor() { + this.#node = new Node2(); } - const valids = /* @__PURE__ */ new Set(); - const complex = []; - for (const { reports, schema } of failures) { - if (reports.length > 1) { - return internals.unmatched(failures, error2); - } - const report = reports[0]; - if (report instanceof Errors.Report === false) { - return internals.unmatched(failures, error2); - } - if (report.state.path.length !== state.path.length) { - complex.push({ type: schema.type, report }); - continue; - } - if (report.code === "any.only") { - for (const valid of report.local.valids) { - valids.add(valid); + add(method, path8, handler) { + const results = checkOptionalParameter(path8); + if (results) { + for (let i2 = 0, len = results.length; i2 < len; i2++) { + this.#node.insert(method, results[i2], handler); } - continue; - } - const [type, code2] = report.code.split("."); - if (code2 !== "base") { - complex.push({ type: schema.type, report }); - continue; + return; } - valids.add(type); + this.#node.insert(method, path8, handler); } - if (!complex.length) { - return { errors: error2("alternatives.types", { types: [...valids] }) }; + match(method, path8) { + return this.#node.search(method, path8); } - if (complex.length === 1) { - return { errors: complex[0].report }; + }; + } +}); +var init_trie_router = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/index.js"() { + init_router4(); + } +}); +var Hono2; +var init_hono = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/hono.js"() { + init_hono_base(); + init_reg_exp_router(); + init_smart_router(); + init_trie_router(); + Hono2 = class extends Hono { + /** + * Creates an instance of the Hono class. + * + * @param options - Optional configuration options for the Hono instance. + */ + constructor(options2 = {}) { + super(options2); + this.router = options2.router ?? new SmartRouter({ + routers: [new RegExpRouter(), new TrieRouter()] + }); } - return internals.unmatched(failures, error2); }; - internals.unmatched = function(failures, error2) { - const errors = []; - for (const failure of failures) { - errors.push(...failure.reports); + } +}); +var init_dist = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/index.js"() { + init_hono(); + } +}); +var COMPRESSIBLE_CONTENT_TYPE_REGEX; +var init_compress = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/compress.js"() { + COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; + } +}); +var getMimeType; +var _baseMimes; +var baseMimes; +var init_mime = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/mime.js"() { + getMimeType = (filename, mimes = baseMimes) => { + const regexp = /\.([a-zA-Z0-9]+?)$/; + const match2 = filename.match(regexp); + if (!match2) { + return; + } + let mimeType = mimes[match2[1].toLowerCase()]; + if (mimeType && mimeType.startsWith("text")) { + mimeType += "; charset=utf-8"; + } + return mimeType; + }; + _baseMimes = { + aac: "audio/aac", + avi: "video/x-msvideo", + avif: "image/avif", + av1: "video/av1", + bin: "application/octet-stream", + bmp: "image/bmp", + css: "text/css", + csv: "text/csv", + eot: "application/vnd.ms-fontobject", + epub: "application/epub+zip", + gif: "image/gif", + gz: "application/gzip", + htm: "text/html", + html: "text/html", + ico: "image/x-icon", + ics: "text/calendar", + jpeg: "image/jpeg", + jpg: "image/jpeg", + js: "text/javascript", + json: "application/json", + jsonld: "application/ld+json", + map: "application/json", + mid: "audio/x-midi", + midi: "audio/x-midi", + mjs: "text/javascript", + mp3: "audio/mpeg", + mp4: "video/mp4", + mpeg: "video/mpeg", + oga: "audio/ogg", + ogv: "video/ogg", + ogx: "application/ogg", + opus: "audio/opus", + otf: "font/otf", + pdf: "application/pdf", + png: "image/png", + rtf: "application/rtf", + svg: "image/svg+xml", + tif: "image/tiff", + tiff: "image/tiff", + ts: "video/mp2t", + ttf: "font/ttf", + txt: "text/plain", + wasm: "application/wasm", + webm: "video/webm", + weba: "audio/webm", + webmanifest: "application/manifest+json", + webp: "image/webp", + woff: "font/woff", + woff2: "font/woff2", + xhtml: "application/xhtml+xml", + xml: "application/xml", + zip: "application/zip", + "3gp": "video/3gpp", + "3g2": "video/3gpp2", + gltf: "model/gltf+json", + glb: "model/gltf-binary" + }; + baseMimes = _baseMimes; + } +}); +var defaultJoin; +var init_path = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/serve-static/path.js"() { + defaultJoin = (...paths) => { + let result = paths.filter((p) => p !== "").join("/"); + result = result.replace(/(?<=\/)\/+/g, ""); + const segments = result.split("/"); + const resolved = []; + for (const segment of segments) { + if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { + resolved.pop(); + } else if (segment !== ".") { + resolved.push(segment); + } } - return { errors: error2("alternatives.match", Errors.details(errors, { override: false })) }; + return resolved.join("/") || "."; }; } }); -var require_array = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/array.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var DeepEqual = require_deepEqual(); - var Reach = require_reach(); - var Any = require_any(); - var Common = require_common2(); - var Compile = require_compile(); - var internals = {}; - module14.exports = Any._extend({ - type: "array", - flags: { - single: { default: false }, - sparse: { default: false } - }, - terms: { - items: { init: [] }, - ordered: { init: [] }, - _exclusions: { init: [] }, - _inclusions: { init: [] }, - _requireds: { init: [] } - }, - coerce: { - from: "object", - method(value, { schema, state, prefs }) { - if (!Array.isArray(value)) { - return; - } - const sort = schema.$_getRule("sort"); - if (!sort) { - return; - } - return internals.sort(schema, value, sort.args.options, state, prefs); +var ENCODINGS; +var ENCODINGS_ORDERED_KEYS; +var DEFAULT_DOCUMENT; +var serveStatic; +var init_serve_static = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/serve-static/index.js"() { + init_compress(); + init_mime(); + init_url(); + init_path(); + ENCODINGS = { + br: ".br", + zstd: ".zst", + gzip: ".gz" + }; + ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); + DEFAULT_DOCUMENT = "index.html"; + serveStatic = (options2) => { + const root = options2.root ?? "./"; + const optionPath = options2.path; + const join10 = options2.join ?? defaultJoin; + return async (c, next) => { + if (c.finalized) { + return next(); } - }, - validate(value, { schema, error: error2 }) { - if (!Array.isArray(value)) { - if (schema._flags.single) { - const single = [value]; - single[Common.symbols.arraySingle] = true; - return { value: single }; + let filename; + if (options2.path) { + filename = options2.path; + } else { + try { + filename = tryDecodeURI(c.req.path); + if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { + throw new Error(); + } + } catch { + await options2.onNotFound?.(c.req.path, c); + return next(); } - return { errors: error2("array.base") }; - } - if (!schema.$_getRule("items")) { - return; } - return { value: value.slice() }; - }, - rules: { - has: { - method(schema) { - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.$_addRule({ name: "has", args: { schema } }); - obj.$_mutateRegister(schema); - return obj; - }, - validate(value, { state, prefs, error: error2 }, { schema: has2 }) { - const ancestors = [value, ...state.ancestors]; - for (let i2 = 0; i2 < value.length; ++i2) { - const localState = state.localize([...state.path, i2], ancestors, has2); - if (has2.$_match(value[i2], localState, prefs)) { - return value; - } - } - return error2("array.hasUnknown", null); - }, - multi: true - }, - items: { - method(...schemas) { - Common.verifyFlat(schemas, "items"); - const obj = this.$_addRule("items"); - for (let i2 = 0; i2 < schemas.length; ++i2) { - const type = Common.tryWithPath(() => this.$_compile(schemas[i2]), i2, { append: true }); - obj.$_terms.items.push(type); - } - return obj.$_mutateRebuild(); - }, - validate(value, { schema, error: error2, state, prefs, errorsArray }) { - const requireds = schema.$_terms._requireds.slice(); - const ordereds = schema.$_terms.ordered.slice(); - const inclusions = [...schema.$_terms._inclusions, ...requireds]; - const wasArray = !value[Common.symbols.arraySingle]; - delete value[Common.symbols.arraySingle]; - const errors = errorsArray(); - let il = value.length; - for (let i2 = 0; i2 < il; ++i2) { - const item = value[i2]; - let errored = false; - let isValid = false; - const key = wasArray ? i2 : new Number(i2); - const path8 = [...state.path, key]; - if (!schema._flags.sparse && item === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - ordereds.shift(); + let path8 = join10( + root, + !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename + ); + if (options2.isDir && await options2.isDir(path8)) { + path8 = join10(path8, DEFAULT_DOCUMENT); + } + const getContent = options2.getContent; + let content = await getContent(path8, c); + if (content instanceof Response) { + return c.newResponse(content.body, content); + } + if (content) { + const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); + c.header("Content-Type", mimeType || "application/octet-stream"); + if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { + const acceptEncodingSet = new Set( + c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) + ); + for (const encoding of ENCODINGS_ORDERED_KEYS) { + if (!acceptEncodingSet.has(encoding)) { continue; } - const ancestors = [value, ...state.ancestors]; - for (const exclusion of schema.$_terms._exclusions) { - if (!exclusion.$_match(item, state.localize(path8, ancestors, exclusion), prefs, { presence: "ignore" })) { - continue; - } - errors.push(error2("array.excludes", { pos: i2, value: item }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - errored = true; - ordereds.shift(); + const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); + if (compressedContent) { + content = compressedContent; + c.header("Content-Encoding", encoding); + c.header("Vary", "Accept-Encoding", { append: true }); break; } - if (errored) { - continue; - } - if (schema.$_terms.ordered.length) { - if (ordereds.length) { - const ordered = ordereds.shift(); - const res = ordered.$_validate(item, state.localize(path8, ancestors, ordered), prefs); - if (!res.errors) { - if (ordered._flags.result === "strip") { - internals.fastSplice(value, i2); - --i2; - --il; - } else if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - continue; - } else { - value[i2] = res.value; - } - } else { - errors.push(...res.errors); - if (prefs.abortEarly) { - return errors; - } - } - continue; - } else if (!schema.$_terms.items.length) { - errors.push(error2("array.orderedLength", { pos: i2, limit: schema.$_terms.ordered.length })); - if (prefs.abortEarly) { - return errors; - } - break; - } - } - const requiredChecks = []; - let jl = requireds.length; - for (let j = 0; j < jl; ++j) { - const localState = state.localize(path8, ancestors, requireds[j]); - localState.snapshot(); - const res = requireds[j].$_validate(item, localState, prefs); - requiredChecks[j] = res; - if (!res.errors) { - value[i2] = res.value; - isValid = true; - internals.fastSplice(requireds, j); - --j; - --jl; - if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - } - break; - } - localState.restore(); - } - if (isValid) { - continue; - } - const stripUnknown = prefs.stripUnknown && !!prefs.stripUnknown.arrays || false; - jl = inclusions.length; - for (const inclusion of inclusions) { - let res; - const previousCheck = requireds.indexOf(inclusion); - if (previousCheck !== -1) { - res = requiredChecks[previousCheck]; - } else { - const localState = state.localize(path8, ancestors, inclusion); - localState.snapshot(); - res = inclusion.$_validate(item, localState, prefs); - if (!res.errors) { - if (inclusion._flags.result === "strip") { - internals.fastSplice(value, i2); - --i2; - --il; - } else if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - errored = true; - } else { - value[i2] = res.value; - } - isValid = true; - break; - } - localState.restore(); - } - if (jl === 1) { - if (stripUnknown) { - internals.fastSplice(value, i2); - --i2; - --il; - isValid = true; - break; - } - errors.push(...res.errors); - if (prefs.abortEarly) { - return errors; - } - errored = true; - break; - } - } - if (errored) { - continue; - } - if (schema.$_terms._inclusions.length && !isValid) { - if (stripUnknown) { - internals.fastSplice(value, i2); - --i2; - --il; - continue; - } - errors.push(error2("array.includes", { pos: i2, value: item }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - } - } - if (requireds.length) { - internals.fillMissedErrors(schema, errors, requireds, value, state, prefs); - } - if (ordereds.length) { - internals.fillOrderedErrors(schema, errors, ordereds, value, state, prefs); - } - return errors.length ? errors : value; - }, - priority: true - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value.length, limit, operator)) { - return value; - } - return helpers.error("array." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } - }, - ordered: { - method(...schemas) { - Common.verifyFlat(schemas, "ordered"); - const obj = this.$_addRule("items"); - for (let i2 = 0; i2 < schemas.length; ++i2) { - const type = Common.tryWithPath(() => this.$_compile(schemas[i2]), i2, { append: true }); - internals.validateSingle(type, obj); - obj.$_mutateRegister(type); - obj.$_terms.ordered.push(type); - } - return obj.$_mutateRebuild(); } - }, - single: { - method(enabled2) { - const value = enabled2 === void 0 ? true : !!enabled2; - Assert(!value || !this._flags._arrayItems, "Cannot specify single rule when array has array items"); - return this.$_setFlag("single", value); - } - }, - sort: { - method(options2 = {}) { - Common.assertOptions(options2, ["by", "order"]); - const settings = { - order: options2.order || "ascending" - }; - if (options2.by) { - settings.by = Compile.ref(options2.by, { ancestor: 0 }); - Assert(!settings.by.ancestor, "Cannot sort by ancestor"); - } - return this.$_addRule({ name: "sort", args: { options: settings } }); - }, - validate(value, { error: error2, state, prefs, schema }, { options: options2 }) { - const { value: sorted, errors } = internals.sort(schema, value, options2, state, prefs); - if (errors) { - return errors; - } - for (let i2 = 0; i2 < value.length; ++i2) { - if (value[i2] !== sorted[i2]) { - return error2("array.sort", { order: options2.order, by: options2.by ? options2.by.key : "value" }); - } + await options2.onFound?.(path8, c); + return c.body(content); + } + await options2.onNotFound?.(path8, c); + await next(); + return; + }; + }; + } +}); +var open; +var lstatSync; +var errors; +var serveStatic2; +var init_serve_static2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/serve-static.js"() { + init_serve_static(); + ({ open, lstatSync, errors } = Deno); + serveStatic2 = (options2) => { + return async function serveStatic22(c, next) { + const getContent = async (path8) => { + try { + if (isDir(path8)) { + return null; } - return value; - }, - convert: true - }, - sparse: { - method(enabled2) { - const value = enabled2 === void 0 ? true : !!enabled2; - if (this._flags.sparse === value) { - return this; + const file = await open(path8); + return file.readable; + } catch (e2) { + if (!(e2 instanceof errors.NotFound)) { + console.warn(`${e2}`); } - const obj = value ? this.clone() : this.$_addRule("items"); - return obj.$_setFlag("sparse", value, { clone: false }); + return null; } - }, - unique: { - method(comparator, options2 = {}) { - Assert(!comparator || typeof comparator === "function" || typeof comparator === "string", "comparator must be a function or a string"); - Common.assertOptions(options2, ["ignoreUndefined", "separator"]); - const rule = { name: "unique", args: { options: options2, comparator } }; - if (comparator) { - if (typeof comparator === "string") { - const separator = Common.default(options2.separator, "."); - rule.path = separator ? comparator.split(separator) : [comparator]; - } else { - rule.comparator = comparator; - } - } - return this.$_addRule(rule); - }, - validate(value, { state, error: error2, schema }, { comparator: raw, options: options2 }, { comparator, path: path8 }) { - const found = { - string: /* @__PURE__ */ Object.create(null), - number: /* @__PURE__ */ Object.create(null), - undefined: /* @__PURE__ */ Object.create(null), - boolean: /* @__PURE__ */ Object.create(null), - object: /* @__PURE__ */ new Map(), - function: /* @__PURE__ */ new Map(), - custom: /* @__PURE__ */ new Map() - }; - const compare = comparator || DeepEqual; - const ignoreUndefined = options2.ignoreUndefined; - for (let i2 = 0; i2 < value.length; ++i2) { - const item = path8 ? Reach(value[i2], path8) : value[i2]; - const records = comparator ? found.custom : found[typeof item]; - Assert(records, "Failed to find unique map container for type", typeof item); - if (records instanceof Map) { - const entries = records.entries(); - let current; - while (!(current = entries.next()).done) { - if (compare(current.value[0], item)) { - const localState = state.localize([...state.path, i2], [value, ...state.ancestors]); - const context = { - pos: i2, - value: value[i2], - dupePos: current.value[1], - dupeValue: value[current.value[1]] - }; - if (path8) { - context.path = raw; - } - return error2("array.unique", context, localState); - } - } - records.set(item, i2); - } else { - if ((!ignoreUndefined || item !== void 0) && records[item] !== void 0) { - const context = { - pos: i2, - value: value[i2], - dupePos: records[item], - dupeValue: value[records[item]] - }; - if (path8) { - context.path = raw; - } - const localState = state.localize([...state.path, i2], [value, ...state.ancestors]); - return error2("array.unique", context, localState); - } - records[item] = i2; - } - } - return value; - }, - args: ["comparator", "options"], - multi: true - } - }, - cast: { - set: { - from: Array.isArray, - to(value, helpers) { - return new Set(value); + }; + const isDir = (path8) => { + let isDir2; + try { + const stat = lstatSync(path8); + isDir2 = stat.isDirectory; + } catch { } - } - }, - rebuild(schema) { - schema.$_terms._inclusions = []; - schema.$_terms._exclusions = []; - schema.$_terms._requireds = []; - for (const type of schema.$_terms.items) { - internals.validateSingle(type, schema); - if (type._flags.presence === "required") { - schema.$_terms._requireds.push(type); - } else if (type._flags.presence === "forbidden") { - schema.$_terms._exclusions.push(type); - } else { - schema.$_terms._inclusions.push(type); - } - } - for (const type of schema.$_terms.ordered) { - internals.validateSingle(type, schema); - } - }, - messages: { - "array.base": "{{#label}} must be an array", - "array.excludes": "{{#label}} contains an excluded value", - "array.hasUnknown": "{{#label}} does not contain at least one required match", - "array.includes": "{{#label}} does not match any of the allowed types", - "array.includesRequiredBoth": "{{#label}} does not contain {{#knownMisses}} and {{#unknownMisses}} other required value(s)", - "array.includesRequiredKnowns": "{{#label}} does not contain {{#knownMisses}}", - "array.includesRequiredUnknowns": "{{#label}} does not contain {{#unknownMisses}} required value(s)", - "array.length": "{{#label}} must contain {{#limit}} items", - "array.max": "{{#label}} must contain less than or equal to {{#limit}} items", - "array.min": "{{#label}} must contain at least {{#limit}} items", - "array.orderedLength": "{{#label}} must contain at most {{#limit}} items", - "array.sort": "{{#label}} must be sorted in {#order} order by {{#by}}", - "array.sort.mismatching": "{{#label}} cannot be sorted due to mismatching types", - "array.sort.unsupported": "{{#label}} cannot be sorted due to unsupported type {#type}", - "array.sparse": "{{#label}} must not be a sparse array item", - "array.unique": "{{#label}} contains a duplicate value" - } - }); - internals.fillMissedErrors = function(schema, errors, requireds, value, state, prefs) { - let unknownMisses = 0; - for (let i2 = 0; i2 < requireds.length; ++i2) { - ++unknownMisses; - } - errors.push(schema.$_createError("array.includesRequiredUnknowns", value, { unknownMisses }, state, prefs)); + return isDir2; + }; + return serveStatic({ + ...options2, + getContent, + join: join72, + isDir + })(c, next); + }; }; - internals.fillOrderedErrors = function(schema, errors, ordereds, value, state, prefs) { - const requiredOrdereds = []; - for (const ordered of ordereds) { - if (ordered._flags.presence === "required") { - requiredOrdereds.push(ordered); - } + } +}); +var init_fetch_result_please = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/client/fetch-result-please.js"() { + } +}); +var init_utils2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/client/utils.js"() { + init_fetch_result_please(); + } +}); +var init_concurrent = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/concurrent.js"() { + } +}); +var init_handler = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/handler.js"() { + init_constants3(); + } +}); +var init_utils3 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/utils.js"() { + init_router(); + init_handler(); + } +}); +var X_HONO_DISABLE_SSG_HEADER_KEY; +var SSG_DISABLED_RESPONSE; +var init_middleware = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/middleware.js"() { + init_utils3(); + X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; + SSG_DISABLED_RESPONSE = (() => { + try { + return new Response("SSG is disabled", { + status: 404, + headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } + }); + } catch { + return null; } - if (requiredOrdereds.length) { - internals.fillMissedErrors(schema, errors, requiredOrdereds, value, state, prefs); + })(); + } +}); +var init_html2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/html/index.js"() { + init_html(); + } +}); +var init_plugins = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/plugins.js"() { + init_html2(); + } +}); +var init_ssg = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/ssg.js"() { + init_utils2(); + init_concurrent(); + init_mime(); + init_middleware(); + init_plugins(); + init_utils3(); + } +}); +var init_ssg2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/index.js"() { + init_ssg(); + init_middleware(); + init_plugins(); + } +}); +var init_ssg3 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/ssg.js"() { + init_ssg2(); + } +}); +var WSContext; +var defineWebSocketHelper; +var init_websocket = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/websocket/index.js"() { + WSContext = class { + #init; + constructor(init2) { + this.#init = init2; + this.raw = init2.raw; + this.url = init2.url ? new URL(init2.url) : null; + this.protocol = init2.protocol ?? null; } - }; - internals.fastSplice = function(arr, i2) { - let pos = i2; - while (pos < arr.length) { - arr[pos++] = arr[pos]; + send(source, options2) { + this.#init.send(source, options2 ?? {}); } - --arr.length; - }; - internals.validateSingle = function(type, obj) { - if (type.type === "array" || type._flags._arrayItems) { - Assert(!obj._flags.single, "Cannot specify array item with single rule enabled"); - obj.$_setFlag("_arrayItems", true, { clone: false }); + raw; + binaryType = "arraybuffer"; + get readyState() { + return this.#init.readyState; } - }; - internals.sort = function(schema, value, settings, state, prefs) { - const order = settings.order === "ascending" ? 1 : -1; - const aFirst = -1 * order; - const bFirst = order; - const sort = (a, b) => { - let compare = internals.compare(a, b, aFirst, bFirst); - if (compare !== null) { - return compare; - } - if (settings.by) { - a = settings.by.resolve(a, state, prefs); - b = settings.by.resolve(b, state, prefs); - } - compare = internals.compare(a, b, aFirst, bFirst); - if (compare !== null) { - return compare; - } - const type = typeof a; - if (type !== typeof b) { - throw schema.$_createError("array.sort.mismatching", value, null, state, prefs); - } - if (type !== "number" && type !== "string") { - throw schema.$_createError("array.sort.unsupported", value, { type }, state, prefs); - } - if (type === "number") { - return (a - b) * order; + url; + protocol; + close(code2, reason) { + this.#init.close(code2, reason); + } + }; + defineWebSocketHelper = (handler) => { + return (...args) => { + if (typeof args[0] === "function") { + const [createEvents, options2] = args; + return async function upgradeWebSocket2(c, next) { + const events = await createEvents(c); + const result = await handler(c, events, options2); + if (result) { + return result; + } + await next(); + }; + } else { + const [c, events, options2] = args; + return (async () => { + const upgraded = await handler(c, events, options2); + if (!upgraded) { + throw new Error("Failed to upgrade WebSocket"); + } + return upgraded; + })(); } - return a < b ? aFirst : bFirst; }; - try { - return { value: value.slice().sort(sort) }; - } catch (err) { - return { errors: err }; - } }; - internals.compare = function(a, b, aFirst, bFirst) { - if (a === b) { - return 0; - } - if (a === void 0) { - return 1; - } - if (b === void 0) { - return -1; - } - if (a === null) { - return bFirst; - } - if (b === null) { - return aFirst; + } +}); +var upgradeWebSocket; +var init_websocket2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/websocket.js"() { + init_websocket(); + upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { + if (c.req.header("upgrade") !== "websocket") { + return; } - return null; - }; + const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); + const wsContext = new WSContext({ + close: (code2, reason) => socket.close(code2, reason), + get protocol() { + return socket.protocol; + }, + raw: socket, + get readyState() { + return socket.readyState; + }, + url: socket.url ? new URL(socket.url) : null, + send: (source) => socket.send(source) + }); + socket.onopen = (evt) => events.onOpen?.(evt, wsContext); + socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); + socket.onclose = (evt) => events.onClose?.(evt, wsContext); + socket.onerror = (evt) => events.onError?.(evt, wsContext); + return response; + }); + } +}); +var init_conninfo = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/conninfo.js"() { + } +}); +var init_deno = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/index.js"() { + init_serve_static2(); + init_ssg3(); + init_websocket2(); + init_conninfo(); } }); -var require_boolean = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/boolean.js"(exports2, module14) { +var dashboard_server_exports = {}; +__export(dashboard_server_exports, { + default: () => dashboard_server_default, + startDashboard: () => startDashboard +}); +async function startDashboard() { + const port = import_npm_nconf4.default.get("server:dashboardPort"); + const host = import_npm_nconf4.default.get("server:host") || "0.0.0.0"; + const dashboardRoot = getDashboardPath(); + const app3 = new Hono2(); + app3.get("/assets/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); + app3.get("/dashboard", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); + app3.get("/dashboard/", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); + app3.get("/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); + app3.get("/*", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); + await new Promise((resolve82) => { + Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app3.fetch); + }); +} +var import_npm_nconf4; +var getDashboardPath; +var dashboard_server_default; +var init_dashboard_server = __esm({ + "src/serve/dashboard-server.ts"() { "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - var Values = require_values(); - var internals = {}; - internals.isBool = function(value) { - return typeof value === "boolean"; + init_dist(); + init_deno(); + import_npm_nconf4 = __toESM(require_nconf()); + getDashboardPath = () => { + return path5.resolve(import.meta.dirname || process5.cwd(), "dist-dashboard"); + }; + dashboard_server_default = startDashboard; + } +}); +var isEventQueueSbpEvent2; +var esm_default5; +var init_esm9 = __esm({ + "node_modules/.deno/@sbp+okturtles.eventqueue@1.2.0/node_modules/@sbp/okturtles.eventqueue/dist/esm/index.js"() { + init_esm(); + isEventQueueSbpEvent2 = (e2) => { + return Object.prototype.hasOwnProperty.call(e2, "sbpInvocation"); }; - module14.exports = Any._extend({ - type: "boolean", - flags: { - sensitive: { default: false } + esm_default5 = esm_default("sbp/selectors/register", { + "okTurtles.eventQueue/_init": function() { + this.eventQueues = /* @__PURE__ */ Object.create(null); }, - terms: { - falsy: { - init: null - }, - truthy: { - init: null - } + "okTurtles.eventQueue/isWaiting": function(name) { + var _a2; + return !!((_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.length); }, - coerce(value, { schema }) { - if (typeof value === "boolean") { - return; - } - if (typeof value === "string") { - const normalized = schema._flags.sensitive ? value : value.toLowerCase(); - value = normalized === "true" ? true : normalized === "false" ? false : value; - } - if (typeof value !== "boolean") { - value = schema.$_terms.truthy?.has(value, null, null, !schema._flags.sensitive) || (schema.$_terms.falsy?.has(value, null, null, !schema._flags.sensitive) ? false : value); + "okTurtles.eventQueue/queuedInvocations": function(name) { + var _a2, _b; + if (name == null) { + return Object.fromEntries(Object.entries(this.eventQueues).map(([name2, events]) => [name2, events.map((event) => { + if (isEventQueueSbpEvent2(event)) { + return event.sbpInvocation; + } else { + return event.fn; + } + })])); } - return { value }; + return (_b = (_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.map((event) => { + if (isEventQueueSbpEvent2(event)) { + return event.sbpInvocation; + } else { + return event.fn; + } + })) !== null && _b !== void 0 ? _b : []; }, - validate(value, { error: error2 }) { - if (typeof value !== "boolean") { - return { value, errors: error2("boolean.base") }; + "okTurtles.eventQueue/queueEvent": async function(name, invocation) { + if (!Object.prototype.hasOwnProperty.call(this.eventQueues, name)) { + this.eventQueues[name] = []; } - }, - rules: { - truthy: { - method(...values) { - Common.verifyFlat(values, "truthy"); - const obj = this.clone(); - obj.$_terms.truthy = obj.$_terms.truthy || new Values(); - for (let i2 = 0; i2 < values.length; ++i2) { - const value = values[i2]; - Assert(value !== void 0, "Cannot call truthy with undefined"); - obj.$_terms.truthy.add(value); + const events = this.eventQueues[name]; + let accept; + const promise = new Promise((resolve82) => { + accept = resolve82; + }); + const thisEvent = typeof invocation === "function" ? { + fn: invocation, + promise + } : { + sbpInvocation: invocation, + promise + }; + events.push(thisEvent); + while (events.length > 0) { + const event = events[0]; + if (event === thisEvent) { + try { + if (typeof invocation === "function") { + return await invocation(); + } else { + return await esm_default(...invocation); + } + } finally { + accept(); + events.shift(); } - return obj; - } - }, - falsy: { - method(...values) { - Common.verifyFlat(values, "falsy"); - const obj = this.clone(); - obj.$_terms.falsy = obj.$_terms.falsy || new Values(); - for (let i2 = 0; i2 < values.length; ++i2) { - const value = values[i2]; - Assert(value !== void 0, "Cannot call falsy with undefined"); - obj.$_terms.falsy.add(value); - } - return obj; - } - }, - sensitive: { - method(enabled2 = true) { - return this.$_setFlag("sensitive", enabled2); - } - } - }, - cast: { - number: { - from: internals.isBool, - to(value, helpers) { - return value ? 1 : 0; - } - }, - string: { - from: internals.isBool, - to(value, helpers) { - return value ? "true" : "false"; + } else { + await event.promise; } } - }, - messages: { - "boolean.base": "{{#label}} must be a boolean" } }); } }); -var require_date = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/date.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - var Template = require_template(); - var internals = {}; - internals.isDate = function(value) { - return value instanceof Date; - }; - module14.exports = Any._extend({ - type: "date", - coerce: { - from: ["number", "string"], - method(value, { schema }) { - return { value: internals.parse(value, schema._flags.format) || value }; - } +var listenKey2; +var esm_default6; +var init_esm10 = __esm({ + "node_modules/.deno/@sbp+okturtles.events@1.0.0/node_modules/@sbp/okturtles.events/dist/esm/index.js"() { + init_esm(); + init_esm3(); + listenKey2 = (evt) => `events/${evt}/listeners`; + esm_default6 = esm_default("sbp/selectors/register", { + "okTurtles.events/_init": function() { + this.errorHandler = (event, e2) => { + console.error(`[okTurtles.events] Error at handler for ${event}`, e2); + }; }, - validate(value, { schema, error: error2, prefs }) { - if (value instanceof Date && !isNaN(value.getTime())) { - return; - } - const format52 = schema._flags.format; - if (!prefs.convert || !format52 || typeof value !== "string") { - return { value, errors: error2("date.base") }; - } - return { value, errors: error2("date.format", { format: format52 }) }; + "okTurtles.events/on": function(event, handler) { + esm_default("okTurtles.data/add", listenKey2(event), handler); + return () => esm_default("okTurtles.events/off", event, handler); }, - rules: { - compare: { - method: false, - validate(value, helpers, { date: date3 }, { name, operator, args }) { - const to = date3 === "now" ? Date.now() : date3.getTime(); - if (Common.compare(value.getTime(), to, operator)) { - return value; - } - return helpers.error("date." + name, { limit: args.date, value }); - }, - args: [ - { - name: "date", - ref: true, - normalize: (date3) => { - return date3 === "now" ? date3 : internals.parse(date3); - }, - assert: (date3) => date3 !== null, - message: "must have a valid date format" - } - ] - }, - format: { - method(format52) { - Assert(["iso", "javascript", "unix"].includes(format52), "Unknown date format", format52); - return this.$_setFlag("format", format52); - } - }, - greater: { - method(date3) { - return this.$_addRule({ name: "greater", method: "compare", args: { date: date3 }, operator: ">" }); - } - }, - iso: { - method() { - return this.format("iso"); - } - }, - less: { - method(date3) { - return this.$_addRule({ name: "less", method: "compare", args: { date: date3 }, operator: "<" }); - } - }, - max: { - method(date3) { - return this.$_addRule({ name: "max", method: "compare", args: { date: date3 }, operator: "<=" }); - } - }, - min: { - method(date3) { - return this.$_addRule({ name: "min", method: "compare", args: { date: date3 }, operator: ">=" }); - } - }, - timestamp: { - method(type = "javascript") { - Assert(["javascript", "unix"].includes(type), '"type" must be one of "javascript, unix"'); - return this.format(type); + "okTurtles.events/once": function(event, handler) { + const cbWithOff = (...args) => { + handler(...args); + esm_default("okTurtles.events/off", event, cbWithOff); + }; + return esm_default("okTurtles.events/on", event, cbWithOff); + }, + "okTurtles.events/emit": function(event, ...data) { + var _a2; + for (const listener of esm_default("okTurtles.data/get", listenKey2(event)) || []) { + try { + listener(...data); + } catch (e2) { + (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); } } }, - cast: { - number: { - from: internals.isDate, - to(value, helpers) { - return value.getTime(); - } - }, - string: { - from: internals.isDate, - to(value, { prefs }) { - return Template.date(value, prefs); - } + // almost identical to Vue.prototype.$off, except we require `event` argument + "okTurtles.events/off": function(event, handler) { + if (handler) { + esm_default("okTurtles.data/remove", listenKey2(event), handler); + } else { + esm_default("okTurtles.data/delete", listenKey2(event)); } }, - messages: { - "date.base": "{{#label}} must be a valid date", - "date.format": "{{#label}} must be in {{#format}} format", - "date.greater": "{{#label}} must be greater than {{:#limit}}", - "date.less": "{{#label}} must be less than {{:#limit}}", - "date.max": "{{#label}} must be less than or equal to {{:#limit}}", - "date.min": "{{#label}} must be greater than or equal to {{:#limit}}" + "okTurtles.events/setErrorHandler": function(errorHandler2) { + this.errorHandler = errorHandler2; } }); - internals.parse = function(value, format52) { - if (value instanceof Date) { - return value; + } +}); +var require_has_flag = __commonJS({ + "node_modules/.deno/has-flag@4.0.0/node_modules/has-flag/index.js"(exports2, module14) { + "use strict"; + module14.exports = (flag, argv = process.argv) => { + const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf("--"); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); + }; + } +}); +var require_supports_color = __commonJS({ + "node_modules/.deno/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module14) { + "use strict"; + var os = __require2("os"); + var tty = __require2("tty"); + var hasFlag = require_has_flag(); + var { env: env2 } = process; + var forceColor; + if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { + forceColor = 0; + } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { + forceColor = 1; + } + if ("FORCE_COLOR" in env2) { + if (env2.FORCE_COLOR === "true") { + forceColor = 1; + } else if (env2.FORCE_COLOR === "false") { + forceColor = 0; + } else { + forceColor = env2.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env2.FORCE_COLOR, 10), 3); } - if (typeof value !== "string" && (isNaN(value) || !isFinite(value))) { - return null; + } + function translateLevel(level) { + if (level === 0) { + return false; } - if (/^\s*$/.test(value)) { - return null; + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; + } + function supportsColor(haveStream, streamIsTTY) { + if (forceColor === 0) { + return 0; } - if (format52 === "iso") { - if (!Common.isIsoDate(value)) { - return null; - } - return internals.date(value.toString()); + if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { + return 3; } - const original = value; - if (typeof value === "string" && /^[+-]?\d+(\.\d+)?$/.test(value)) { - value = parseFloat(value); + if (hasFlag("color=256")) { + return 2; } - if (format52) { - if (format52 === "javascript") { - return internals.date(1 * value); - } - if (format52 === "unix") { - return internals.date(1e3 * value); - } - if (typeof original === "string") { - return null; - } + if (haveStream && !streamIsTTY && forceColor === void 0) { + return 0; } - return internals.date(value); - }; - internals.date = function(value) { - const date3 = new Date(value); - if (!isNaN(date3.getTime())) { - return date3; + const min = forceColor || 0; + if (env2.TERM === "dumb") { + return min; } - return null; - }; - } -}); -var require_lib8 = __commonJS({ - "node_modules/.deno/@hapi+topo@6.0.2/node_modules/@hapi/topo/lib/index.js"(exports2) { - "use strict"; - var { assert: assert2 } = require_lib(); - var internals = {}; - exports2.Sorter = class { - constructor() { - this._items = []; - this.nodes = []; - } - add(nodes, options2) { - options2 = options2 ?? {}; - const before = [].concat(options2.before ?? []); - const after = [].concat(options2.after ?? []); - const group = options2.group ?? "?"; - const sort = options2.sort ?? 0; - assert2(!before.includes(group), `Item cannot come before itself: ${group}`); - assert2(!before.includes("?"), "Item cannot come before unassociated items"); - assert2(!after.includes(group), `Item cannot come after itself: ${group}`); - assert2(!after.includes("?"), "Item cannot come after unassociated items"); - if (!Array.isArray(nodes)) { - nodes = [nodes]; - } - for (const node of nodes) { - const item = { - seq: this._items.length, - sort, - before, - after, - group, - node - }; - this._items.push(item); - } - if (!options2.manual) { - const valid = this._sort(); - assert2(valid, "item", group !== "?" ? `added into group ${group}` : "", "created a dependencies error"); + if (process.platform === "win32") { + const osRelease = os.release().split("."); + if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; } - return this.nodes; + return 1; } - merge(others) { - if (!Array.isArray(others)) { - others = [others]; - } - for (const other of others) { - if (other) { - for (const item of other._items) { - this._items.push(Object.assign({}, item)); - } - } - } - this._items.sort(internals.mergeSort); - for (let i2 = 0; i2 < this._items.length; ++i2) { - this._items[i2].seq = i2; + if ("CI" in env2) { + if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign2) => sign2 in env2) || env2.CI_NAME === "codeship") { + return 1; } - const valid = this._sort(); - assert2(valid, "merge created a dependencies error"); - return this.nodes; + return min; } - sort() { - const valid = this._sort(); - assert2(valid, "sort created a dependencies error"); - return this.nodes; + if ("TEAMCITY_VERSION" in env2) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env2.TEAMCITY_VERSION) ? 1 : 0; } - _sort() { - const graph = {}; - const graphAfters = /* @__PURE__ */ Object.create(null); - const groups = /* @__PURE__ */ Object.create(null); - for (const item of this._items) { - const seq = item.seq; - const group = item.group; - groups[group] = groups[group] ?? []; - groups[group].push(seq); - graph[seq] = item.before; - for (const after of item.after) { - graphAfters[after] = graphAfters[after] ?? []; - graphAfters[after].push(seq); - } - } - for (const node in graph) { - const expandedGroups = []; - for (const graphNodeItem in graph[node]) { - const group = graph[node][graphNodeItem]; - groups[group] = groups[group] ?? []; - expandedGroups.push(...groups[group]); - } - graph[node] = expandedGroups; - } - for (const group in graphAfters) { - if (groups[group]) { - for (const node of groups[group]) { - graph[node].push(...graphAfters[group]); - } - } - } - const ancestors = {}; - for (const node in graph) { - const children = graph[node]; - for (const child of children) { - ancestors[child] = ancestors[child] ?? []; - ancestors[child].push(node); - } - } - const visited = {}; - const sorted = []; - for (let i2 = 0; i2 < this._items.length; ++i2) { - let next = i2; - if (ancestors[i2]) { - next = null; - for (let j = 0; j < this._items.length; ++j) { - if (visited[j] === true) { - continue; - } - if (!ancestors[j]) { - ancestors[j] = []; - } - const shouldSeeCount = ancestors[j].length; - let seenCount = 0; - for (let k = 0; k < shouldSeeCount; ++k) { - if (visited[ancestors[j][k]]) { - ++seenCount; - } - } - if (seenCount === shouldSeeCount) { - next = j; - break; - } - } - } - if (next !== null) { - visited[next] = true; - sorted.push(next); - } - } - if (sorted.length !== this._items.length) { - return false; - } - const seqIndex = {}; - for (const item of this._items) { - seqIndex[item.seq] = item; - } - this._items = []; - this.nodes = []; - for (const value of sorted) { - const sortedItem = seqIndex[value]; - this.nodes.push(sortedItem.node); - this._items.push(sortedItem); + if (env2.COLORTERM === "truecolor") { + return 3; + } + if ("TERM_PROGRAM" in env2) { + const version3 = parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10); + switch (env2.TERM_PROGRAM) { + case "iTerm.app": + return version3 >= 3 ? 3 : 2; + case "Apple_Terminal": + return 2; } - return true; } - }; - internals.mergeSort = (a, b) => { - return a.sort === b.sort ? 0 : a.sort < b.sort ? -1 : 1; + if (/-256(color)?$/i.test(env2.TERM)) { + return 2; + } + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env2.TERM)) { + return 1; + } + if ("COLORTERM" in env2) { + return 1; + } + return min; + } + function getSupportLevel(stream) { + const level = supportsColor(stream, stream && stream.isTTY); + return translateLevel(level); + } + module14.exports = { + supportsColor: getSupportLevel, + stdout: translateLevel(supportsColor(true, tty.isatty(1))), + stderr: translateLevel(supportsColor(true, tty.isatty(2))) }; } }); -var require_keys = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/keys.js"(exports2, module14) { +var require_util2 = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/util.js"(exports2, module14) { "use strict"; - var ApplyToDefaults = require_applyToDefaults(); - var Assert = require_assert(); - var Clone = require_clone(); - var Topo = require_lib8(); - var Any = require_any(); - var Common = require_common2(); - var Compile = require_compile(); - var Errors = require_errors2(); - var Ref = require_ref(); - var internals = { - renameDefaults: { - alias: false, - // Keep old value in place - multiple: false, - // Allow renaming multiple keys into the same target - override: false - // Overrides an existing key + var stringReplaceAll = (string3, substring, replacer) => { + let index = string3.indexOf(substring); + if (index === -1) { + return string3; } + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ""; + do { + returnValue += string3.substr(endIndex, index - endIndex) + substring + replacer; + endIndex = index + substringLength; + index = string3.indexOf(substring, endIndex); + } while (index !== -1); + returnValue += string3.substr(endIndex); + return returnValue; }; - module14.exports = Any._extend({ - type: "_keys", - properties: { - typeof: "object" - }, - flags: { - unknown: { default: false } - }, - terms: { - dependencies: { init: null }, - keys: { init: null }, - patterns: { init: null }, - renames: { init: null } - }, - args(schema, keys) { - return schema.keys(keys); - }, - validate(value, { schema, error: error2, state, prefs }) { - if (!value || typeof value !== schema.$_property("typeof") || Array.isArray(value)) { - return { value, errors: error2("object.base", { type: schema.$_property("typeof") }) }; - } - if (!schema.$_terms.renames && !schema.$_terms.dependencies && !schema.$_terms.keys && // null allows any keys - !schema.$_terms.patterns) { - return; - } - value = internals.clone(value, prefs); - const errors = []; - if (schema.$_terms.renames && !internals.rename(schema, value, state, prefs, errors)) { - return { value, errors }; - } - if (!schema.$_terms.keys && // null allows any keys - !schema.$_terms.patterns && !schema.$_terms.dependencies) { - return { value, errors }; - } - const unprocessed = new Set(Object.keys(value)); - if (schema.$_terms.keys) { - const ancestors = [value, ...state.ancestors]; - for (const child of schema.$_terms.keys) { - const key = child.key; - const item = value[key]; - unprocessed.delete(key); - const localState = state.localize([...state.path, key], ancestors, child); - const result = child.schema.$_validate(item, localState, prefs); - if (result.errors) { - if (prefs.abortEarly) { - return { value, errors: result.errors }; - } - errors.push(...result.errors); - } else if (child.schema._flags.result === "strip" || result.value === void 0 && item !== void 0) { - delete value[key]; - } else if (result.value !== void 0) { - value[key] = result.value; - } - } - } - if (unprocessed.size || schema._flags._hasPatternMatch) { - const early = internals.unknown(schema, value, unprocessed, errors, state, prefs); - if (early) { - return early; - } - } - if (schema.$_terms.dependencies) { - for (const dep of schema.$_terms.dependencies) { - if (dep.key && dep.key.resolve(value, state, prefs, null, { shadow: false }) === void 0) { - continue; - } - const failed = internals.dependencies[dep.rel](schema, dep, value, state, prefs); - if (failed) { - const report = schema.$_createError(failed.code, value, failed.context, state, prefs); - if (prefs.abortEarly) { - return { value, errors: report }; - } - errors.push(report); - } - } - } - return { value, errors }; - }, - rules: { - and: { - method(...peers) { - Common.verifyFlat(peers, "and"); - return internals.dependency(this, "and", null, peers); - } - }, - append: { - method(schema) { - if (schema === null || schema === void 0 || Object.keys(schema).length === 0) { - return this; - } - return this.keys(schema); - } - }, - assert: { - method(subject, schema, message) { - subject = Compile.ref(subject); - Assert(message === void 0 || typeof message === "string", "Message must be a string"); - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.$_addRule({ name: "assert", args: { subject, schema, message } }); - obj.$_mutateRegister(subject); - obj.$_mutateRegister(schema); - return obj; - }, - validate(value, { error: error2, prefs, state }, { subject, schema, message }) { - const about = subject.resolve(value, state, prefs); - const path8 = subject.absolute(state); - if (schema.$_match(about, state.localize(path8, [value, ...state.ancestors], schema), prefs)) { - return value; - } - return error2("object.assert", { subject, message }); - }, - args: ["subject", "schema", "message"], - multi: true - }, - instance: { - method(constructor, name) { - Assert(typeof constructor === "function", "constructor must be a function"); - name = name || constructor.name; - return this.$_addRule({ name: "instance", args: { constructor, name } }); - }, - validate(value, helpers, { constructor, name }) { - if (value instanceof constructor) { - return value; - } - return helpers.error("object.instance", { type: name, value }); - }, - args: ["constructor", "name"] - }, - keys: { - method(schema) { - Assert(schema === void 0 || typeof schema === "object", "Object schema must be a valid object"); - Assert(!Common.isSchema(schema), "Object schema cannot be a joi schema"); - const obj = this.clone(); - if (!schema) { - obj.$_terms.keys = null; - } else if (!Object.keys(schema).length) { - obj.$_terms.keys = new internals.Keys(); - } else { - obj.$_terms.keys = obj.$_terms.keys ? obj.$_terms.keys.filter((child) => !schema.hasOwnProperty(child.key)) : new internals.Keys(); - for (const key in schema) { - Common.tryWithPath(() => obj.$_terms.keys.push({ key, schema: this.$_compile(schema[key]) }), key); - } - } - return obj.$_mutateRebuild(); - } - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(Object.keys(value).length, limit, operator)) { - return value; - } - return helpers.error("object." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } - }, - nand: { - method(...peers) { - Common.verifyFlat(peers, "nand"); - return internals.dependency(this, "nand", null, peers); - } - }, - or: { - method(...peers) { - Common.verifyFlat(peers, "or"); - return internals.dependency(this, "or", null, peers); - } - }, - oxor: { - method(...peers) { - return internals.dependency(this, "oxor", null, peers); - } - }, - pattern: { - method(pattern, schema, options2 = {}) { - const isRegExp = pattern instanceof RegExp; - if (!isRegExp) { - pattern = this.$_compile(pattern, { appendPath: true }); - } - Assert(schema !== void 0, "Invalid rule"); - Common.assertOptions(options2, ["fallthrough", "matches"]); - if (isRegExp) { - Assert(!pattern.flags.includes("g") && !pattern.flags.includes("y"), "pattern should not use global or sticky mode"); - } - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.clone(); - obj.$_terms.patterns = obj.$_terms.patterns || []; - const config2 = { [isRegExp ? "regex" : "schema"]: pattern, rule: schema }; - if (options2.matches) { - config2.matches = this.$_compile(options2.matches); - if (config2.matches.type !== "array") { - config2.matches = config2.matches.$_root.array().items(config2.matches); - } - obj.$_mutateRegister(config2.matches); - obj.$_setFlag("_hasPatternMatch", true, { clone: false }); - } - if (options2.fallthrough) { - config2.fallthrough = true; - } - obj.$_terms.patterns.push(config2); - obj.$_mutateRegister(schema); - return obj; - } - }, - ref: { - method() { - return this.$_addRule("ref"); - }, - validate(value, helpers) { - if (Ref.isRef(value)) { - return value; - } - return helpers.error("object.refType", { value }); - } - }, - regex: { - method() { - return this.$_addRule("regex"); - }, - validate(value, helpers) { - if (value instanceof RegExp) { - return value; - } - return helpers.error("object.regex", { value }); - } - }, - rename: { - method(from3, to, options2 = {}) { - Assert(typeof from3 === "string" || from3 instanceof RegExp, "Rename missing the from argument"); - Assert(typeof to === "string", "Invalid rename to argument"); - Assert(to !== from3, "Cannot rename key to same name:", from3); - Common.assertOptions(options2, ["alias", "ignoreUndefined", "override", "multiple"]); - const obj = this.clone(); - obj.$_terms.renames = obj.$_terms.renames || []; - for (const rename of obj.$_terms.renames) { - Assert(rename.from !== from3, "Cannot rename the same key multiple times"); - } - obj.$_terms.renames.push({ - from: from3, - to, - options: ApplyToDefaults(internals.renameDefaults, options2) - }); - return obj; - } - }, - schema: { - method(type = "any") { - return this.$_addRule({ name: "schema", args: { type } }); - }, - validate(value, helpers, { type }) { - if (Common.isSchema(value) && (type === "any" || value.type === type)) { - return value; - } - return helpers.error("object.schema", { type }); - } - }, - unknown: { - method(allow) { - return this.$_setFlag("unknown", allow !== false); - } - }, - with: { - method(key, peers, options2 = {}) { - return internals.dependency(this, "with", key, peers, options2); - } - }, - without: { - method(key, peers, options2 = {}) { - return internals.dependency(this, "without", key, peers, options2); - } - }, - xor: { - method(...peers) { - Common.verifyFlat(peers, "xor"); - return internals.dependency(this, "xor", null, peers); - } - } - }, - overrides: { - default(value, options2) { - if (value === void 0) { - value = Common.symbols.deepDefault; - } - return this.$_parent("default", value, options2); - } - }, - rebuild(schema) { - if (schema.$_terms.keys) { - const topo = new Topo.Sorter(); - for (const child of schema.$_terms.keys) { - Common.tryWithPath(() => topo.add(child, { after: child.schema.$_rootReferences(), group: child.key }), child.key); - } - schema.$_terms.keys = new internals.Keys(...topo.nodes); - } - }, - messages: { - "object.and": "{{#label}} contains {{#present}} without its required peers {{#missing}}", - "object.assert": "{{#label}} is invalid because it failed to pass the assertion test", - "object.base": "{{#label}} must be of type {{#type}}", - "object.instance": "{{#label}} must be an instance of {{:#type}}", - "object.length": "{{#label}} must have {{#limit}} keys", - "object.max": "{{#label}} must have less than or equal to {{#limit}} keys", - "object.min": "{{#label}} must have at least {{#limit}} keys", - "object.missing": "{{#label}} must contain at least one of {{#peers}}", - "object.nand": "{{:#main}} must not exist simultaneously with {{#peers}}", - "object.oxor": "{{#label}} contains a conflict between optional exclusive peers {{#peers}}", - "object.pattern.match": "{{#label}} keys failed to match pattern requirements", - "object.refType": "{{#label}} must be a Joi reference", - "object.regex": "{{#label}} must be a RegExp object", - "object.rename.multiple": "{{#label}} cannot rename {{:#from}} because multiple renames are disabled and another key was already renamed to {{:#to}}", - "object.rename.override": "{{#label}} cannot rename {{:#from}} because override is disabled and target {{:#to}} exists", - "object.schema": "{{#label}} must be a Joi schema of {{#type}} type", - "object.unknown": "{{#label}} is not allowed", - "object.with": "{{:#main}} missing required peer {{:#peer}}", - "object.without": "{{:#main}} conflict with forbidden peer {{:#peer}}", - "object.xor": "{{#label}} contains a conflict between exclusive peers {{#peers}}" + var stringEncaseCRLFWithFirstIndex = (string3, prefix, postfix, index) => { + let endIndex = 0; + let returnValue = ""; + do { + const gotCR = string3[index - 1] === "\r"; + returnValue += string3.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? "\r\n" : "\n") + postfix; + endIndex = index + 1; + index = string3.indexOf("\n", endIndex); + } while (index !== -1); + returnValue += string3.substr(endIndex); + return returnValue; + }; + module14.exports = { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex + }; + } +}); +var require_templates = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/templates.js"(exports2, module14) { + "use strict"; + var TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; + var STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; + var STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; + var ESCAPE_REGEX2 = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; + var ESCAPES = /* @__PURE__ */ new Map([ + ["n", "\n"], + ["r", "\r"], + ["t", " "], + ["b", "\b"], + ["f", "\f"], + ["v", "\v"], + ["0", "\0"], + ["\\", "\\"], + ["e", "\x1B"], + ["a", "\x07"] + ]); + function unescape(c) { + const u2 = c[0] === "u"; + const bracket = c[1] === "{"; + if (u2 && !bracket && c.length === 5 || c[0] === "x" && c.length === 3) { + return String.fromCharCode(parseInt(c.slice(1), 16)); } - }); - internals.clone = function(value, prefs) { - if (typeof value === "object") { - if (prefs.nonEnumerables) { - return Clone(value, { shallow: true }); - } - const clone3 = Object.create(Object.getPrototypeOf(value)); - Object.assign(clone3, value); - return clone3; + if (u2 && bracket) { + return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); } - const clone2 = function(...args) { - return value.apply(this, args); - }; - clone2.prototype = Clone(value.prototype); - Object.defineProperty(clone2, "name", { value: value.name, writable: false }); - Object.defineProperty(clone2, "length", { value: value.length, writable: false }); - Object.assign(clone2, value); - return clone2; - }; - internals.dependency = function(schema, rel, key, peers, options2) { - Assert(key === null || typeof key === "string", rel, "key must be a strings"); - if (!options2) { - options2 = peers.length > 1 && typeof peers[peers.length - 1] === "object" ? peers.pop() : {}; - } - Common.assertOptions(options2, ["separator"]); - peers = [].concat(peers); - const separator = Common.default(options2.separator, "."); - const paths = []; - for (const peer of peers) { - Assert(typeof peer === "string", rel, "peers must be a string or a reference"); - paths.push(Compile.ref(peer, { separator, ancestor: 0, prefix: false })); - } - if (key !== null) { - key = Compile.ref(key, { separator, ancestor: 0, prefix: false }); - } - const obj = schema.clone(); - obj.$_terms.dependencies = obj.$_terms.dependencies || []; - obj.$_terms.dependencies.push(new internals.Dependency(rel, key, paths, peers)); - return obj; - }; - internals.dependencies = { - and(schema, dep, value, state, prefs) { - const missing = []; - const present = []; - const count = dep.peers.length; - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) === void 0) { - missing.push(peer.key); - } else { - present.push(peer.key); - } - } - if (missing.length !== count && present.length !== count) { - return { - code: "object.and", - context: { - present, - missing - } - }; - } - }, - nand(schema, dep, value, state, prefs) { - const present = []; - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) !== void 0) { - present.push(peer.key); - } - } - if (present.length !== dep.peers.length) { - return; - } - const main = dep.paths[0]; - const values = dep.paths.slice(1); - return { - code: "object.nand", - context: { - main, - peers: values - } - }; - }, - or(schema, dep, value, state, prefs) { - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) !== void 0) { - return; - } - } - return { - code: "object.missing", - context: { - peers: dep.paths - } - }; - }, - oxor(schema, dep, value, state, prefs) { - const present = []; - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) !== void 0) { - present.push(peer.key); - } - } - if (!present.length || present.length === 1) { - return; - } - const context = { peers: dep.paths }; - context.present = present; - return { code: "object.oxor", context }; - }, - with(schema, dep, value, state, prefs) { - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) === void 0) { - return { - code: "object.with", - context: { - main: dep.key.key, - peer: peer.key - } - }; - } - } - }, - without(schema, dep, value, state, prefs) { - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) !== void 0) { - return { - code: "object.without", - context: { - main: dep.key.key, - peer: peer.key - } - }; - } - } - }, - xor(schema, dep, value, state, prefs) { - const present = []; - for (const peer of dep.peers) { - if (peer.resolve(value, state, prefs, null, { shadow: false }) !== void 0) { - present.push(peer.key); - } - } - if (present.length === 1) { - return; - } - const context = { peers: dep.paths }; - if (present.length === 0) { - return { code: "object.missing", context }; + return ESCAPES.get(c) || c; + } + function parseArguments(name, arguments_) { + const results = []; + const chunks = arguments_.trim().split(/\s*,\s*/g); + let matches; + for (const chunk of chunks) { + const number3 = Number(chunk); + if (!Number.isNaN(number3)) { + results.push(number3); + } else if (matches = chunk.match(STRING_REGEX)) { + results.push(matches[2].replace(ESCAPE_REGEX2, (m3, escape, character) => escape ? unescape(escape) : character)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); } - context.present = present; - return { code: "object.xor", context }; } - }; - internals.rename = function(schema, value, state, prefs, errors) { - const renamed = {}; - for (const rename of schema.$_terms.renames) { - const matches = []; - const pattern = typeof rename.from !== "string"; - if (!pattern) { - if (Object.prototype.hasOwnProperty.call(value, rename.from) && (value[rename.from] !== void 0 || !rename.options.ignoreUndefined)) { - matches.push(rename); - } + return results; + } + function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; + const results = []; + let matches; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); } else { - for (const from3 in value) { - if (value[from3] === void 0 && rename.options.ignoreUndefined) { - continue; - } - if (from3 === rename.to) { - continue; - } - const match = rename.from.exec(from3); - if (!match) { - continue; - } - matches.push({ from: from3, to: rename.to, match }); - } - } - for (const match of matches) { - const from3 = match.from; - const to = match.to; - if (!rename.options.multiple && renamed[to]) { - errors.push(schema.$_createError("object.rename.multiple", value, { from: from3, to, pattern }, state, prefs)); - if (prefs.abortEarly) { - return false; - } - } - if (Object.prototype.hasOwnProperty.call(value, to) && !rename.options.override && !renamed[to]) { - errors.push(schema.$_createError("object.rename.override", value, { from: from3, to, pattern }, state, prefs)); - if (prefs.abortEarly) { - return false; - } - } - if (value[from3] === void 0) { - delete value[to]; - } else { - value[to] = value[from3]; - } - renamed[to] = true; - if (!rename.options.alias) { - delete value[from3]; - } + results.push([name]); } } - return true; - }; - internals.unknown = function(schema, value, unprocessed, errors, state, prefs) { - if (schema.$_terms.patterns) { - let hasMatches = false; - const matches = schema.$_terms.patterns.map((pattern) => { - if (pattern.matches) { - hasMatches = true; - return []; - } - }); - const ancestors = [value, ...state.ancestors]; - for (const key of unprocessed) { - const item = value[key]; - const path8 = [...state.path, key]; - for (let i2 = 0; i2 < schema.$_terms.patterns.length; ++i2) { - const pattern = schema.$_terms.patterns[i2]; - if (pattern.regex) { - const match = pattern.regex.test(key); - if (!match) { - continue; - } - } else { - if (!pattern.schema.$_match(key, state.nest(pattern.schema, `pattern.${i2}`), prefs)) { - continue; - } - } - unprocessed.delete(key); - const localState = state.localize(path8, ancestors, { schema: pattern.rule, key }); - const result = pattern.rule.$_validate(item, localState, prefs); - if (result.errors) { - if (prefs.abortEarly) { - return { value, errors: result.errors }; - } - errors.push(...result.errors); - } - if (pattern.matches) { - matches[i2].push(key); - } - value[key] = result.value; - if (!pattern.fallthrough) { - break; - } - } - } - if (hasMatches) { - for (let i2 = 0; i2 < matches.length; ++i2) { - const match = matches[i2]; - if (!match) { - continue; - } - const stpm = schema.$_terms.patterns[i2].matches; - const localState = state.localize(state.path, ancestors, stpm); - const result = stpm.$_validate(match, localState, prefs); - if (result.errors) { - const details = Errors.details(result.errors, { override: false }); - details.matches = match; - const report = schema.$_createError("object.pattern.match", value, details, state, prefs); - if (prefs.abortEarly) { - return { value, errors: report }; - } - errors.push(report); - } - } + return results; + } + function buildStyle(chalk5, styles) { + const enabled2 = {}; + for (const layer of styles) { + for (const style of layer.styles) { + enabled2[style[0]] = layer.inverse ? null : style.slice(1); } } - if (!unprocessed.size || !schema.$_terms.keys && !schema.$_terms.patterns) { - return; - } - if (prefs.stripUnknown && !schema._flags.unknown || prefs.skipFunctions) { - const stripUnknown = prefs.stripUnknown ? prefs.stripUnknown === true ? true : !!prefs.stripUnknown.objects : false; - for (const key of unprocessed) { - if (stripUnknown) { - delete value[key]; - unprocessed.delete(key); - } else if (typeof value[key] === "function") { - unprocessed.delete(key); - } + let current = chalk5; + for (const [styleName, styles2] of Object.entries(enabled2)) { + if (!Array.isArray(styles2)) { + continue; } - } - const forbidUnknown = !Common.default(schema._flags.unknown, prefs.allowUnknown); - if (forbidUnknown) { - for (const unprocessedKey of unprocessed) { - const localState = state.localize([...state.path, unprocessedKey], []); - const report = schema.$_createError("object.unknown", value[unprocessedKey], { child: unprocessedKey }, localState, prefs, { flags: false }); - if (prefs.abortEarly) { - return { value, errors: report }; - } - errors.push(report); + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); } + current = styles2.length > 0 ? current[styleName](...styles2) : current[styleName]; } - }; - internals.Dependency = class { - constructor(rel, key, peers, paths) { - this.rel = rel; - this.key = key; - this.peers = peers; - this.paths = paths; - } - }; - internals.Keys = class extends Array { - concat(source) { - const result = this.slice(); - const keys = /* @__PURE__ */ new Map(); - for (let i2 = 0; i2 < result.length; ++i2) { - keys.set(result[i2].key, i2); - } - for (const item of source) { - const key = item.key; - const pos = keys.get(key); - if (pos !== void 0) { - result[pos] = { key, schema: result[pos].schema.concat(item.schema) }; - } else { - result.push(item); + return current; + } + module14.exports = (chalk5, temporary) => { + const styles = []; + const chunks = []; + let chunk = []; + temporary.replace(TEMPLATE_REGEX, (m3, escapeCharacter, inverse, style, close, character) => { + if (escapeCharacter) { + chunk.push(unescape(escapeCharacter)); + } else if (style) { + const string3 = chunk.join(""); + chunk = []; + chunks.push(styles.length === 0 ? string3 : buildStyle(chalk5, styles)(string3)); + styles.push({ inverse, styles: parseStyle(style) }); + } else if (close) { + if (styles.length === 0) { + throw new Error("Found extraneous } in Chalk template literal"); } + chunks.push(buildStyle(chalk5, styles)(chunk.join(""))); + chunk = []; + styles.pop(); + } else { + chunk.push(character); } - return result; + }); + chunks.push(chunk.join("")); + if (styles.length > 0) { + const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? "" : "s"} (\`}\`)`; + throw new Error(errMessage); } + return chunks.join(""); }; } }); -var require_function = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/function.js"(exports2, module14) { +var require_source = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/index.js"(exports2, module14) { "use strict"; - var Assert = require_assert(); - var Keys = require_keys(); - module14.exports = Keys._extend({ - type: "function", - properties: { - typeof: "function" - }, - rules: { - arity: { - method(n) { - Assert(Number.isSafeInteger(n) && n >= 0, "n must be a positive integer"); - return this.$_addRule({ name: "arity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length === n) { - return value; - } - return helpers.error("function.arity", { n }); - } - }, - class: { - method() { - return this.$_addRule("class"); - }, - validate(value, helpers) { - if (/^\s*class\s/.test(value.toString())) { - return value; - } - return helpers.error("function.class", { value }); - } - }, - minArity: { - method(n) { - Assert(Number.isSafeInteger(n) && n > 0, "n must be a strict positive integer"); - return this.$_addRule({ name: "minArity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length >= n) { - return value; - } - return helpers.error("function.minArity", { n }); - } - }, - maxArity: { - method(n) { - Assert(Number.isSafeInteger(n) && n >= 0, "n must be a positive integer"); - return this.$_addRule({ name: "maxArity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length <= n) { - return value; - } - return helpers.error("function.maxArity", { n }); - } - } - }, - messages: { - "function.arity": "{{#label}} must have an arity of {{#n}}", - "function.class": "{{#label}} must be a class", - "function.maxArity": "{{#label}} must have an arity lesser or equal to {{#n}}", - "function.minArity": "{{#label}} must have an arity greater or equal to {{#n}}" - } - }); - } -}); -var require_link = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/link.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - var Compile = require_compile(); - var Errors = require_errors2(); - var internals = {}; - module14.exports = Any._extend({ - type: "link", - properties: { - schemaChain: true - }, - terms: { - link: { init: null, register: false } - }, - args(schema, ref) { - return schema.ref(ref); - }, - validate(value, { schema, state, prefs }) { - Assert(schema.$_terms.link, "Uninitialized link schema"); - const linked = internals.generate(schema, value, state, prefs); - const ref = schema.$_terms.link[0].ref; - return linked.$_validate(value, state.nest(linked, `link:${ref.display}:${linked.type}`), prefs); - }, - generate(schema, value, state, prefs) { - return internals.generate(schema, value, state, prefs); - }, - rules: { - ref: { - method(ref) { - Assert(!this.$_terms.link, "Cannot reinitialize schema"); - ref = Compile.ref(ref); - Assert(ref.type === "value" || ref.type === "local", "Invalid reference type:", ref.type); - Assert(ref.type === "local" || ref.ancestor === "root" || ref.ancestor > 0, "Link cannot reference itself"); - const obj = this.clone(); - obj.$_terms.link = [{ ref }]; - return obj; - } - }, - relative: { - method(enabled2 = true) { - return this.$_setFlag("relative", enabled2); - } - } - }, - overrides: { - concat(source) { - Assert(this.$_terms.link, "Uninitialized link schema"); - Assert(Common.isSchema(source), "Invalid schema object"); - Assert(source.type !== "link", "Cannot merge type link with another link"); - const obj = this.clone(); - if (!obj.$_terms.whens) { - obj.$_terms.whens = []; - } - obj.$_terms.whens.push({ concat: source }); - return obj.$_mutateRebuild(); - } - } - }); - internals.generate = function(schema, value, state, prefs) { - let linked = state.mainstay.links.get(schema); - if (linked) { - return linked._generate(value, state, prefs).schema; - } - const ref = schema.$_terms.link[0].ref; - const { perspective, path: path8 } = internals.perspective(ref, state); - internals.assert(perspective, "which is outside of schema boundaries", ref, schema, state, prefs); - try { - linked = path8.length ? perspective.$_reach(path8) : perspective; - } catch (ignoreErr) { - internals.assert(false, "to non-existing schema", ref, schema, state, prefs); - } - internals.assert(linked.type !== "link", "which is another link", ref, schema, state, prefs); - if (!schema._flags.relative) { - state.mainstay.links.set(schema, linked); - } - return linked._generate(value, state, prefs).schema; - }; - internals.perspective = function(ref, state) { - if (ref.type === "local") { - for (const { schema, key } of state.schemas) { - const id = schema._flags.id || key; - if (id === ref.path[0]) { - return { perspective: schema, path: ref.path.slice(1) }; - } - if (schema.$_terms.shared) { - for (const shared of schema.$_terms.shared) { - if (shared._flags.id === ref.path[0]) { - return { perspective: shared, path: ref.path.slice(1) }; - } - } - } - } - return { perspective: null, path: null }; - } - if (ref.ancestor === "root") { - return { perspective: state.schemas[state.schemas.length - 1].schema, path: ref.path }; + var ansiStyles = require_ansi_styles(); + var { stdout: stdoutColor, stderr: stderrColor } = require_supports_color(); + var { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex + } = require_util2(); + var { isArray } = Array; + var levelMapping = [ + "ansi", + "ansi", + "ansi256", + "ansi16m" + ]; + var styles = /* @__PURE__ */ Object.create(null); + var applyOptions = (object2, options2 = {}) => { + if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) { + throw new Error("The `level` option should be an integer from 0 to 3"); } - return { perspective: state.schemas[ref.ancestor]?.schema, path: ref.path }; + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object2.level = options2.level === void 0 ? colorLevel : options2.level; }; - internals.assert = function(condition, message, ref, schema, state, prefs) { - if (condition) { - return; + var ChalkClass = class { + constructor(options2) { + return chalkFactory(options2); } - Assert(false, `"${Errors.label(schema._flags, state, prefs)}" contains link reference "${ref.display}" ${message}`); }; - } -}); -var require_number = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/number.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - var internals = { - numberRx: /^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i, - precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/ + var chalkFactory = (options2) => { + const chalk6 = {}; + applyOptions(chalk6, options2); + chalk6.template = (...arguments_) => chalkTag(chalk6.template, ...arguments_); + Object.setPrototypeOf(chalk6, Chalk.prototype); + Object.setPrototypeOf(chalk6.template, chalk6); + chalk6.template.constructor = () => { + throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead."); + }; + chalk6.template.Instance = ChalkClass; + return chalk6.template; }; - module14.exports = Any._extend({ - type: "number", - flags: { - unsafe: { default: false } - }, - coerce: { - from: "string", - method(value, { schema, error: error2 }) { - const matches = value.match(internals.numberRx); - if (!matches) { - return; - } - value = value.trim(); - const result = { value: parseFloat(value) }; - if (result.value === 0) { - result.value = 0; - } - if (!schema._flags.unsafe) { - if (value.match(/e/i)) { - const constructed = internals.normalizeExponent(`${result.value / Math.pow(10, matches[1])}e${matches[1]}`); - if (constructed !== internals.normalizeExponent(value)) { - result.errors = error2("number.unsafe"); - return result; - } - } else { - const string3 = result.value.toString(); - if (string3.match(/e/i)) { - return result; - } - if (string3 !== internals.normalizeDecimal(value)) { - result.errors = error2("number.unsafe"); - return result; - } - } - } - return result; + function Chalk(options2) { + return chalkFactory(options2); + } + for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { + get() { + const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + Object.defineProperty(this, styleName, { value: builder }); + return builder; } - }, - validate(value, { schema, error: error2, prefs }) { - if (value === Infinity || value === -Infinity) { - return { value, errors: error2("number.infinity") }; + }; + } + styles.visible = { + get() { + const builder = createBuilder(this, this._styler, true); + Object.defineProperty(this, "visible", { value: builder }); + return builder; + } + }; + var usedModels = ["rgb", "hex", "keyword", "hsl", "hsv", "hwb", "ansi", "ansi256"]; + for (const model of usedModels) { + styles[model] = { + get() { + const { level } = this; + return function(...arguments_) { + const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; } - if (!Common.isNumber(value)) { - return { value, errors: error2("number.base") }; + }; + } + for (const model of usedModels) { + const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const { level } = this; + return function(...arguments_) { + const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; } - const result = { value }; - if (prefs.convert) { - const rule = schema.$_getRule("precision"); - if (rule) { - const precision = Math.pow(10, rule.args.limit); - result.value = Math.round(result.value * precision) / precision; - } + }; + } + var proto3 = Object.defineProperties(() => { + }, { + ...styles, + level: { + enumerable: true, + get() { + return this._generator.level; + }, + set(level) { + this._generator.level = level; } - if (result.value === 0) { - result.value = 0; - } - if (!schema._flags.unsafe && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER)) { - result.errors = error2("number.unsafe"); - } - return result; - }, - rules: { - compare: { - method: false, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value, limit, operator)) { - return value; - } - return helpers.error("number." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.isNumber, - message: "must be a number" - } - ] - }, - greater: { - method(limit) { - return this.$_addRule({ name: "greater", method: "compare", args: { limit }, operator: ">" }); - } - }, - integer: { - method() { - return this.$_addRule("integer"); - }, - validate(value, helpers) { - if (Math.trunc(value) - value === 0) { - return value; - } - return helpers.error("number.integer"); - } - }, - less: { - method(limit) { - return this.$_addRule({ name: "less", method: "compare", args: { limit }, operator: "<" }); - } - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "compare", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "compare", args: { limit }, operator: ">=" }); - } - }, - multiple: { - method(base2) { - return this.$_addRule({ name: "multiple", args: { base: base2 } }); - }, - validate(value, helpers, { base: base2 }, options2) { - if (value % base2 === 0) { - return value; - } - return helpers.error("number.multiple", { multiple: options2.args.base, value }); - }, - args: [ - { - name: "base", - ref: true, - assert: (value) => typeof value === "number" && isFinite(value) && value > 0, - message: "must be a positive number" - } - ], - multi: true - }, - negative: { - method() { - return this.sign("negative"); - } - }, - port: { - method() { - return this.$_addRule("port"); - }, - validate(value, helpers) { - if (Number.isSafeInteger(value) && value >= 0 && value <= 65535) { - return value; - } - return helpers.error("number.port"); - } - }, - positive: { - method() { - return this.sign("positive"); - } - }, - precision: { - method(limit) { - Assert(Number.isSafeInteger(limit), "limit must be an integer"); - return this.$_addRule({ name: "precision", args: { limit } }); - }, - validate(value, helpers, { limit }) { - const places = value.toString().match(internals.precisionRx); - const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0); - if (decimals <= limit) { - return value; - } - return helpers.error("number.precision", { limit, value }); - }, - convert: true - }, - sign: { - method(sign2) { - Assert(["negative", "positive"].includes(sign2), "Invalid sign", sign2); - return this.$_addRule({ name: "sign", args: { sign: sign2 } }); - }, - validate(value, helpers, { sign: sign2 }) { - if (sign2 === "negative" && value < 0 || sign2 === "positive" && value > 0) { - return value; - } - return helpers.error(`number.${sign2}`); - } - }, - unsafe: { - method(enabled2 = true) { - Assert(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_setFlag("unsafe", enabled2); - } + } + }); + var createStyler = (open2, close, parent) => { + let openAll; + let closeAll; + if (parent === void 0) { + openAll = open2; + closeAll = close; + } else { + openAll = parent.openAll + open2; + closeAll = close + parent.closeAll; + } + return { + open: open2, + close, + openAll, + closeAll, + parent + }; + }; + var createBuilder = (self2, _styler, _isEmpty) => { + const builder = (...arguments_) => { + if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { + return applyStyle(builder, chalkTag(builder, ...arguments_)); } - }, - cast: { - string: { - from: (value) => typeof value === "number", - to(value, helpers) { - return value.toString(); - } + return applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")); + }; + Object.setPrototypeOf(builder, proto3); + builder._generator = self2; + builder._styler = _styler; + builder._isEmpty = _isEmpty; + return builder; + }; + var applyStyle = (self2, string3) => { + if (self2.level <= 0 || !string3) { + return self2._isEmpty ? "" : string3; + } + let styler = self2._styler; + if (styler === void 0) { + return string3; + } + const { openAll, closeAll } = styler; + if (string3.indexOf("\x1B") !== -1) { + while (styler !== void 0) { + string3 = stringReplaceAll(string3, styler.close, styler.open); + styler = styler.parent; } - }, - messages: { - "number.base": "{{#label}} must be a number", - "number.greater": "{{#label}} must be greater than {{#limit}}", - "number.infinity": "{{#label}} cannot be infinity", - "number.integer": "{{#label}} must be an integer", - "number.less": "{{#label}} must be less than {{#limit}}", - "number.max": "{{#label}} must be less than or equal to {{#limit}}", - "number.min": "{{#label}} must be greater than or equal to {{#limit}}", - "number.multiple": "{{#label}} must be a multiple of {{#multiple}}", - "number.negative": "{{#label}} must be a negative number", - "number.port": "{{#label}} must be a valid port", - "number.positive": "{{#label}} must be a positive number", - "number.precision": "{{#label}} must have no more than {{#limit}} decimal places", - "number.unsafe": "{{#label}} must be a safe number" } - }); - internals.normalizeExponent = function(str) { - return str.replace(/E/, "e").replace(/\.(\d*[1-9])?0+e/, ".$1e").replace(/\.e/, "e").replace(/e\+/, "e").replace(/^\+/, "").replace(/^(-?)0+([1-9])/, "$1$2"); + const lfIndex = string3.indexOf("\n"); + if (lfIndex !== -1) { + string3 = stringEncaseCRLFWithFirstIndex(string3, closeAll, openAll, lfIndex); + } + return openAll + string3 + closeAll; }; - internals.normalizeDecimal = function(str) { - str = str.replace(/^\+/, "").replace(/\.0+$/, "").replace(/^(-?)\.([^\.]*)$/, "$10.$2").replace(/^(-?)0+([1-9])/, "$1$2"); - if (str.includes(".") && str.endsWith("0")) { - str = str.replace(/0+$/, ""); + var template; + var chalkTag = (chalk6, ...strings) => { + const [firstString] = strings; + if (!isArray(firstString) || !isArray(firstString.raw)) { + return strings.join(" "); + } + const arguments_ = strings.slice(1); + const parts = [firstString.raw[0]]; + for (let i2 = 1; i2 < firstString.length; i2++) { + parts.push( + String(arguments_[i2 - 1]).replace(/[{}\\]/g, "\\$&"), + String(firstString.raw[i2]) + ); } - if (str === "-0") { - return "0"; + if (template === void 0) { + template = require_templates(); } - return str; + return template(chalk6, parts.join("")); }; + Object.defineProperties(Chalk.prototype, styles); + var chalk5 = Chalk(); + chalk5.supportsColor = stdoutColor; + chalk5.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 }); + chalk5.stderr.supportsColor = stderrColor; + module14.exports = chalk5; } }); -var require_object = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/object.js"(exports2, module14) { +var SERVER_INSTANCE; +var PUBSUB_INSTANCE; +var init_instance_keys = __esm({ + "src/serve/instance-keys.ts"() { "use strict"; - var Keys = require_keys(); - module14.exports = Keys._extend({ - type: "object", - cast: { - map: { - from: (value) => value && typeof value === "object", - to(value, helpers) { - return new Map(Object.entries(value)); - } - } - } - }); + SERVER_INSTANCE = "@instance/server"; + PUBSUB_INSTANCE = "@instance/pubsub"; } }); -var require_string = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/string.js"(exports2, module14) { - "use strict"; - var Url = __require2("url"); - var Assert = require_assert(); - var EscapeRegex = require_escapeRegex(); - var Any = require_any(); - var Common = require_common2(); - var internals = { - base64Regex: { - // paddingRequired - true: { - // urlSafe - true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}==|[\w\-]{3}=)?$/, - false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/ - }, - false: { - true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}(==)?|[\w\-]{3}=?)?$/, - false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/ - } - }, - dataUriRegex: /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/, - hexRegex: /^[a-f0-9]+$/i, - isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/, - guidBrackets: { - "{": "}", - "[": "]", - "(": ")", - "": "" - }, - guidVersions: { - uuidv1: "1", - uuidv2: "2", - uuidv3: "3", - uuidv4: "4", - uuidv5: "5" - }, - guidSeparators: /* @__PURE__ */ new Set([void 0, true, false, "-", ":"]), - normalizationForms: ["NFC", "NFD", "NFKC", "NFKD"], - domainControlRx: /[\x00-\x20@\:\/]/, - // Control + space + separators - domainSegmentRx: /^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/, - finalSegmentAdditionalRx: /[^0-9]/ - // Domain segment which is additionally not all-numeric - }; - module14.exports = Any._extend({ - type: "string", - flags: { - insensitive: { default: false }, - truncate: { default: false } - }, - terms: { - replacements: { init: null } - }, - coerce: { - from: "string", - method(value, { schema, state, prefs }) { - const normalize32 = schema.$_getRule("normalize"); - if (normalize32) { - value = value.normalize(normalize32.args.form); - } - const casing = schema.$_getRule("case"); - if (casing) { - value = casing.args.direction === "upper" ? value.toLocaleUpperCase() : value.toLocaleLowerCase(); - } - const trim = schema.$_getRule("trim"); - if (trim && trim.args.enabled) { - value = value.trim(); - } - if (schema.$_terms.replacements) { - for (const replacement of schema.$_terms.replacements) { - value = value.replace(replacement.pattern, replacement.replacement); - } - } - const hex = schema.$_getRule("hex"); - if (hex && hex.args.options.byteAligned && value.length % 2 !== 0) { - value = `0${value}`; - } - if (schema.$_getRule("isoDate")) { - const iso = internals.isoDate(value); - if (iso) { - value = iso; - } - } - if (schema._flags.truncate) { - const rule = schema.$_getRule("max"); - if (rule) { - let limit = rule.args.limit; - if (Common.isResolvable(limit)) { - limit = limit.resolve(value, state, prefs); - if (!Common.limit(limit)) { - return { value, errors: schema.$_createError("any.ref", limit, { ref: rule.args.limit, arg: "limit", reason: "must be a positive integer" }, state, prefs) }; - } - } - value = value.slice(0, limit); - } - } - return { value }; - } - }, - validate(value, { error: error2 }) { - if (typeof value !== "string") { - return { value, errors: error2("string.base") }; - } - if (value === "") { - return { value, errors: error2("string.empty") }; - } - }, - rules: { - alphanum: { - method() { - return this.$_addRule("alphanum"); - }, - validate(value, helpers) { - if (/^[a-zA-Z0-9]+$/.test(value)) { - return value; - } - return helpers.error("string.alphanum"); - } - }, - base64: { - method(options2 = {}) { - Common.assertOptions(options2, ["paddingRequired", "urlSafe"]); - options2 = { urlSafe: false, paddingRequired: true, ...options2 }; - Assert(typeof options2.paddingRequired === "boolean", "paddingRequired must be boolean"); - Assert(typeof options2.urlSafe === "boolean", "urlSafe must be boolean"); - return this.$_addRule({ name: "base64", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - const regex = internals.base64Regex[options2.paddingRequired][options2.urlSafe]; - if (regex.test(value)) { - return value; - } - return helpers.error("string.base64"); - } - }, - case: { - method(direction) { - Assert(["lower", "upper"].includes(direction), "Invalid case:", direction); - return this.$_addRule({ name: "case", args: { direction } }); - }, - validate(value, helpers, { direction }) { - if (direction === "lower" && value === value.toLocaleLowerCase() || direction === "upper" && value === value.toLocaleUpperCase()) { - return value; - } - return helpers.error(`string.${direction}case`); - }, - convert: true - }, - creditCard: { - method() { - return this.$_addRule("creditCard"); - }, - validate(value, helpers) { - let i2 = value.length; - let sum = 0; - let mul = 1; - while (i2--) { - const char = value.charAt(i2) * mul; - sum = sum + (char - (char > 9) * 9); - mul = mul ^ 3; - } - if (sum > 0 && sum % 10 === 0) { - return value; - } - return helpers.error("string.creditCard"); - } - }, - dataUri: { - method(options2 = {}) { - Common.assertOptions(options2, ["paddingRequired"]); - options2 = { paddingRequired: true, ...options2 }; - Assert(typeof options2.paddingRequired === "boolean", "paddingRequired must be boolean"); - return this.$_addRule({ name: "dataUri", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - const matches = value.match(internals.dataUriRegex); - if (matches) { - if (!matches[2]) { - return value; - } - if (matches[2] !== "base64") { - return value; - } - const base64regex = internals.base64Regex[options2.paddingRequired].false; - if (base64regex.test(matches[3])) { - return value; - } - } - return helpers.error("string.dataUri"); - } - }, - guid: { - alias: "uuid", - method(options2 = {}) { - Common.assertOptions(options2, ["version", "separator"]); - let versionNumbers = ""; - if (options2.version) { - const versions = [].concat(options2.version); - Assert(versions.length >= 1, "version must have at least 1 valid version specified"); - const set = /* @__PURE__ */ new Set(); - for (let i2 = 0; i2 < versions.length; ++i2) { - const version3 = versions[i2]; - Assert(typeof version3 === "string", "version at position " + i2 + " must be a string"); - const versionNumber = internals.guidVersions[version3.toLowerCase()]; - Assert(versionNumber, "version at position " + i2 + " must be one of " + Object.keys(internals.guidVersions).join(", ")); - Assert(!set.has(versionNumber), "version at position " + i2 + " must not be a duplicate"); - versionNumbers += versionNumber; - set.add(versionNumber); - } - } - Assert(internals.guidSeparators.has(options2.separator), 'separator must be one of true, false, "-", or ":"'); - const separator = options2.separator === void 0 ? "[:-]?" : options2.separator === true ? "[:-]" : options2.separator === false ? "[]?" : `\\${options2.separator}`; - const regex = new RegExp(`^([\\[{\\(]?)[0-9A-F]{8}(${separator})[0-9A-F]{4}\\2?[${versionNumbers || "0-9A-F"}][0-9A-F]{3}\\2?[${versionNumbers ? "89AB" : "0-9A-F"}][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$`, "i"); - return this.$_addRule({ name: "guid", args: { options: options2 }, regex }); - }, - validate(value, helpers, args, { regex }) { - const results = regex.exec(value); - if (!results) { - return helpers.error("string.guid"); - } - if (internals.guidBrackets[results[1]] !== results[results.length - 1]) { - return helpers.error("string.guid"); - } - return value; - } - }, - hex: { - method(options2 = {}) { - Common.assertOptions(options2, ["byteAligned"]); - options2 = { byteAligned: false, ...options2 }; - Assert(typeof options2.byteAligned === "boolean", "byteAligned must be boolean"); - return this.$_addRule({ name: "hex", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - if (!internals.hexRegex.test(value)) { - return helpers.error("string.hex"); - } - if (options2.byteAligned && value.length % 2 !== 0) { - return helpers.error("string.hexAlign"); - } - return value; - } - }, - hostname: { - method() { - return this.$_addRule("hostname"); - }, - validate(value, helpers) { - if (internals.isDomainValid(value) || internals.ipRegex.test(value)) { - return value; - } - return helpers.error("string.hostname"); - } - }, - insensitive: { - method() { - return this.$_setFlag("insensitive", true); - } - }, - isoDate: { - method() { - return this.$_addRule("isoDate"); - }, - validate(value, { error: error2 }) { - if (internals.isoDate(value)) { - return value; - } - return error2("string.isoDate"); - } - }, - isoDuration: { - method() { - return this.$_addRule("isoDuration"); - }, - validate(value, helpers) { - if (internals.isoDurationRegex.test(value)) { - return value; - } - return helpers.error("string.isoDuration"); - } - }, - length: { - method(limit, encoding) { - return internals.length(this, "length", limit, "=", encoding); - }, - validate(value, helpers, { limit, encoding }, { name, operator, args }) { - const length2 = encoding ? Buffer.byteLength(value, encoding) : value.length; - if (Common.compare(length2, limit, operator)) { - return value; - } - return helpers.error("string." + name, { limit: args.limit, value, encoding }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - }, - "encoding" - ] - }, - lowercase: { - method() { - return this.case("lower"); - } - }, - max: { - method(limit, encoding) { - return internals.length(this, "max", limit, "<=", encoding); - }, - args: ["limit", "encoding"] - }, - min: { - method(limit, encoding) { - return internals.length(this, "min", limit, ">=", encoding); - }, - args: ["limit", "encoding"] - }, - normalize: { - method(form = "NFC") { - Assert(internals.normalizationForms.includes(form), "normalization form must be one of " + internals.normalizationForms.join(", ")); - return this.$_addRule({ name: "normalize", args: { form } }); - }, - validate(value, { error: error2 }, { form }) { - if (value === value.normalize(form)) { - return value; - } - return error2("string.normalize", { value, form }); - }, - convert: true - }, - pattern: { - alias: "regex", - method(regex, options2 = {}) { - Assert(regex instanceof RegExp, "regex must be a RegExp"); - Assert(!regex.flags.includes("g") && !regex.flags.includes("y"), "regex should not use global or sticky mode"); - if (typeof options2 === "string") { - options2 = { name: options2 }; - } - Common.assertOptions(options2, ["invert", "name"]); - const errorCode = ["string.pattern", options2.invert ? ".invert" : "", options2.name ? ".name" : ".base"].join(""); - return this.$_addRule({ name: "pattern", args: { regex, options: options2 }, errorCode }); - }, - validate(value, helpers, { regex, options: options2 }, { errorCode }) { - const patternMatch = regex.test(value); - if (patternMatch ^ options2.invert) { - return value; - } - return helpers.error(errorCode, { name: options2.name, regex, value }); - }, - args: ["regex", "options"], - multi: true - }, - replace: { - method(pattern, replacement) { - if (typeof pattern === "string") { - pattern = new RegExp(EscapeRegex(pattern), "g"); - } - Assert(pattern instanceof RegExp, "pattern must be a RegExp"); - Assert(typeof replacement === "string", "replacement must be a String"); - const obj = this.clone(); - if (!obj.$_terms.replacements) { - obj.$_terms.replacements = []; - } - obj.$_terms.replacements.push({ pattern, replacement }); - return obj; - } - }, - token: { - method() { - return this.$_addRule("token"); - }, - validate(value, helpers) { - if (/^\w+$/.test(value)) { - return value; - } - return helpers.error("string.token"); - } - }, - trim: { - method(enabled2 = true) { - Assert(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_addRule({ name: "trim", args: { enabled: enabled2 } }); - }, - validate(value, helpers, { enabled: enabled2 }) { - if (!enabled2 || value === value.trim()) { - return value; - } - return helpers.error("string.trim"); - }, - convert: true - }, - truncate: { - method(enabled2 = true) { - Assert(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_setFlag("truncate", enabled2); - } - }, - uppercase: { - method() { - return this.case("upper"); - } - } - }, - messages: { - "string.alphanum": "{{#label}} must only contain alpha-numeric characters", - "string.base": "{{#label}} must be a string", - "string.base64": "{{#label}} must be a valid base64 string", - "string.creditCard": "{{#label}} must be a credit card", - "string.dataUri": "{{#label}} must be a valid dataUri string", - "string.empty": "{{#label}} is not allowed to be empty", - "string.guid": "{{#label}} must be a valid GUID", - "string.hex": "{{#label}} must only contain hexadecimal characters", - "string.hexAlign": "{{#label}} hex decoded representation must be byte aligned", - "string.hostname": "{{#label}} must be a valid hostname", - "string.isoDate": "{{#label}} must be in iso format", - "string.isoDuration": "{{#label}} must be a valid ISO 8601 duration", - "string.length": "{{#label}} length must be {{#limit}} characters long", - "string.lowercase": "{{#label}} must only contain lowercase characters", - "string.max": "{{#label}} length must be less than or equal to {{#limit}} characters long", - "string.min": "{{#label}} length must be at least {{#limit}} characters long", - "string.normalize": "{{#label}} must be unicode normalized in the {{#form}} form", - "string.token": "{{#label}} must only contain alpha-numeric and underscore characters", - "string.pattern.base": "{{#label}} with value {:.} fails to match the required pattern: {{#regex}}", - "string.pattern.name": "{{#label}} with value {:.} fails to match the {{#name}} pattern", - "string.pattern.invert.base": "{{#label}} with value {:.} matches the inverted pattern: {{#regex}}", - "string.pattern.invert.name": "{{#label}} with value {:.} matches the inverted {{#name}} pattern", - "string.trim": "{{#label}} must not have leading or trailing whitespace", - "string.uppercase": "{{#label}} must only contain uppercase characters" - } - }); - internals.isoDate = function(value) { - if (!Common.isIsoDate(value)) { - return null; +var require_err_helpers = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-helpers.js"(exports2, module14) { + "use strict"; + var isErrorLike = (err) => { + return err && typeof err.message === "string"; + }; + var getErrorCause = (err) => { + if (!err) return; + const cause = err.cause; + if (typeof cause === "function") { + const causeResult = err.cause(); + return isErrorLike(causeResult) ? causeResult : void 0; + } else { + return isErrorLike(cause) ? cause : void 0; } - const date3 = new Date(value); - if (isNaN(date3.getTime())) { - return null; + }; + var _stackWithCauses = (err, seen) => { + if (!isErrorLike(err)) return ""; + const stack = err.stack || ""; + if (seen.has(err)) { + return stack + "\ncauses have become circular..."; } - return date3.toISOString(); - }; - internals.length = function(schema, name, limit, operator, encoding) { - Assert(!encoding || Buffer.isEncoding(encoding), "Invalid encoding:", encoding); - return schema.$_addRule({ name, method: "length", args: { limit, encoding }, operator }); - }; - internals.rfc3986 = function() { - const rfc3986 = {}; - const hexDigit = "\\dA-Fa-f"; - const hexDigitOnly = "[" + hexDigit + "]"; - const unreserved = "\\w-\\.~"; - const subDelims = "!\\$&'\\(\\)\\*\\+,;="; - const decOctect = "(?:0{0,2}\\d|0?[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])"; - rfc3986.ipv4 = "(?:" + decOctect + "\\.){3}" + decOctect; - const h16 = hexDigitOnly + "{1,4}"; - const ls32 = "(?:" + h16 + ":" + h16 + "|" + rfc3986.ipv4 + ")"; - const IPv6SixHex = "(?:" + h16 + ":){6}" + ls32; - const IPv6FiveHex = "::(?:" + h16 + ":){5}" + ls32; - const IPv6FourHex = "(?:" + h16 + ")?::(?:" + h16 + ":){4}" + ls32; - const IPv6ThreeHex = "(?:(?:" + h16 + ":){0,1}" + h16 + ")?::(?:" + h16 + ":){3}" + ls32; - const IPv6TwoHex = "(?:(?:" + h16 + ":){0,2}" + h16 + ")?::(?:" + h16 + ":){2}" + ls32; - const IPv6OneHex = "(?:(?:" + h16 + ":){0,3}" + h16 + ")?::" + h16 + ":" + ls32; - const IPv6NoneHex = "(?:(?:" + h16 + ":){0,4}" + h16 + ")?::" + ls32; - const IPv6NoneHex2 = "(?:(?:" + h16 + ":){0,5}" + h16 + ")?::" + h16; - const IPv6NoneHex3 = "(?:(?:" + h16 + ":){0,6}" + h16 + ")?::"; - rfc3986.v4Cidr = "(?:\\d|[1-2]\\d|3[0-2])"; - rfc3986.v6Cidr = "(?:0{0,2}\\d|0?[1-9]\\d|1[01]\\d|12[0-8])"; - rfc3986.ipv6 = "(?:" + IPv6SixHex + "|" + IPv6FiveHex + "|" + IPv6FourHex + "|" + IPv6ThreeHex + "|" + IPv6TwoHex + "|" + IPv6OneHex + "|" + IPv6NoneHex + "|" + IPv6NoneHex2 + "|" + IPv6NoneHex3 + ")"; - rfc3986.ipvfuture = "v" + hexDigitOnly + "+\\.[" + unreserved + subDelims + ":]+"; - return rfc3986; - }; - internals.ipRegex = function() { - const versions = ["ipv4", "ipv6", "ipvfuture"]; - const rfc3986 = internals.rfc3986(); - const parts = versions.map((version3) => { - const cidrpart = `\\/${version3 === "ipv4" ? rfc3986.v4Cidr : rfc3986.v6Cidr}`; - return `${rfc3986[version3]}(?:${cidrpart})?`; - }); - const raw = `(?:${parts.join("|")})`; - return new RegExp(`^${raw}$`); - }(); - internals.isDomainValid = function(domain) { - if (domain.length > 256) { - return false; + const cause = getErrorCause(err); + if (cause) { + seen.add(err); + return stack + "\ncaused by: " + _stackWithCauses(cause, seen); + } else { + return stack; } - domain = domain.normalize("NFC"); - if (internals.domainControlRx.test(domain)) { - return false; + }; + var stackWithCauses = (err) => _stackWithCauses(err, /* @__PURE__ */ new Set()); + var _messageWithCauses = (err, seen, skip) => { + if (!isErrorLike(err)) return ""; + const message = skip ? "" : err.message || ""; + if (seen.has(err)) { + return message + ": ..."; } - domain = internals.punycode(domain); - const segments = domain.split("."); - for (let i2 = 0; i2 < segments.length; ++i2) { - const segment = segments[i2]; - if (!segment.length) { - return false; - } - if (segment.length > 63) { - return false; - } - if (!internals.domainSegmentRx.test(segment)) { - return false; - } - const isFinalSegment = i2 === segments.length - 1; - if (isFinalSegment && !internals.finalSegmentAdditionalRx.test(segment)) { - return false; - } + const cause = getErrorCause(err); + if (cause) { + seen.add(err); + const skipIfVErrorStyleCause = typeof err.cause === "function"; + return message + (skipIfVErrorStyleCause ? "" : ": ") + _messageWithCauses(cause, seen, skipIfVErrorStyleCause); + } else { + return message; } - return true; }; - internals.punycode = function(domain) { - try { - return new Url.URL(`http://${domain}`).host; - } catch (err) { - return domain; - } + var messageWithCauses = (err) => _messageWithCauses(err, /* @__PURE__ */ new Set()); + module14.exports = { + isErrorLike, + getErrorCause, + stackWithCauses, + messageWithCauses }; } }); -var require_symbol = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/symbol.js"(exports2, module14) { +var require_err_proto = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-proto.js"(exports2, module14) { "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var internals = {}; - internals.Map = class extends Map { - slice() { - return new internals.Map(this); - } - }; - module14.exports = Any._extend({ - type: "symbol", - terms: { - map: { init: new internals.Map() } - }, - coerce: { - method(value, { schema, error: error2 }) { - const lookup = schema.$_terms.map.get(value); - if (lookup) { - value = lookup; - } - if (!schema._flags.only || typeof value === "symbol") { - return { value }; - } - return { value, errors: error2("symbol.map", { map: schema.$_terms.map }) }; - } - }, - validate(value, { error: error2 }) { - if (typeof value !== "symbol") { - return { value, errors: error2("symbol.base") }; - } + var seen = Symbol("circular-ref-tag"); + var rawSymbol = Symbol("pino-raw-err-ref"); + var pinoErrProto = Object.create({}, { + type: { + enumerable: true, + writable: true, + value: void 0 }, - rules: { - map: { - method(iterable) { - if (iterable && !iterable[Symbol.iterator] && typeof iterable === "object") { - iterable = Object.entries(iterable); - } - Assert(iterable && iterable[Symbol.iterator], "Iterable must be an iterable or object"); - const obj = this.clone(); - const symbols2 = []; - for (const entry of iterable) { - Assert(entry && entry[Symbol.iterator], "Entry must be an iterable"); - const [key, value] = entry; - Assert(typeof key !== "object" && typeof key !== "function" && typeof key !== "symbol", "Key must not be of type object, function, or Symbol"); - Assert(typeof value === "symbol", "Value must be a Symbol"); - obj.$_terms.map.set(key, value); - symbols2.push(value); - } - return obj.valid(...symbols2); - } - } + message: { + enumerable: true, + writable: true, + value: void 0 }, - messages: { - "symbol.base": "{{#label}} must be a symbol", - "symbol.map": "{{#label}} must be one of {{#map}}" - } - }); - } -}); -var require_binary = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/types/binary.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Any = require_any(); - var Common = require_common2(); - module14.exports = Any._extend({ - type: "binary", - coerce: { - from: "string", - method(value, { schema }) { - try { - return { value: Buffer.from(value, schema._flags.encoding) }; - } catch (ignoreErr) { - } - } + stack: { + enumerable: true, + writable: true, + value: void 0 }, - validate(value, { error: error2 }) { - if (!Buffer.isBuffer(value)) { - return { value, errors: error2("binary.base") }; - } + aggregateErrors: { + enumerable: true, + writable: true, + value: void 0 }, - rules: { - encoding: { - method(encoding) { - Assert(Buffer.isEncoding(encoding), "Invalid encoding:", encoding); - return this.$_setFlag("encoding", encoding); - } - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", method: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value.length, limit, operator)) { - return value; - } - return helpers.error("binary." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } - } - }, - cast: { - string: { - from: (value) => Buffer.isBuffer(value), - to(value, helpers) { - return value.toString(); - } + set: function(val) { + this[rawSymbol] = val; } - }, - messages: { - "binary.base": "{{#label}} must be a buffer or a string", - "binary.length": "{{#label}} must be {{#limit}} bytes", - "binary.max": "{{#label}} must be less than or equal to {{#limit}} bytes", - "binary.min": "{{#label}} must be at least {{#limit}} bytes" } }); - } -}); -var require_lib9 = __commonJS({ - "node_modules/.deno/@hapi+validate@2.0.1/node_modules/@hapi/validate/lib/index.js"(exports2, module14) { - "use strict"; - var Assert = require_assert(); - var Clone = require_clone(); - var Common = require_common2(); - var Compile = require_compile(); - var Errors = require_errors2(); - var Ref = require_ref(); - var internals = { - types: { - alternatives: require_alternatives(), - any: require_any(), - array: require_array(), - boolean: require_boolean(), - date: require_date(), - function: require_function(), - link: require_link(), - number: require_number(), - object: require_object(), - string: require_string(), - symbol: require_symbol() - }, - aliases: { - alt: "alternatives", - bool: "boolean", - func: "function" - } - }; - if (Buffer) { - internals.types.binary = require_binary(); - } - internals.root = function() { - const root = { - _types: new Set(Object.keys(internals.types)) - }; - for (const type of root._types) { - root[type] = function(...args) { - Assert(!args.length || ["alternatives", "link", "object"].includes(type), "The", type, "type does not allow arguments"); - return internals.generate(this, internals.types[type], args); - }; - } - for (const method of ["allow", "custom", "disallow", "equal", "exist", "forbidden", "invalid", "not", "only", "optional", "options", "prefs", "preferences", "required", "strip", "valid", "when"]) { - root[method] = function(...args) { - return this.any()[method](...args); - }; - } - Object.assign(root, internals.methods); - for (const alias in internals.aliases) { - const target = internals.aliases[alias]; - root[alias] = root[target]; - } - return root; - }; - internals.methods = { - ValidationError: Errors.ValidationError, - version: Common.version, - assert(value, schema, ...args) { - internals.assert(value, schema, true, args); - }, - attempt(value, schema, ...args) { - return internals.assert(value, schema, false, args); - }, - checkPreferences(prefs) { - Common.checkPreferences(prefs); - }, - compile(schema, options2) { - return Compile.compile(this, schema, options2); - }, - isError: Errors.ValidationError.isError, - isRef: Ref.isRef, - isSchema: Common.isSchema, - in(...args) { - return Ref.in(...args); - }, - override: Common.symbols.override, - ref(...args) { - return Ref.create(...args); - } - }; - internals.assert = function(value, schema, annotate, args) { - const message = args[0] instanceof Error || typeof args[0] === "string" ? args[0] : null; - const options2 = message ? args[1] : args[0]; - const result = schema.validate(value, Common.preferences({ errors: { stack: true } }, options2 || {})); - let error2 = result.error; - if (!error2) { - return result.value; - } - if (message instanceof Error) { - throw message; - } - const display = annotate && typeof error2.annotate === "function" ? error2.annotate() : error2.message; - if (error2 instanceof Errors.ValidationError === false) { - error2 = Clone(error2); - } - error2.message = message ? `${message} ${display}` : display; - throw error2; - }; - internals.generate = function(root, schema, args) { - Assert(root, "Must be invoked on a Joi instance."); - schema.$_root = root; - if (!schema._definition.args || !args.length) { - return schema; + Object.defineProperty(pinoErrProto, rawSymbol, { + writable: true, + value: {} + }); + module14.exports = { + pinoErrProto, + pinoErrorSymbols: { + seen, + rawSymbol } - return schema._definition.args(schema, ...args); }; - module14.exports = internals.root(); - } -}); -var require_symbols = __commonJS({ - "node_modules/.deno/@hapi+shot@6.0.2/node_modules/@hapi/shot/lib/symbols.js"(exports2) { - "use strict"; - exports2.injection = Symbol("injection"); } }); -var require_request = __commonJS({ - "node_modules/.deno/@hapi+shot@6.0.2/node_modules/@hapi/shot/lib/request.js"(exports2, module14) { +var require_err = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err.js"(exports2, module14) { "use strict"; - var Events2 = __require2("events"); - var Stream = __require2("stream"); - var Url = __require2("url"); - var Symbols = require_symbols(); - var internals = {}; - exports2 = module14.exports = internals.Request = class extends Stream.Readable { - constructor(options2) { - super({ - emitClose: !!options2.simulate?.close, - autoDestroy: true - // This is the default in node 14+ - }); - let url2 = options2.url; - if (typeof url2 === "object") { - url2 = Url.format(url2); - } - const uri = Url.parse(url2); - this.url = uri.path; - this.httpVersion = "1.1"; - this.method = options2.method ? options2.method.toUpperCase() : "GET"; - this.headers = {}; - const headers = options2.headers ?? {}; - const fields = Object.keys(headers); - fields.forEach((field) => { - this.headers[field.toLowerCase()] = headers[field]; - }); - this.headers["user-agent"] = this.headers["user-agent"] ?? "shot"; - const hostHeaderFromUri = function() { - if (uri.port) { - return uri.host; - } - if (uri.protocol) { - return uri.hostname + (uri.protocol === "https:" ? ":443" : ":80"); - } - return null; - }; - this.headers.host = this.headers.host ?? hostHeaderFromUri() ?? options2.authority ?? "localhost:80"; - this.socket = this.connection = new internals.MockSocket(options2); - let payload = options2.payload ?? null; - if (payload && typeof payload !== "string" && !(payload instanceof Stream) && !Buffer.isBuffer(payload)) { - payload = JSON.stringify(payload); - this.headers["content-type"] = this.headers["content-type"] || "application/json"; - } - if (payload && !(payload instanceof Stream) && !this.headers.hasOwnProperty("content-length")) { - this.headers["content-length"] = (Buffer.isBuffer(payload) ? payload.length : Buffer.byteLength(payload)).toString(); - } - this._shot = { - payload, - isDone: false, - simulate: options2.simulate ?? {} - }; - return this; + module14.exports = errSerializer; + var { messageWithCauses, stackWithCauses, isErrorLike } = require_err_helpers(); + var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); + var { seen } = pinoErrorSymbols; + var { toString } = Object.prototype; + function errSerializer(err) { + if (!isErrorLike(err)) { + return err; } - prepare(next) { - if (this._shot.payload instanceof Stream === false) { - return next(); - } - const chunks = []; - this._shot.payload.on("data", (chunk) => chunks.push(Buffer.from(chunk))); - this._shot.payload.on("end", () => { - const payload = Buffer.concat(chunks); - this.headers["content-length"] = this.headers["content-length"] || payload.length; - this._shot.payload = payload; - return next(); - }); + err[seen] = void 0; + const _err = Object.create(pinoErrProto); + _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; + _err.message = messageWithCauses(err); + _err.stack = stackWithCauses(err); + if (Array.isArray(err.errors)) { + _err.aggregateErrors = err.errors.map((err2) => errSerializer(err2)); } - _read(size) { - setImmediate(() => { - if (this._shot.isDone) { - if (this._shot.simulate.end !== false) { - this.push(null); - } - return; - } - this._shot.isDone = true; - if (this._shot.payload) { - if (this._shot.simulate.split) { - this.push(this._shot.payload.slice(0, 1)); - this.push(this._shot.payload.slice(1)); - } else { - this.push(this._shot.payload); + for (const key in err) { + if (_err[key] === void 0) { + const val = err[key]; + if (isErrorLike(val)) { + if (key !== "cause" && !Object.prototype.hasOwnProperty.call(val, seen)) { + _err[key] = errSerializer(val); } + } else { + _err[key] = val; } - if (this._shot.simulate.error) { - this.destroy(new Error("Simulated")); - } else if (this._shot.simulate.end !== false) { - this.push(null); - } else if (this._shot.simulate.close) { - this.emit("close"); - } - }); - } - }; - internals.Request.prototype[Symbols.injection] = true; - internals.MockSocket = class MockSocket extends Events2.EventEmitter { - constructor({ remoteAddress }) { - super(); - this.remoteAddress = remoteAddress ?? "127.0.0.1"; - } - // Net.Socket APIs used by hapi - end() { - } - setTimeout() { + } } - }; + delete err[seen]; + _err.raw = err; + return _err; + } } }); -var require_response = __commonJS({ - "node_modules/.deno/@hapi+shot@6.0.2/node_modules/@hapi/shot/lib/response.js"(exports2, module14) { +var require_err_with_cause = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-with-cause.js"(exports2, module14) { "use strict"; - var Http = __require2("http"); - var Stream = __require2("stream"); - var Hoek = require_lib(); - var Symbols = require_symbols(); - var internals = {}; - exports2 = module14.exports = internals.Response = class extends Http.ServerResponse { - constructor(req, onEnd) { - super({ method: req.method, httpVersionMajor: 1, httpVersionMinor: 1 }); - this._shot = { headers: null, trailers: {}, payloadChunks: [] }; - this.assignSocket(internals.nullSocket()); - this.socket.on("error", Hoek.ignore); - if (req._shot.simulate.close) { - req.once("close", () => { - process.nextTick(() => this.destroy()); - }); - } - const finalize = (aborted2) => { - const res = internals.payload(this); - res.raw.req = req; - if (aborted2) { - res.aborted = aborted2; - if (!this.headersSent) { - res.statusCode = 499; - } - } - this.removeListener("close", abort); - process.nextTick(() => onEnd(res)); - }; - const abort = () => finalize(true); - this.once("finish", finalize); - this.on("close", abort); - } - writeHead(...args) { - const headers = args[args.length - 1]; - if (typeof headers === "object" && headers !== null) { - const headerNames = Object.keys(headers); - for (let i2 = 0; i2 < headerNames.length; ++i2) { - const name = headerNames[i2]; - try { - this.setHeader(name, headers[name]); - break; - } catch (ignoreErr) { - } - } - } - const result = super.writeHead(...args); - this._shot.headers = this.getHeaders(); - ["Date", "Connection", "Transfer-Encoding"].forEach((name) => { - const regex = new RegExp("\\r\\n" + name + ": ([^\\r]*)\\r\\n"); - const field = this._header.match(regex); - if (field) { - this._shot.headers[name.toLowerCase()] = field[1]; - } - }); - return result; + module14.exports = errWithCauseSerializer; + var { isErrorLike } = require_err_helpers(); + var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); + var { seen } = pinoErrorSymbols; + var { toString } = Object.prototype; + function errWithCauseSerializer(err) { + if (!isErrorLike(err)) { + return err; } - write(data, encoding, callback) { - super.write(data, encoding, callback); - this._shot.payloadChunks.push(Buffer.from(data, encoding)); - return true; + err[seen] = void 0; + const _err = Object.create(pinoErrProto); + _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; + _err.message = err.message; + _err.stack = err.stack; + if (Array.isArray(err.errors)) { + _err.aggregateErrors = err.errors.map((err2) => errWithCauseSerializer(err2)); } - end(data, encoding, callback) { - if (data) { - this.write(data, encoding); - } - super.end(callback); - this.emit("finish"); + if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) { + _err.cause = errWithCauseSerializer(err.cause); } - addTrailers(trailers) { - for (const key in trailers) { - this._shot.trailers[key.toLowerCase().trim()] = trailers[key].toString().trim(); + for (const key in err) { + if (_err[key] === void 0) { + const val = err[key]; + if (isErrorLike(val)) { + if (!Object.prototype.hasOwnProperty.call(val, seen)) { + _err[key] = errWithCauseSerializer(val); + } + } else { + _err[key] = val; + } } } - }; - internals.Response.prototype[Symbols.injection] = true; - internals.payload = function(response) { - const res = { - raw: { - res: response - }, - headers: response._shot.headers, - statusCode: response.statusCode, - statusMessage: response.statusMessage, - trailers: {} - }; - const rawBuffer = Buffer.concat(response._shot.payloadChunks); - res.rawPayload = rawBuffer; - res.payload = rawBuffer.toString(); - res.trailers = response._shot.trailers; - return res; - }; - internals.nullSocket = function() { - return new Stream.Writable({ - write(chunk, encoding, callback) { - setImmediate(callback); - } - }); - }; - } -}); -var require_lib10 = __commonJS({ - "node_modules/.deno/@hapi+shot@6.0.2/node_modules/@hapi/shot/lib/index.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var Validate = require_lib9(); - var Request2 = require_request(); - var Response2 = require_response(); - var Symbols = require_symbols(); - var internals = {}; - internals.options = Validate.object().keys({ - url: Validate.alternatives([ - Validate.string(), - Validate.object().keys({ - protocol: Validate.string(), - hostname: Validate.string(), - port: Validate.any(), - pathname: Validate.string().required(), - query: Validate.any() - }) - ]).required(), - headers: Validate.object(), - payload: Validate.any(), - simulate: { - end: Validate.boolean(), - split: Validate.boolean(), - error: Validate.boolean(), - close: Validate.boolean() - }, - authority: Validate.string(), - remoteAddress: Validate.string(), - method: Validate.string(), - validate: Validate.boolean() - }); - exports2.inject = async function(dispatchFunc, options2) { - options2 = typeof options2 === "string" ? { url: options2 } : options2; - if (options2?.validate !== false) { - Hoek.assert(typeof dispatchFunc === "function", "Invalid or missing dispatch function"); - Validate.assert(options2 ?? null, internals.options, "Invalid options:"); - } - return new Promise((resolve82) => { - const req = new Request2(options2); - const res = new Response2(req, resolve82); - req.prepare(() => dispatchFunc(req, res)); - }); - }; - exports2.isInjection = function(obj) { - return !!obj[Symbols.injection]; - }; + delete err[seen]; + _err.raw = err; + return _err; + } } }); -var require_lib11 = __commonJS({ - "node_modules/.deno/@hapi+teamwork@6.0.1/node_modules/@hapi/teamwork/lib/index.js"(exports2) { +var require_req = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/req.js"(exports2, module14) { "use strict"; - var internals = {}; - exports2.Team = class { - #meetings = null; - #count = null; - #notes = null; - #done = false; - #strict = false; - constructor(options2) { - this._init(options2); - } - static _notes(instance) { - return instance.#notes; - } - _init(options2 = {}) { - this.work = new Promise((resolve82, reject) => { - this._resolve = resolve82; - this._reject = reject; - }); - const meetings = options2.meetings ?? 1; - const strict = !!options2.strict; - if (!Number.isInteger(meetings) || meetings <= 0) { - if (meetings === 0 && !strict) { - return this._finalize(null, null); - } - throw new Error("Invalid meetings value"); - } - this.#meetings = meetings; - this.#count = meetings; - this.#notes = []; - this.#done = false; - this.#strict = strict; - } - _finalize(err, note) { - this.#done = true; - this.#notes = null; - if (err) { - this._reject(err); - } else { - this._resolve(note); - } - } - attend(note) { - if (this.#done) { - if (this.#strict) { - throw new Error("Unscheduled meeting"); - } - return; - } - if (note instanceof Error) { - return this._finalize(note); - } - this.#notes.push(note); - if (--this.#count) { - return; - } - this._finalize(null, this.#meetings === 1 ? this.#notes[0] : this.#notes); - } - async regroup(options2) { - try { - await this.work; - } catch { - } - this._init(options2); - } - }; - exports2.Events = class { - #iterators = /* @__PURE__ */ new Set(); - static _iterators(instance) { - return instance.#iterators; - } - static isIterator(iterator) { - return iterator instanceof internals.EventsIterator; - } - iterator() { - const iterator = new internals.EventsIterator(this); - this.#iterators.add(iterator); - return iterator; - } - emit(value) { - for (const iterator of this.#iterators) { - iterator._queue({ value, done: false }); - } - } - end() { - for (const iterator of this.#iterators) { - iterator._queue({ done: true }); - } - } - _remove(iterator) { - this.#iterators.delete(iterator); - } + module14.exports = { + mapHttpRequest, + reqSerializer }; - internals.EventsIterator = class { - #events; - #pending = null; - #queue = []; - constructor(events) { - this.#events = events; - } - [Symbol.asyncIterator]() { - return this; - } - next() { - if (this.#queue.length) { - return Promise.resolve(this.#queue.shift()); - } - if (!this.#events) { - return { done: true }; + var rawSymbol = Symbol("pino-raw-req-ref"); + var pinoReqProto = Object.create({}, { + id: { + enumerable: true, + writable: true, + value: "" + }, + method: { + enumerable: true, + writable: true, + value: "" + }, + url: { + enumerable: true, + writable: true, + value: "" + }, + query: { + enumerable: true, + writable: true, + value: "" + }, + params: { + enumerable: true, + writable: true, + value: "" + }, + headers: { + enumerable: true, + writable: true, + value: {} + }, + remoteAddress: { + enumerable: true, + writable: true, + value: "" + }, + remotePort: { + enumerable: true, + writable: true, + value: "" + }, + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; + }, + set: function(val) { + this[rawSymbol] = val; } - this.#pending = new exports2.Team(); - return this.#pending.work; } - return() { - this._cleanup(); - return { done: true }; + }); + Object.defineProperty(pinoReqProto, rawSymbol, { + writable: true, + value: {} + }); + function reqSerializer(req) { + const connection = req.info || req.socket; + const _req = Object.create(pinoReqProto); + _req.id = typeof req.id === "function" ? req.id() : req.id || (req.info ? req.info.id : void 0); + _req.method = req.method; + if (req.originalUrl) { + _req.url = req.originalUrl; + } else { + const path8 = req.path; + _req.url = typeof path8 === "string" ? path8 : req.url ? req.url.path || req.url : void 0; } - _cleanup() { - this.#events?._remove(this); - this.#events = null; + if (req.query) { + _req.query = req.query; } - _queue(item) { - if (item.done) { - this._cleanup(); - } - if (this.#pending) { - this.#pending.attend(item); - this.#pending = null; - } else { - this.#queue.push(item); - } + if (req.params) { + _req.params = req.params; } - }; + _req.headers = req.headers; + _req.remoteAddress = connection && connection.remoteAddress; + _req.remotePort = connection && connection.remotePort; + _req.raw = req.raw || req; + return _req; + } + function mapHttpRequest(req) { + return { + req: reqSerializer(req) + }; + } } }); -var require_lib12 = __commonJS({ - "node_modules/.deno/@hapi+bounce@3.0.2/node_modules/@hapi/bounce/lib/index.js"(exports2) { +var require_res = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/res.js"(exports2, module14) { "use strict"; - var Assert = __require2("assert"); - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var internals = { - system: [ - // JavaScript - EvalError, - RangeError, - ReferenceError, - SyntaxError, - TypeError, - URIError, - // Node - Assert.AssertionError, - // Hoek - Hoek.AssertError - ] - }; - exports2.rethrow = function(err, types, options2 = {}) { - return internals.catch(err, types, options2, true); - }; - exports2.ignore = function(err, types, options2 = {}) { - return internals.catch(err, types, options2, false); - }; - internals.catch = function(err, types, options2, match) { - if (internals.match(err, types) !== match) { - return; - } - if (options2.override) { - err = options2.override; - } - if (options2.decorate) { - Object.assign(err, options2.decorate); - } - if (options2.return) { - return err; - } - throw err; + module14.exports = { + mapHttpResponse, + resSerializer }; - exports2.background = async function(operation, action = "rethrow", types = "system", options2 = {}) { - try { - if (typeof operation === "function") { - await operation(); - } else { - await operation; + var rawSymbol = Symbol("pino-raw-res-ref"); + var pinoResProto = Object.create({}, { + statusCode: { + enumerable: true, + writable: true, + value: 0 + }, + headers: { + enumerable: true, + writable: true, + value: "" + }, + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; + }, + set: function(val) { + this[rawSymbol] = val; } - } catch (err) { - return exports2[action](err, types, options2); } - }; - exports2.isBoom = function(err) { - return Boom5.isBoom(err); - }; - exports2.isError = function(err) { - return err instanceof Error; - }; - exports2.isSystem = function(err) { - if (!err) { - return false; + }); + Object.defineProperty(pinoResProto, rawSymbol, { + writable: true, + value: {} + }); + function resSerializer(res) { + const _res = Object.create(pinoResProto); + _res.statusCode = res.headersSent ? res.statusCode : null; + _res.headers = res.getHeaders ? res.getHeaders() : res._headers; + _res.raw = res; + return _res; + } + function mapHttpResponse(res) { + return { + res: resSerializer(res) + }; + } + } +}); +var require_pino_std_serializers = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/index.js"(exports2, module14) { + "use strict"; + var errSerializer = require_err(); + var errWithCauseSerializer = require_err_with_cause(); + var reqSerializers = require_req(); + var resSerializers = require_res(); + module14.exports = { + err: errSerializer, + errWithCause: errWithCauseSerializer, + mapHttpRequest: reqSerializers.mapHttpRequest, + mapHttpResponse: resSerializers.mapHttpResponse, + req: reqSerializers.reqSerializer, + res: resSerializers.resSerializer, + wrapErrorSerializer: function wrapErrorSerializer(customSerializer) { + if (customSerializer === errSerializer) return customSerializer; + return function wrapErrSerializer(err) { + return customSerializer(errSerializer(err)); + }; + }, + wrapRequestSerializer: function wrapRequestSerializer(customSerializer) { + if (customSerializer === reqSerializers.reqSerializer) return customSerializer; + return function wrappedReqSerializer(req) { + return customSerializer(reqSerializers.reqSerializer(req)); + }; + }, + wrapResponseSerializer: function wrapResponseSerializer(customSerializer) { + if (customSerializer === resSerializers.resSerializer) return customSerializer; + return function wrappedResSerializer(res) { + return customSerializer(resSerializers.resSerializer(res)); + }; } - if (err.isBoom) { - return false; + }; + } +}); +var require_caller = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/caller.js"(exports2, module14) { + "use strict"; + function noOpPrepareStackTrace(_, stack) { + return stack; + } + module14.exports = function getCallers() { + const originalPrepare = Error.prepareStackTrace; + Error.prepareStackTrace = noOpPrepareStackTrace; + const stack = new Error().stack; + Error.prepareStackTrace = originalPrepare; + if (!Array.isArray(stack)) { + return void 0; } - for (const system of internals.system) { - if (err instanceof system) { - return true; + const entries = stack.slice(2); + const fileNames = []; + for (const entry of entries) { + if (!entry) { + continue; } + fileNames.push(entry.getFileName()); } - return false; - }; - internals.rules = { - system: exports2.isSystem, - boom: exports2.isBoom + return fileNames; }; - internals.match = function(err, types) { - if (!types) { - return true; - } - types = Array.isArray(types) ? types : [types]; - for (const type of types) { - if (typeof type === "string") { - if (internals.rules[type](err)) { - return true; + } +}); +var require_validator = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/validator.js"(exports2, module14) { + "use strict"; + module14.exports = validator; + function validator(opts = {}) { + const { + ERR_PATHS_MUST_BE_STRINGS = () => "fast-redact - Paths must be (non-empty) strings", + ERR_INVALID_PATH = (s) => `fast-redact \u2013 Invalid path (${s})` + } = opts; + return function validate({ paths }) { + paths.forEach((s) => { + if (typeof s !== "string") { + throw Error(ERR_PATHS_MUST_BE_STRINGS()); } - } else if (typeof type === "object") { - if (Hoek.contain(err, type, { deep: true, part: true })) { - return true; + try { + if (/〇/.test(s)) throw Error(); + const expr = (s[0] === "[" ? "" : ".") + s.replace(/^\*/, "\u3007").replace(/\.\*/g, ".\u3007").replace(/\[\*\]/g, "[\u3007]"); + if (/\n|\r|;/.test(expr)) throw Error(); + if (/\/\*/.test(expr)) throw Error(); + Function(` + 'use strict' + const o = new Proxy({}, { get: () => o, set: () => { throw Error() } }); + const \u3007 = null; + o${expr} + if ([o${expr}].length !== 1) throw Error()`)(); + } catch (e2) { + throw Error(ERR_INVALID_PATH(s)); } - } else if (err instanceof type) { - return true; - } - } - return false; - }; + }); + }; + } } }); -var require_lib13 = __commonJS({ - "node_modules/.deno/@hapi+somever@4.1.1/node_modules/@hapi/somever/lib/index.js"(exports2) { +var require_rx = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/rx.js"(exports2, module14) { "use strict"; - var Bounce = require_lib12(); - var Hoek = require_lib(); - var internals = { - maxLength: 256, - wildcards: ["x", "X", "*"], - any: Symbol("any") - }; - internals.versionRx = /^\s*[vV]?(\d+|[xX*])(?:\.(\d+|[xX*])(?:\.(\d+|[xX*])(?:\-?([^+]+))?(?:\+(.+))?)?)?\s*$/; - internals.strict = { - tokenRx: /^[-\dA-Za-z]+(?:\.[-\dA-Za-z]+)*$/, - numberRx: /^((?:0)|(?:[1-9]\d*))$/ - }; - exports2.version = function(version3, options2) { - return new internals.Version(version3, options2); - }; - exports2.range = function(range) { - return new internals.Range(range); - }; - exports2.match = function(version3, range, options2) { - try { - return exports2.range(range).match(version3, options2); - } catch (err) { - Bounce.rethrow(err, "system"); - return false; - } - }; - exports2.compare = function(a, b, options2 = {}) { - let aFirst = -1; - let bFirst = 1; - a = exports2.version(a, options2); - b = exports2.version(b, options2); - if (options2.range && !options2.includePrerelease && a.prerelease.length && (a.major !== b.major || a.minor !== b.minor || a.patch !== b.patch || !b.prerelease.length)) { - aFirst = -2; - bFirst = 2; - } - for (let i2 = 0; i2 < 3; ++i2) { - const av = a.dots[i2]; - const bv = b.dots[i2]; - if (av === bv || av === internals.any || // Wildcard is equal to everything - bv === internals.any) { - continue; + module14.exports = /[^.[\]]+|\[((?:.)*?)\]/g; + } +}); +var require_parse = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/parse.js"(exports2, module14) { + "use strict"; + var rx = require_rx(); + module14.exports = parse52; + function parse52({ paths }) { + const wildcards = []; + var wcLen = 0; + const secret = paths.reduce(function(o2, strPath, ix) { + var path8 = strPath.match(rx).map((p) => p.replace(/'|"|`/g, "")); + const leadingBracket = strPath[0] === "["; + path8 = path8.map((p) => { + if (p[0] === "[") return p.substr(1, p.length - 2); + else return p; + }); + const star = path8.indexOf("*"); + if (star > -1) { + const before = path8.slice(0, star); + const beforeStr = before.join("."); + const after = path8.slice(star + 1, path8.length); + const nested = after.length > 0; + wcLen++; + wildcards.push({ + before, + beforeStr, + after, + nested + }); + } else { + o2[strPath] = { + path: path8, + val: void 0, + precensored: false, + circle: "", + escPath: JSON.stringify(strPath), + leadingBracket + }; } - return av - bv < 0 ? aFirst : bFirst; + return o2; + }, {}); + return { wildcards, wcLen, secret }; + } + } +}); +var require_redactor = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/redactor.js"(exports2, module14) { + "use strict"; + var rx = require_rx(); + module14.exports = redactor; + function redactor({ secret, serialize, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { + const redact = Function("o", ` + if (typeof o !== 'object' || o == null) { + ${strictImpl(strict, serialize)} + } + const { censor, secret } = this + const originalSecret = {} + const secretKeys = Object.keys(secret) + for (var i = 0; i < secretKeys.length; i++) { + originalSecret[secretKeys[i]] = secret[secretKeys[i]] + } + + ${redactTmpl(secret, isCensorFct, censorFctTakesPath)} + this.compileRestore() + ${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} + this.secret = originalSecret + ${resultTmpl(serialize)} + `).bind(state); + redact.state = state; + if (serialize === false) { + redact.restore = (o2) => state.restore(o2); } - if (!a.prerelease.length && !b.prerelease.length) { - return 0; - } else if (!b.prerelease.length) { - return options2.includePrerelease && b.patch === internals.any ? 0 : aFirst; - } else if (!a.prerelease.length) { - return options2.includePrerelease && a.patch === internals.any ? 0 : bFirst; - } - for (let i2 = 0; ; ++i2) { - const ai = a.prerelease[i2]; - const bi = b.prerelease[i2]; - if (ai === void 0 && bi === void 0) { - return 0; - } - if (ai === bi) { - continue; - } - if (ai === void 0) { - return aFirst; - } - if (bi === void 0) { - return bFirst; - } - const an = Number.isFinite(ai); - const bn = Number.isFinite(bi); - if (an !== bn) { - return an ? aFirst : bFirst; + return redact; + } + function redactTmpl(secret, isCensorFct, censorFctTakesPath) { + return Object.keys(secret).map((path8) => { + const { escPath, leadingBracket, path: arrPath } = secret[path8]; + const skip = leadingBracket ? 1 : 0; + const delim = leadingBracket ? "" : "."; + const hops = []; + var match2; + while ((match2 = rx.exec(path8)) !== null) { + const [, ix] = match2; + const { index, input } = match2; + if (index > skip) hops.push(input.substring(0, index - (ix ? 0 : 1))); } - return ai < bi ? aFirst : bFirst; + var existence = hops.map((p) => `o${delim}${p}`).join(" && "); + if (existence.length === 0) existence += `o${delim}${path8} != null`; + else existence += ` && o${delim}${path8} != null`; + const circularDetection = ` + switch (true) { + ${hops.reverse().map((p) => ` + case o${delim}${p} === censor: + secret[${escPath}].circle = ${JSON.stringify(p)} + break + `).join("\n")} } - }; - internals.Version = class { - constructor(version3, options2 = {}) { - Hoek.assert(version3, "Missing version argument"); - if (version3 instanceof internals.Version) { - return version3; - } - if (typeof version3 === "object") { - this._copy(version3); + `; + const censorArgs = censorFctTakesPath ? `val, ${JSON.stringify(arrPath)}` : `val`; + return ` + if (${existence}) { + const val = o${delim}${path8} + if (val === censor) { + secret[${escPath}].precensored = true } else { - this._parse(version3, options2); - } - this.format(); - } - _copy(version3) { - this.major = version3.major === void 0 ? internals.any : version3.major; - this.minor = version3.minor === void 0 ? internals.any : version3.minor; - this.patch = version3.patch === void 0 ? internals.any : version3.patch; - this.prerelease = version3.prerelease ?? []; - this.build = version3.build ?? []; - } - _parse(version3, options2) { - Hoek.assert(typeof version3 === "string", "Version argument must be a string"); - Hoek.assert(version3.length <= internals.maxLength, "Version string too long"); - const match = version3.match(internals.versionRx); - if (!match) { - throw new Error(`Invalid version string format: ${version3}`); - } - this.major = internals.Version._number(match[1], "major", options2); - this.minor = internals.Version._number(match[2] || "x", "minor", options2); - this.patch = internals.Version._number(match[3] || "x", "patch", options2); - this.prerelease = internals.Version._sub(match[4], "prerelease", options2); - this.build = internals.Version._sub(match[5], "build", options2); - } - static _number(string3, source, options2) { - if (internals.wildcards.includes(string3)) { - return internals.any; - } - if (options2.strict) { - Hoek.assert(string3.match(internals.strict.numberRx), "Value must be 0 or a number without a leading zero:", source); - } - const value = parseInt(string3, 10); - Hoek.assert(value <= Number.MAX_SAFE_INTEGER, "Value must be positive and less than max safe integer:", source); - return value; - } - static _sub(string3, source, options2) { - if (!string3) { - return []; - } - if (options2.strict) { - Hoek.assert(string3.match(internals.strict.tokenRx), "Value can only contain dot-separated hyphens, digits, a-z or A-Z:", source); - } - const subs = []; - const parts = string3.split("."); - for (const part of parts) { - if (!part) { - throw new Error(`Invalid empty ${source} segment`); - } - subs.push(part.match(/^\d+$/) ? internals.Version._number(part, source, { strict: options2.strict }) : part); + secret[${escPath}].val = val + o${delim}${path8} = ${isCensorFct ? `censor(${censorArgs})` : "censor"} + ${circularDetection} } - return subs; - } - format() { - this.version = `${internals.dot(this.major)}.${internals.dot(this.minor)}.${internals.dot(this.patch)}${internals.token(this.prerelease, "-")}${internals.token(this.build, "+")}`; - this.dots = [this.major, this.minor, this.patch]; - this.wildcard = this.major === internals.any && this.minor === internals.any && this.patch === internals.any && !this.prerelease.length; - } - toString() { - return this.version; } - compare(to, options2) { - return internals.Version.compare(this, to, options2); - } - static compare(a, b, options2 = {}) { - return exports2.compare(a, b, options2); + `; + }).join("\n"); + } + function dynamicRedactTmpl(hasWildcards, isCensorFct, censorFctTakesPath) { + return hasWildcards === true ? ` + { + const { wildcards, wcLen, groupRedact, nestedRedact } = this + for (var i = 0; i < wcLen; i++) { + const { before, beforeStr, after, nested } = wildcards[i] + if (nested === true) { + secret[beforeStr] = secret[beforeStr] || [] + nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath}) + } else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath}) } + } + ` : ""; + } + function resultTmpl(serialize) { + return serialize === false ? `return o` : ` + var s = this.serialize(o) + this.restore(o) + return s + `; + } + function strictImpl(strict, serialize) { + return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize === false ? `return o` : `return this.serialize(o)`; + } + } +}); +var require_modifiers = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/modifiers.js"(exports2, module14) { + "use strict"; + module14.exports = { + groupRedact, + groupRestore, + nestedRedact, + nestedRestore }; - internals.dot = (v2) => { - return v2 === internals.any ? "x" : v2; - }; - internals.token = (v2, prefix) => { - if (!v2.length) { - return ""; + function groupRestore({ keys, values, target }) { + if (target == null || typeof target === "string") return; + const length2 = keys.length; + for (var i2 = 0; i2 < length2; i2++) { + const k = keys[i2]; + target[k] = values[i2]; } - return `${prefix}${v2.join(".")}`; - }; - internals.Range = class { - constructor(range, options2) { - this._settings = Object.assign({}, options2); - this._anything = false; - this._or = []; - this._active = null; - if (range !== void 0) { - this.pattern(range); + } + function groupRedact(o2, path8, censor, isCensorFct, censorFctTakesPath) { + const target = get2(o2, path8); + if (target == null || typeof target === "string") return { keys: null, values: null, target, flat: true }; + const keys = Object.keys(target); + const keysLength = keys.length; + const pathLength = path8.length; + const pathWithKey = censorFctTakesPath ? [...path8] : void 0; + const values = new Array(keysLength); + for (var i2 = 0; i2 < keysLength; i2++) { + const key = keys[i2]; + values[i2] = target[key]; + if (censorFctTakesPath) { + pathWithKey[pathLength] = key; + target[key] = censor(target[key], pathWithKey); + } else if (isCensorFct) { + target[key] = censor(target[key]); + } else { + target[key] = censor; } - this._another(); } - _another() { - if (!this._active || this._active.rules.length) { - this._active = { rules: [] }; - this._or.push(this._active); + return { keys, values, target, flat: true }; + } + function nestedRestore(instructions) { + for (let i2 = 0; i2 < instructions.length; i2++) { + const { target, path: path8, value } = instructions[i2]; + let current = target; + for (let i3 = path8.length - 1; i3 > 0; i3--) { + current = current[path8[i3]]; } - return this; - } - _rule(operator, version3) { - version3 = exports2.version(version3, this._settings); - const compare = internals.operator(operator); - this._active.rules.push({ compare, version: version3, operator }); - return this; - } - get or() { - return this._another(); - } - equal(version3) { - return this._rule("=", version3); - } - above(version3) { - return this._rule(">", version3); + current[path8[0]] = value; } - below(version3) { - return this._rule("<", version3); - } - between(from3, to) { - this._rule(">=", from3); - this._rule("<=", to); - return this; + } + function nestedRedact(store, o2, path8, ns, censor, isCensorFct, censorFctTakesPath) { + const target = get2(o2, path8); + if (target == null) return; + const keys = Object.keys(target); + const keysLength = keys.length; + for (var i2 = 0; i2 < keysLength; i2++) { + const key = keys[i2]; + specialSet(store, target, key, path8, ns, censor, isCensorFct, censorFctTakesPath); } - minor(version3) { - version3 = exports2.version(version3, this._settings); - if (version3.major === internals.any) { - this._rule("=", version3); - return this; - } - this._rule(">=", version3); - if (version3.minor === internals.any) { - this._rule("<", { major: version3.major + 1, minor: 0, patch: 0, prerelease: [0] }); - } else { - this._rule("<", { major: version3.major, minor: version3.minor + 1, patch: 0, prerelease: [0] }); + return store; + } + function has2(obj, prop) { + return obj !== void 0 && obj !== null ? "hasOwn" in Object ? Object.hasOwn(obj, prop) : Object.prototype.hasOwnProperty.call(obj, prop) : false; + } + function specialSet(store, o2, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath) { + const afterPathLen = afterPath.length; + const lastPathIndex = afterPathLen - 1; + const originalKey = k; + var i2 = -1; + var n; + var nv; + var ov; + var oov = null; + var wc = null; + var kIsWc; + var wcov; + var consecutive = false; + var level = 0; + var depth = 0; + var redactPathCurrent = tree(); + ov = n = o2[k]; + if (typeof n !== "object") return; + while (n != null && ++i2 < afterPathLen) { + depth += 1; + k = afterPath[i2]; + oov = ov; + if (k !== "*" && !wc && !(typeof n === "object" && k in n)) { + break; } - return this; - } - compatible(version3) { - version3 = exports2.version(version3, this._settings); - if (version3.major === internals.any) { - this._rule("=", version3); - return this; + if (k === "*") { + if (wc === "*") { + consecutive = true; + } + wc = k; + if (i2 !== lastPathIndex) { + continue; + } } - this._rule(">=", version3); - if (version3.major === 0 && version3.minor !== internals.any) { - if (version3.minor === 0) { - this._rule("<", { major: 0, minor: 0, patch: version3.patch + 1, prerelease: [0] }); - } else { - this._rule("<", { major: 0, minor: version3.minor + 1, patch: 0, prerelease: [0] }); + if (wc) { + const wcKeys = Object.keys(n); + for (var j = 0; j < wcKeys.length; j++) { + const wck = wcKeys[j]; + wcov = n[wck]; + kIsWc = k === "*"; + if (consecutive) { + redactPathCurrent = node(redactPathCurrent, wck, depth); + level = i2; + ov = iterateNthLevel(wcov, level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, o2[originalKey], depth + 1); + } else { + if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { + if (kIsWc) { + ov = wcov; + } else { + ov = wcov[k]; + } + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (kIsWc) { + const rv = restoreInstr(node(redactPathCurrent, wck, depth), ov, o2[originalKey]); + store.push(rv); + n[wck] = nv; + } else { + if (wcov[k] === nv) { + } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { + redactPathCurrent = node(redactPathCurrent, wck, depth); + } else { + redactPathCurrent = node(redactPathCurrent, wck, depth); + const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, o2[originalKey]); + store.push(rv); + wcov[k] = nv; + } + } + } + } } + wc = null; } else { - this._rule("<", { major: version3.major + 1, minor: 0, patch: 0, prerelease: [0] }); + ov = n[k]; + redactPathCurrent = node(redactPathCurrent, k, depth); + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (has2(n, k) && nv === ov || nv === void 0 && censor !== void 0) { + } else { + const rv = restoreInstr(redactPathCurrent, ov, o2[originalKey]); + store.push(rv); + n[k] = nv; + } + n = n[k]; } - return this; - } - pattern(range) { - try { - this._pattern(range); - return this; - } catch (err) { - throw new Error(`Invalid range: "${range}" because: ${err.message}`); + if (typeof n !== "object") break; + if (ov === oov || typeof ov === "undefined") { } } - _pattern(range) { - if (range === "") { - this._anything = true; - return; - } - const normalized = internals.normalize(range); - const ors = normalized.split(/\s*\|\|\s*/); - for (const condition of ors) { - if (!condition) { - this._anything = true; - return; - } - this._another(); - const ands = condition.split(/\s+/); - for (const and of ands) { - const hyphen = and.indexOf("@"); - if (hyphen !== -1) { - const from3 = and.slice(0, hyphen); - const to = and.slice(hyphen + 1); - this.between(from3, to); - continue; - } - const parts = and.match(/^(\^|~|<\=|>\=|<|>|\=)?(.+)$/); - const operator = parts[1]; - const version3 = exports2.version(parts[2], this._settings); - if (version3.wildcard) { - this._anything = true; - return; - } - if (operator === "~") { - this.minor(version3); - continue; - } - if (operator === "^") { - this.compatible(version3); - continue; - } - if (operator) { - this._rule(operator, version3); - continue; - } - this.equal(version3); - } - } + } + function get2(o2, p) { + var i2 = -1; + var l = p.length; + var n = o2; + while (n != null && ++i2 < l) { + n = n[p[i2]]; } - match(version3, options2 = {}) { - version3 = exports2.version(version3, this._settings); - if (this._anything) { - return !!options2.includePrerelease || !version3.prerelease.length; - } - for (const { rules } of this._or) { - if (!rules.length) { - continue; + return n; + } + function iterateNthLevel(wcov, level, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth) { + if (level === 0) { + if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { + if (kIsWc) { + ov = wcov; + } else { + ov = wcov[k]; } - let matches = 0; - let excludes = 0; - for (const rule of rules) { - const compare = version3.compare(rule.version, Object.assign(this._settings, options2, { range: true })); - const exclude = Math.abs(compare) === 2; - if (rule.compare.includes(compare / (exclude ? 2 : 1))) { - ++matches; - if (exclude) { - ++excludes; - } + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (kIsWc) { + const rv = restoreInstr(redactPathCurrent, ov, parent); + store.push(rv); + n[wck] = nv; + } else { + if (wcov[k] === nv) { + } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { } else { - break; + const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, parent); + store.push(rv); + wcov[k] = nv; } } - if (matches === rules.length && excludes < matches) { - return true; - } } - return false; } - toString() { - if (this._anything) { - return "*"; - } - let string3 = ""; - for (const { rules } of this._or) { - if (!rules.length) { - continue; - } - const conditions = []; - for (const rule of rules) { - conditions.push(`${rule.operator !== "=" ? rule.operator : ""}${rule.version.version}`); - } - string3 += (string3 ? "||" : "") + conditions.join(" "); + for (const key in wcov) { + if (typeof wcov[key] === "object") { + redactPathCurrent = node(redactPathCurrent, key, depth); + iterateNthLevel(wcov[key], level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth + 1); } - return string3; } - }; - internals.operator = function(compare) { - switch (compare) { - case "=": - return [0]; - case ">": - return [1]; - case ">=": - return [0, 1]; - case "<": - return [-1]; - case "<=": - return [0, -1]; + } + function tree() { + return { parent: null, key: null, children: [], depth: 0 }; + } + function node(parent, key, depth) { + if (parent.depth === depth) { + return node(parent.parent, key, depth); } - }; - internals.normalize = function(range) { - return range.replace(/ \- /g, "@").replace(/~>/g, "~").replace(/(\^|~|<\=|>\=|<|>|\=)\s*([^\s]+)/g, ($0, $1, $2) => `${$1}${$2}`); - }; + var child = { + parent, + key, + depth, + children: [] + }; + parent.children.push(child); + return child; + } + function restoreInstr(node2, value, target) { + let current = node2; + const path8 = []; + do { + path8.push(current.key); + current = current.parent; + } while (current.parent != null); + return { path: path8, value, target }; + } } }); -var require_config = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/config.js"(exports2) { +var require_restorer = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/restorer.js"(exports2, module14) { "use strict"; - var Os = __require2("os"); - var Somever = require_lib13(); - var Validate = require_lib9(); - var internals = {}; - exports2.symbol = Symbol("hapi-response"); - exports2.apply = function(type, options2, ...message) { - const result = internals[type].validate(options2); - if (result.error) { - throw new Error(`Invalid ${type} options ${message.length ? "(" + message.join(" ") + ")" : ""} ${result.error.annotate()}`); - } - return result.value; - }; - exports2.enable = function(options2) { - const settings = options2 ? Object.assign({}, options2) : {}; - if (settings.security === true) { - settings.security = {}; + var { groupRestore, nestedRestore } = require_modifiers(); + module14.exports = restorer; + function restorer() { + return function compileRestore() { + if (this.restore) { + this.restore.state.secret = this.secret; + return; + } + const { secret, wcLen } = this; + const paths = Object.keys(secret); + const resetters = resetTmpl(secret, paths); + const hasWildcards = wcLen > 0; + const state = hasWildcards ? { secret, groupRestore, nestedRestore } : { secret }; + this.restore = Function( + "o", + restoreTmpl(resetters, paths, hasWildcards) + ).bind(state); + this.restore.state = state; + }; + } + function resetTmpl(secret, paths) { + return paths.map((path8) => { + const { circle, escPath, leadingBracket } = secret[path8]; + const delim = leadingBracket ? "" : "."; + const reset = circle ? `o.${circle} = secret[${escPath}].val` : `o${delim}${path8} = secret[${escPath}].val`; + const clear = `secret[${escPath}].val = undefined`; + return ` + if (secret[${escPath}].val !== undefined) { + try { ${reset} } catch (e) {} + ${clear} } - if (settings.cors === true) { - settings.cors = {}; + `; + }).join(""); + } + function restoreTmpl(resetters, paths, hasWildcards) { + const dynamicReset = hasWildcards === true ? ` + const keys = Object.keys(secret) + const len = keys.length + for (var i = len - 1; i >= ${paths.length}; i--) { + const k = keys[i] + const o = secret[k] + if (o) { + if (o.flat === true) this.groupRestore(o) + else this.nestedRestore(o) + secret[k] = null } - return settings; - }; - exports2.versionMatch = (version3, range) => Somever.match(version3, range, { includePrerelease: true }); - internals.access = Validate.object({ - entity: Validate.valid("user", "app", "any"), - scope: [false, Validate.array().items(Validate.string()).single().min(1)] - }); - internals.auth = Validate.alternatives([ - Validate.string(), - internals.access.keys({ - mode: Validate.valid("required", "optional", "try"), - strategy: Validate.string(), - strategies: Validate.array().items(Validate.string()).min(1), - access: Validate.array().items(internals.access.min(1)).single().min(1), - payload: [ - Validate.valid("required", "optional"), - Validate.boolean() - ] - }).without("strategy", "strategies").without("access", ["scope", "entity"]) - ]); - internals.event = Validate.object({ - method: Validate.array().items(Validate.function()).single(), - options: Validate.object({ - before: Validate.array().items(Validate.string()).single(), - after: Validate.array().items(Validate.string()).single(), - bind: Validate.any(), - sandbox: Validate.valid("server", "plugin"), - timeout: Validate.number().integer().min(1) - }).default({}) - }); - internals.exts = Validate.array().items(internals.event.keys({ type: Validate.string().required() })).single(); - internals.failAction = Validate.alternatives([ - Validate.valid("error", "log", "ignore"), - Validate.function() - ]).default("error"); - internals.routeBase = Validate.object({ - app: Validate.object().allow(null), - auth: internals.auth.allow(false), - bind: Validate.object().allow(null), - cache: Validate.object({ - expiresIn: Validate.number(), - expiresAt: Validate.string(), - privacy: Validate.valid("default", "public", "private"), - statuses: Validate.array().items(Validate.number().integer().min(200)).min(1).single().default([200, 204]), - otherwise: Validate.string().default("no-cache") - }).allow(false).default(), - compression: Validate.object().pattern(/.+/, Validate.object()).default(), - cors: Validate.object({ - origin: Validate.array().min(1).allow("ignore").default(["*"]), - maxAge: Validate.number().default(86400), - headers: Validate.array().items(Validate.string()).default(["Accept", "Authorization", "Content-Type", "If-None-Match"]), - additionalHeaders: Validate.array().items(Validate.string()).default([]), - exposedHeaders: Validate.array().items(Validate.string()).default(["WWW-Authenticate", "Server-Authorization"]), - additionalExposedHeaders: Validate.array().items(Validate.string()).default([]), - credentials: Validate.boolean().when("origin", { is: "ignore", then: false }).default(false), - preflightStatusCode: Validate.valid(200, 204).default(200) - }).allow(false, true).default(false), - ext: Validate.object({ - onPreAuth: Validate.array().items(internals.event).single(), - onCredentials: Validate.array().items(internals.event).single(), - onPostAuth: Validate.array().items(internals.event).single(), - onPreHandler: Validate.array().items(internals.event).single(), - onPostHandler: Validate.array().items(internals.event).single(), - onPreResponse: Validate.array().items(internals.event).single(), - onPostResponse: Validate.array().items(internals.event).single() - }).default({}), - files: Validate.object({ - relativeTo: Validate.string().pattern(/^([\/\.])|([A-Za-z]:\\)|(\\\\)/).default(".") - }).default(), - json: Validate.object({ - replacer: Validate.alternatives(Validate.function(), Validate.array()).allow(null).default(null), - space: Validate.number().allow(null).default(null), - suffix: Validate.string().allow(null).default(null), - escape: Validate.boolean().default(false) - }).default(), - log: Validate.object({ - collect: Validate.boolean().default(false) - }).default(), - payload: Validate.object({ - output: Validate.valid("data", "stream", "file").default("data"), - parse: Validate.boolean().allow("gunzip").default(true), - multipart: Validate.object({ - output: Validate.valid("data", "stream", "file", "annotated").required() - }).default(false).allow(true, false), - allow: Validate.array().items(Validate.string()).single(), - override: Validate.string(), - protoAction: Validate.valid("error", "remove", "ignore").default("error"), - maxBytes: Validate.number().integer().positive().default(1024 * 1024), - maxParts: Validate.number().integer().positive().default(1e3), - uploads: Validate.string().default(Os.tmpdir()), - failAction: internals.failAction, - timeout: Validate.number().integer().positive().allow(false).default(10 * 1e3), - defaultContentType: Validate.string().default("application/json"), - compression: Validate.object().pattern(/.+/, Validate.object()).default() - }).default(), - plugins: Validate.object(), - response: Validate.object({ - disconnectStatusCode: Validate.number().integer().min(400).default(499), - emptyStatusCode: Validate.valid(200, 204).default(204), - failAction: internals.failAction, - modify: Validate.boolean(), - options: Validate.object(), - ranges: Validate.boolean().default(true), - sample: Validate.number().min(0).max(100).when("modify", { then: Validate.forbidden() }), - schema: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(true, false), - status: Validate.object().pattern(/\d\d\d/, Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(true, false)) - }).default(), - security: Validate.object({ - hsts: Validate.alternatives([ - Validate.object({ - maxAge: Validate.number(), - includeSubdomains: Validate.boolean(), - includeSubDomains: Validate.boolean(), - preload: Validate.boolean() - }), - Validate.boolean(), - Validate.number() - ]).default(15768e3), - xframe: Validate.alternatives([ - Validate.boolean(), - Validate.valid("sameorigin", "deny"), - Validate.object({ - rule: Validate.valid("sameorigin", "deny", "allow-from"), - source: Validate.string() - }) - ]).default("deny"), - xss: Validate.valid("enabled", "disabled", false).default("disabled"), - noOpen: Validate.boolean().default(true), - noSniff: Validate.boolean().default(true), - referrer: Validate.alternatives([ - Validate.boolean().valid(false), - Validate.valid( - "", - "no-referrer", - "no-referrer-when-downgrade", - "unsafe-url", - "same-origin", - "origin", - "strict-origin", - "origin-when-cross-origin", - "strict-origin-when-cross-origin" - ) - ]).default(false) - }).allow(null, false, true).default(false), - state: Validate.object({ - parse: Validate.boolean().default(true), - failAction: internals.failAction - }).default(), - timeout: Validate.object({ - socket: Validate.number().integer().positive().allow(false), - server: Validate.number().integer().positive().allow(false).default(false) - }).default(), - validate: Validate.object({ - headers: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(null, true), - params: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(null, true), - query: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(null, false, true), - payload: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(null, false, true), - state: Validate.alternatives(Validate.object(), Validate.array(), Validate.function()).allow(null, false, true), - failAction: internals.failAction, - errorFields: Validate.object(), - options: Validate.object().default(), - validator: Validate.object() - }).default() - }); - internals.server = Validate.object({ - address: Validate.string().hostname(), - app: Validate.object().allow(null), - autoListen: Validate.boolean(), - cache: Validate.allow(null), - // Validated elsewhere - compression: Validate.object({ - minBytes: Validate.number().min(1).integer().default(1024) - }).allow(false).default(), - debug: Validate.object({ - request: Validate.array().items(Validate.string()).single().allow(false).default(["implementation"]), - log: Validate.array().items(Validate.string()).single().allow(false) - }).allow(false).default(), - host: Validate.string().hostname().allow(null), - info: Validate.object({ - remote: Validate.boolean().default(false) - }).default({}), - listener: Validate.any(), - load: Validate.object({ - sampleInterval: Validate.number().integer().min(0).default(0) - }).unknown().default(), - mime: Validate.object().empty(null).default(), - operations: Validate.object({ - cleanStop: Validate.boolean().default(true) - }).default(), - plugins: Validate.object(), - port: Validate.alternatives([ - Validate.number().integer().min(0), - // TCP port - Validate.string().pattern(/\//), - // Unix domain socket - Validate.string().pattern(/^\\\\\.\\pipe\\/) - // Windows named pipe - ]).allow(null), - query: Validate.object({ - parser: Validate.function() - }).default(), - router: Validate.object({ - isCaseSensitive: Validate.boolean().default(true), - stripTrailingSlash: Validate.boolean().default(false) - }).default(), - routes: internals.routeBase.default(), - state: Validate.object(), - // Cookie defaults - tls: Validate.alternatives([ - Validate.object().allow(null), - Validate.boolean() - ]), - uri: Validate.string().pattern(/[^/]$/) - }); - internals.vhost = Validate.alternatives([ - Validate.string().hostname(), - Validate.array().items(Validate.string().hostname()).min(1) - ]); - internals.handler = Validate.alternatives([ - Validate.function(), - Validate.object().length(1) - ]); - internals.route = Validate.object({ - method: Validate.string().pattern(/^[a-zA-Z0-9!#\$%&'\*\+\-\.^_`\|~]+$/).required(), - path: Validate.string().required(), - rules: Validate.object(), - vhost: internals.vhost, - // Validated in route construction - handler: Validate.any(), - options: Validate.any(), - config: Validate.any() - // Backwards compatibility - }).without("config", "options"); - internals.pre = [ - Validate.function(), - Validate.object({ - method: Validate.alternatives(Validate.string(), Validate.function()).required(), - assign: Validate.string(), - mode: Validate.valid("serial", "parallel"), - failAction: internals.failAction - }) - ]; - internals.routeConfig = internals.routeBase.keys({ - description: Validate.string(), - id: Validate.string(), - isInternal: Validate.boolean(), - notes: [ - Validate.string(), - Validate.array().items(Validate.string()) - ], - pre: Validate.array().items(...internals.pre.concat(Validate.array().items(...internals.pre).min(1))), - tags: [ - Validate.string(), - Validate.array().items(Validate.string()) - ] - }); - internals.cacheConfig = Validate.alternatives([ - Validate.function(), - Validate.object({ - name: Validate.string().invalid("_default"), - shared: Validate.boolean(), - provider: [ - Validate.function(), - { - constructor: Validate.function().required(), - options: Validate.object({ - partition: Validate.string().default("hapi-cache") - }).unknown().default({}) - } - ], - engine: Validate.object() - }).xor("provider", "engine") - ]); - internals.cache = Validate.array().items(internals.cacheConfig).min(1).single(); - internals.cachePolicy = Validate.object({ - cache: Validate.string().allow(null).allow(""), - segment: Validate.string(), - shared: Validate.boolean() - }).unknown(); - internals.method = Validate.object({ - bind: Validate.object().allow(null), - generateKey: Validate.function(), - cache: internals.cachePolicy - }); - internals.methodObject = Validate.object({ - name: Validate.string().required(), - method: Validate.function().required(), - options: Validate.object() - }); - internals.register = Validate.object({ - once: true, - routes: Validate.object({ - prefix: Validate.string().pattern(/^\/.+/), - vhost: internals.vhost - }).default({}) - }); - internals.semver = Validate.string(); - internals.plugin = internals.register.keys({ - options: Validate.any(), - plugin: Validate.object({ - register: Validate.function().required(), - name: Validate.string().when("pkg.name", { is: Validate.exist(), otherwise: Validate.required() }), - version: Validate.string(), - multiple: Validate.boolean().default(false), - dependencies: [ - Validate.array().items(Validate.string()).single(), - Validate.object().pattern(/.+/, internals.semver) - ], - once: true, - requirements: Validate.object({ - hapi: Validate.string(), - node: Validate.string() - }).default(), - pkg: Validate.object({ - name: Validate.string(), - version: Validate.string().default("0.0.0") - }).unknown().default({}) - }).unknown() - }).without("once", "options").unknown(); - internals.rules = Validate.object({ - validate: Validate.object({ - schema: Validate.alternatives(Validate.object(), Validate.array()).required(), - options: Validate.object().default({ allowUnknown: true }) - }) - }); + } + ` : ""; + return ` + const secret = this.secret + ${dynamicReset} + ${resetters} + return o + `; + } } }); -var require_decode = __commonJS({ - "node_modules/.deno/@hapi+call@9.0.1/node_modules/@hapi/call/lib/decode.js"(exports2) { +var require_state = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/state.js"(exports2, module14) { "use strict"; - var internals = {}; - exports2.decode = function(string3) { - let percentPos = string3.indexOf("%"); - if (percentPos === -1) { - return string3; - } - let decoded = ""; - let last = 0; - let codepoint = 0; - let startOfOctets = percentPos; - let state = internals.utf8.accept; - while (percentPos > -1 && percentPos < string3.length) { - const high = internals.resolveHex(string3[percentPos + 1], 4); - const low = internals.resolveHex(string3[percentPos + 2], 0); - const byte = high | low; - const type = internals.utf8.data[byte]; - state = internals.utf8.data[256 + state + type]; - codepoint = codepoint << 6 | byte & internals.utf8.data[364 + type]; - if (state === internals.utf8.accept) { - decoded += string3.slice(last, startOfOctets); - decoded += codepoint <= 65535 ? String.fromCharCode(codepoint) : String.fromCharCode(55232 + (codepoint >> 10), 56320 + (codepoint & 1023)); - codepoint = 0; - last = percentPos + 3; - percentPos = string3.indexOf("%", last); - startOfOctets = percentPos; - continue; - } - if (state === internals.utf8.reject) { - return null; - } - percentPos += 3; - if (percentPos >= string3.length || string3[percentPos] !== "%") { - return null; - } - } - return decoded + string3.slice(last); - }; - internals.resolveHex = function(char, shift) { - const i2 = internals.hex[char]; - return i2 === void 0 ? 255 : i2 << shift; - }; - internals.hex = { - "0": 0, - "1": 1, - "2": 2, - "3": 3, - "4": 4, - "5": 5, - "6": 6, - "7": 7, - "8": 8, - "9": 9, - "a": 10, - "A": 10, - "b": 11, - "B": 11, - "c": 12, - "C": 12, - "d": 13, - "D": 13, - "e": 14, - "E": 14, - "f": 15, - "F": 15 - }; - internals.utf8 = { - accept: 12, - reject: 0, - data: [ - // Maps bytes to character to a transition - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 4, - 4, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 6, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 8, - 7, - 7, - 10, - 9, - 9, - 9, - 11, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - // Maps a state to a new state when adding a transition - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 12, - 0, - 0, - 0, - 0, - 24, - 36, - 48, - 60, - 72, - 84, - 96, - 0, - 12, - 12, - 12, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 24, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 48, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // Maps the current transition to a mask that needs to apply to the byte - 127, - 63, - 63, - 63, - 0, - 31, - 15, - 15, - 15, - 7, - 7, - 7 - ] - }; + module14.exports = state; + function state(o2) { + const { + secret, + censor, + compileRestore, + serialize, + groupRedact, + nestedRedact, + wildcards, + wcLen + } = o2; + const builder = [{ secret, censor, compileRestore }]; + if (serialize !== false) builder.push({ serialize }); + if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }); + return Object.assign(...builder); + } } }); -var require_regex = __commonJS({ - "node_modules/.deno/@hapi+call@9.0.1/node_modules/@hapi/call/lib/regex.js"(exports2) { - "use strict"; - exports2.generate = function() { - const empty2 = "(?:^\\/$)"; - const legalChars = "[\\w\\!\\$&'\\(\\)\\*\\+\\,;\\=\\:@\\-\\.~]"; - const encoded = "%[A-F0-9]{2}"; - const literalChar = "(?:" + legalChars + "|" + encoded + ")"; - const literal = literalChar + "+"; - const literalOptional = literalChar + "*"; - const midParam = "(?:\\{\\w+(?:\\*[1-9]\\d*)?\\})"; - const endParam = "(?:\\/(?:\\{\\w+(?:(?:\\*(?:[1-9]\\d*)?)|(?:\\?))?\\})?)?"; - const partialParam = "(?:\\{\\w+\\??\\})"; - const mixedParam = "(?:(?:" + literal + partialParam + ")+" + literalOptional + ")|(?:" + partialParam + "(?:" + literal + partialParam + ")+" + literalOptional + ")|(?:" + partialParam + literal + ")"; - const segmentContent = "(?:" + literal + "|" + midParam + "|" + mixedParam + ")"; - const segment = "\\/" + segmentContent; - const segments = "(?:" + segment + ")*"; - const path8 = "(?:^" + segments + endParam + "$)"; - const parseParam = "(" + literal + ")|(?:\\{(\\w+)(?:(\\*)(\\d+)?)?(\\?)?\\})"; - const expressions = { - parseParam: new RegExp(parseParam, "g"), - validatePath: new RegExp(empty2 + "|" + path8), - validatePathEncoded: /%(?:2[146-9A-E]|3[\dABD]|4[\dA-F]|5[\dAF]|6[1-9A-F]|7[\dAE])/g - }; - return expressions; - }; - } -}); -var require_segment = __commonJS({ - "node_modules/.deno/@hapi+call@9.0.1/node_modules/@hapi/call/lib/segment.js"(exports2, module14) { - "use strict"; - var Hoek = require_lib(); - var internals = {}; - exports2 = module14.exports = internals.Segment = function() { - this._edge = null; - this._fulls = null; - this._literals = null; - this._param = null; - this._mixed = null; - this._wildcard = null; - }; - internals.Segment.prototype.add = function(segments, record2) { - const current = segments[0]; - const remaining = segments.slice(1); - const isEdge = !remaining.length; - const literals = []; - let isLiteral = true; - for (let i2 = 0; i2 < segments.length && isLiteral; ++i2) { - isLiteral = segments[i2].literal !== void 0; - literals.push(segments[i2].literal); - } - if (isLiteral) { - this._fulls = this._fulls ?? /* @__PURE__ */ new Map(); - let literal = "/" + literals.join("/"); - if (!record2.settings.isCaseSensitive) { - literal = literal.toLowerCase(); - } - Hoek.assert(!this._fulls.has(literal), "New route", record2.path, "conflicts with existing", this._fulls.get(literal)?.record.path); - this._fulls.set(literal, { segment: current, record: record2 }); - } else if (current.literal !== void 0) { - this._literals = this._literals ?? /* @__PURE__ */ new Map(); - const currentLiteral = record2.settings.isCaseSensitive ? current.literal : current.literal.toLowerCase(); - if (!this._literals.has(currentLiteral)) { - this._literals.set(currentLiteral, new internals.Segment()); - } - this._literals.get(currentLiteral).add(remaining, record2); - } else if (current.wildcard) { - Hoek.assert(!this._wildcard, "New route", record2.path, "conflicts with existing", this._wildcard?.record.path); - Hoek.assert(!this._param || !this._param._wildcard, "New route", record2.path, "conflicts with existing", this._param?._wildcard?.record.path); - this._wildcard = { segment: current, record: record2 }; - } else if (current.mixed) { - this._mixed = this._mixed ?? []; - let mixed = this._mixedLookup(current); - if (!mixed) { - mixed = { segment: current, node: new internals.Segment() }; - this._mixed.push(mixed); - this._mixed.sort(internals.mixed); - } - if (isEdge) { - Hoek.assert(!mixed.node._edge, "New route", record2.path, "conflicts with existing", mixed.node._edge?.record.path); - mixed.node._edge = { segment: current, record: record2 }; - } else { - mixed.node.add(remaining, record2); - } - } else { - this._param = this._param ?? new internals.Segment(); - if (isEdge) { - Hoek.assert(!this._param._edge, "New route", record2.path, "conflicts with existing", this._param._edge?.record.path); - this._param._edge = { segment: current, record: record2 }; - } else { - Hoek.assert(!this._wildcard || !remaining[0].wildcard, "New route", record2.path, "conflicts with existing", this._wildcard?.record.path); - this._param.add(remaining, record2); - } - } - }; - internals.Segment.prototype._mixedLookup = function(segment) { - for (let i2 = 0; i2 < this._mixed.length; ++i2) { - if (internals.mixed({ segment }, this._mixed[i2]) === 0) { - return this._mixed[i2]; - } +var require_fast_redact = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/index.js"(exports2, module14) { + "use strict"; + var validator = require_validator(); + var parse52 = require_parse(); + var redactor = require_redactor(); + var restorer = require_restorer(); + var { groupRedact, nestedRedact } = require_modifiers(); + var state = require_state(); + var rx = require_rx(); + var validate = validator(); + var noop = (o2) => o2; + noop.restore = noop; + var DEFAULT_CENSOR = "[REDACTED]"; + fastRedact.rx = rx; + fastRedact.validator = validator; + module14.exports = fastRedact; + function fastRedact(opts = {}) { + const paths = Array.from(new Set(opts.paths || [])); + const serialize = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; + const remove = opts.remove; + if (remove === true && serialize !== JSON.stringify) { + throw Error("fast-redact \u2013 remove option may only be set when serializer is JSON.stringify"); } - return null; + const censor = remove === true ? void 0 : "censor" in opts ? opts.censor : DEFAULT_CENSOR; + const isCensorFct = typeof censor === "function"; + const censorFctTakesPath = isCensorFct && censor.length > 1; + if (paths.length === 0) return serialize || noop; + validate({ paths, serialize, censor }); + const { wildcards, wcLen, secret } = parse52({ paths, censor }); + const compileRestore = restorer(); + const strict = "strict" in opts ? opts.strict : true; + return redactor({ secret, wcLen, serialize, strict, isCensorFct, censorFctTakesPath }, state({ + secret, + censor, + compileRestore, + serialize, + groupRedact, + nestedRedact, + wildcards, + wcLen + })); + } + } +}); +var require_symbols = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/symbols.js"(exports2, module14) { + "use strict"; + var setLevelSym = Symbol("pino.setLevel"); + var getLevelSym = Symbol("pino.getLevel"); + var levelValSym = Symbol("pino.levelVal"); + var levelCompSym = Symbol("pino.levelComp"); + var useLevelLabelsSym = Symbol("pino.useLevelLabels"); + var useOnlyCustomLevelsSym = Symbol("pino.useOnlyCustomLevels"); + var mixinSym = Symbol("pino.mixin"); + var lsCacheSym = Symbol("pino.lsCache"); + var chindingsSym = Symbol("pino.chindings"); + var asJsonSym = Symbol("pino.asJson"); + var writeSym = Symbol("pino.write"); + var redactFmtSym = Symbol("pino.redactFmt"); + var timeSym = Symbol("pino.time"); + var timeSliceIndexSym = Symbol("pino.timeSliceIndex"); + var streamSym = Symbol("pino.stream"); + var stringifySym = Symbol("pino.stringify"); + var stringifySafeSym = Symbol("pino.stringifySafe"); + var stringifiersSym = Symbol("pino.stringifiers"); + var endSym = Symbol("pino.end"); + var formatOptsSym = Symbol("pino.formatOpts"); + var messageKeySym = Symbol("pino.messageKey"); + var errorKeySym = Symbol("pino.errorKey"); + var nestedKeySym = Symbol("pino.nestedKey"); + var nestedKeyStrSym = Symbol("pino.nestedKeyStr"); + var mixinMergeStrategySym = Symbol("pino.mixinMergeStrategy"); + var msgPrefixSym = Symbol("pino.msgPrefix"); + var wildcardFirstSym = Symbol("pino.wildcardFirst"); + var serializersSym = Symbol.for("pino.serializers"); + var formattersSym = Symbol.for("pino.formatters"); + var hooksSym = Symbol.for("pino.hooks"); + var needsMetadataGsym = Symbol.for("pino.metadata"); + module14.exports = { + setLevelSym, + getLevelSym, + levelValSym, + levelCompSym, + useLevelLabelsSym, + mixinSym, + lsCacheSym, + chindingsSym, + asJsonSym, + writeSym, + serializersSym, + redactFmtSym, + timeSym, + timeSliceIndexSym, + streamSym, + stringifySym, + stringifySafeSym, + stringifiersSym, + endSym, + formatOptsSym, + messageKeySym, + errorKeySym, + nestedKeySym, + wildcardFirstSym, + needsMetadataGsym, + useOnlyCustomLevelsSym, + formattersSym, + hooksSym, + nestedKeyStrSym, + mixinMergeStrategySym, + msgPrefixSym }; - internals.mixed = function(a, b) { - const aFirst = -1; - const bFirst = 1; - const as = a.segment; - const bs = b.segment; - if (as.length !== bs.length) { - return as.length > bs.length ? aFirst : bFirst; - } - if (as.first !== bs.first) { - return as.first ? bFirst : aFirst; - } - for (let i2 = 0; i2 < as.segments.length; ++i2) { - const am = as.segments[i2]; - const bm = bs.segments[i2]; - if (am === bm) { - continue; + } +}); +var require_redaction = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/redaction.js"(exports2, module14) { + "use strict"; + var fastRedact = require_fast_redact(); + var { redactFmtSym, wildcardFirstSym } = require_symbols(); + var { rx, validator } = fastRedact; + var validate = validator({ + ERR_PATHS_MUST_BE_STRINGS: () => "pino \u2013 redacted paths must be strings", + ERR_INVALID_PATH: (s) => `pino \u2013 redact paths array contains an invalid path (${s})` + }); + var CENSOR = "[Redacted]"; + var strict = false; + function redaction(opts, serialize) { + const { paths, censor } = handle(opts); + const shape = paths.reduce((o2, str) => { + rx.lastIndex = 0; + const first = rx.exec(str); + const next = rx.exec(str); + let ns = first[1] !== void 0 ? first[1].replace(/^(?:"|'|`)(.*)(?:"|'|`)$/, "$1") : first[0]; + if (ns === "*") { + ns = wildcardFirstSym; } - if (am.length === bm.length) { - return am > bm ? bFirst : aFirst; + if (next === null) { + o2[ns] = null; + return o2; } - return am.length < bm.length ? bFirst : aFirst; - } - return 0; - }; - internals.Segment.prototype.lookup = function(path8, segments, options2) { - let match = null; - if (this._fulls) { - match = this._fulls.get(options2.isCaseSensitive ? path8 : path8.toLowerCase()); - if (match) { - return { record: match.record, array: [] }; + if (o2[ns] === null) { + return o2; } - } - const current = segments[0]; - const nextPath = path8.slice(current.length + 1); - const remainder = segments.length > 1 ? segments.slice(1) : null; - if (this._literals) { - const literal = options2.isCaseSensitive ? current : current.toLowerCase(); - match = this._literals.get(literal); - if (match) { - const record2 = internals.deeper(match, nextPath, remainder, [], options2); - if (record2) { - return record2; - } + const { index } = next; + const nextPath = `${str.substr(index, str.length - 1)}`; + o2[ns] = o2[ns] || []; + if (ns !== wildcardFirstSym && o2[ns].length === 0) { + o2[ns].push(...o2[wildcardFirstSym] || []); } - } - if (this._mixed) { - for (let i2 = 0; i2 < this._mixed.length; ++i2) { - match = this._mixed[i2]; - const params = current.match(match.segment.mixed); - if (params) { - const array2 = []; - for (let j = 1; j < params.length; ++j) { - array2.push(params[j]); - } - const record2 = internals.deeper(match.node, nextPath, remainder, array2, options2); - if (record2) { - return record2; + if (ns === wildcardFirstSym) { + Object.keys(o2).forEach(function(k) { + if (o2[k]) { + o2[k].push(nextPath); } - } - } - } - if (this._param) { - if (current || this._param._edge?.segment.empty) { - const record2 = internals.deeper(this._param, nextPath, remainder, [current], options2); - if (record2) { - return record2; - } - } - } - if (this._wildcard) { - return { record: this._wildcard.record, array: [path8.slice(1)] }; - } - return null; - }; - internals.deeper = function(match, path8, segments, array2, options2) { - if (!segments) { - if (match._edge) { - return { record: match._edge.record, array: array2 }; - } - if (match._wildcard) { - return { record: match._wildcard.record, array: array2 }; - } - } else { - const result = match.lookup(path8, segments, options2); - if (result) { - return { record: result.record, array: array2.concat(result.array) }; + }); } - } - return null; - }; - } -}); -var require_lib14 = __commonJS({ - "node_modules/.deno/@hapi+call@9.0.1/node_modules/@hapi/call/lib/index.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Decode = require_decode(); - var Regex = require_regex(); - var Segment = require_segment(); - var internals = { - pathRegex: Regex.generate(), - defaults: { - isCaseSensitive: true - } - }; - exports2.Router = internals.Router = function(options2) { - this.settings = Hoek.applyToDefaults(internals.defaults, options2 || {}); - this.routes = /* @__PURE__ */ new Map(); - this.ids = /* @__PURE__ */ new Map(); - this.vhosts = null; - this.specials = { - badRequest: null, - notFound: null, - options: null + o2[ns].push(nextPath); + return o2; + }, {}); + const result = { + [redactFmtSym]: fastRedact({ paths, censor, serialize, strict }) }; - }; - internals.Router.prototype.add = function(config2, route2) { - const method = config2.method.toLowerCase(); - const vhost = config2.vhost || "*"; - if (vhost !== "*") { - this.vhosts = this.vhosts ?? /* @__PURE__ */ new Map(); - if (!this.vhosts.has(vhost)) { - this.vhosts.set(vhost, /* @__PURE__ */ new Map()); - } - } - const table = vhost === "*" ? this.routes : this.vhosts.get(vhost); - if (!table.has(method)) { - table.set(method, { routes: [], router: new Segment() }); - } - const analysis = config2.analysis ?? this.analyze(config2.path); - const record2 = { - path: config2.path, - route: route2 || config2.path, - segments: analysis.segments, - params: analysis.params, - fingerprint: analysis.fingerprint, - settings: this.settings + const topCensor = (...args) => { + return typeof censor === "function" ? serialize(censor(...args)) : serialize(censor); }; - const map = table.get(method); - map.router.add(analysis.segments, record2); - map.routes.push(record2); - map.routes.sort(internals.sort); - const last = record2.segments[record2.segments.length - 1]; - if (last.empty) { - map.router.add(analysis.segments.slice(0, -1), record2); - } - if (config2.id) { - Hoek.assert(!this.ids.has(config2.id), "Route id", config2.id, "for path", config2.path, "conflicts with existing path", this.ids.has(config2.id) && this.ids.get(config2.id).path); - this.ids.set(config2.id, record2); - } - return record2; - }; - internals.Router.prototype.special = function(type, route2) { - Hoek.assert(Object.keys(this.specials).indexOf(type) !== -1, "Unknown special route type:", type); - this.specials[type] = { route: route2 }; - }; - internals.Router.prototype.route = function(method, path8, hostname2) { - const segments = path8.length === 1 ? [""] : path8.split("/").slice(1); - const vhost = this.vhosts && hostname2 && this.vhosts.get(hostname2); - const route2 = vhost && this._lookup(path8, segments, vhost, method) || this._lookup(path8, segments, this.routes, method) || method === "head" && vhost && this._lookup(path8, segments, vhost, "get") || method === "head" && this._lookup(path8, segments, this.routes, "get") || method === "options" && this.specials.options || vhost && this._lookup(path8, segments, vhost, "*") || this._lookup(path8, segments, this.routes, "*") || this.specials.notFound || Boom5.notFound(); - return route2; - }; - internals.Router.prototype._lookup = function(path8, segments, table, method) { - const set = table.get(method); - if (!set) { - return null; - } - const match = set.router.lookup(path8, segments, this.settings); - if (!match) { - return null; - } - const assignments = {}; - const array2 = []; - for (let i2 = 0; i2 < match.array.length; ++i2) { - const name = match.record.params[i2]; - const value = Decode.decode(match.array[i2]); - if (value === null) { - return this.specials.badRequest ?? Boom5.badRequest("Invalid request path"); - } - if (assignments[name] !== void 0) { - assignments[name] = assignments[name] + "/" + value; + return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o2, k) => { + if (shape[k] === null) { + o2[k] = (value) => topCensor(value, [k]); } else { - assignments[name] = value; - } - if (i2 + 1 === match.array.length || // Only include the last segment of a multi-segment param - name !== match.record.params[i2 + 1]) { - array2.push(assignments[name]); - } - } - return { params: assignments, paramsArray: array2, route: match.record.route }; - }; - internals.Router.prototype.normalize = function(path8) { - if (path8 && path8.indexOf("%") !== -1) { - const uppercase2 = path8.replace(/%[0-9a-fA-F][0-9a-fA-F]/g, (encoded) => encoded.toUpperCase()); - const decoded = uppercase2.replace(/%(?:2[146-9A-E]|3[\dABD]|4[\dA-F]|5[\dAF]|6[1-9A-F]|7[\dAE])/g, (encoded) => String.fromCharCode(parseInt(encoded.substring(1), 16))); - path8 = decoded; - } - if (path8 && (path8.indexOf("/.") !== -1 || path8[0] === ".")) { - const hasLeadingSlash = path8[0] === "/"; - const segments = path8.split("/"); - const normalized = []; - let segment; - for (let i2 = 0; i2 < segments.length; ++i2) { - segment = segments[i2]; - if (segment === "..") { - normalized.pop(); - } else if (segment !== ".") { - normalized.push(segment); - } - } - if (segment === "." || segment === "..") { - normalized.push(""); - } - path8 = normalized.join("/"); - if (path8[0] !== "/" && hasLeadingSlash) { - path8 = "/" + path8; - } - } - return path8; - }; - internals.Router.prototype.analyze = function(path8) { - Hoek.assert(internals.pathRegex.validatePath.test(path8), "Invalid path:", path8); - Hoek.assert(!internals.pathRegex.validatePathEncoded.test(path8), "Path cannot contain encoded non-reserved path characters:", path8); - const pathParts = path8.split("/"); - const segments = []; - const params = []; - const fingers = []; - for (let i2 = 1; i2 < pathParts.length; ++i2) { - let segment = pathParts[i2]; - if (segment.indexOf("{") === -1) { - segment = this.settings.isCaseSensitive ? segment : segment.toLowerCase(); - fingers.push(segment); - segments.push({ literal: segment }); - continue; - } - const parts = internals.parseParams(segment); - if (parts.length === 1) { - const item = parts[0]; - Hoek.assert(params.indexOf(item.name) === -1, "Cannot repeat the same parameter name:", item.name, "in:", path8); - params.push(item.name); - if (item.wildcard) { - if (item.count) { - for (let j = 0; j < item.count; ++j) { - fingers.push("?"); - segments.push({}); - if (j) { - params.push(item.name); - } - } - } else { - fingers.push("#"); - segments.push({ wildcard: true }); - } - } else { - fingers.push("?"); - segments.push({ empty: item.empty }); - } - } else { - const seg = { - length: parts.length, - first: typeof parts[0] !== "string", - segments: [] - }; - let finger = ""; - let regex = "^"; - for (let j = 0; j < parts.length; ++j) { - const part = parts[j]; - if (typeof part === "string") { - finger = finger + part; - regex = regex + Hoek.escapeRegex(part); - seg.segments.push(part); - } else { - Hoek.assert(params.indexOf(part.name) === -1, "Cannot repeat the same parameter name:", part.name, "in:", path8); - params.push(part.name); - finger = finger + "?"; - regex = regex + "(." + (part.empty ? "*" : "+") + ")"; - } - } - seg.mixed = new RegExp(regex + "$", !this.settings.isCaseSensitive ? "i" : ""); - fingers.push(finger); - segments.push(seg); - } - } - return { - segments, - fingerprint: "/" + fingers.join("/"), - params - }; - }; - internals.parseParams = function(segment) { - const parts = []; - segment.replace(internals.pathRegex.parseParam, ($0, literal, name, wildcard, count, empty2) => { - if (literal) { - parts.push(literal); - } else { - parts.push({ - name, - wildcard: !!wildcard, - count: count && parseInt(count, 10), - empty: !!empty2 + const wrappedCensor = typeof censor === "function" ? (value, path8) => { + return censor(value, [k, ...path8]); + } : censor; + o2[k] = fastRedact({ + paths: shape[k], + censor: wrappedCensor, + serialize, + strict }); } - return ""; - }); - return parts; - }; - internals.Router.prototype.table = function(host) { - const result = []; - const collect = (table) => { - if (!table) { - return; - } - for (const map of table.values()) { - for (const record2 of map.routes) { - result.push(record2.route); - } - } - }; - if (this.vhosts) { - const vhosts = host ? [].concat(host) : [...this.vhosts.keys()]; - for (const vhost of vhosts) { - collect(this.vhosts.get(vhost)); - } + return o2; + }, result); + } + function handle(opts) { + if (Array.isArray(opts)) { + opts = { paths: opts, censor: CENSOR }; + validate(opts); + return opts; } - collect(this.routes); - return result; - }; - internals.sort = function(a, b) { - const aFirst = -1; - const bFirst = 1; - const as = a.segments; - const bs = b.segments; - if (as.length !== bs.length) { - return as.length > bs.length ? bFirst : aFirst; - } - for (let i2 = 0; ; ++i2) { - if (as[i2].literal) { - if (bs[i2].literal) { - if (as[i2].literal === bs[i2].literal) { - continue; - } - return as[i2].literal > bs[i2].literal ? bFirst : aFirst; - } - return aFirst; - } - if (bs[i2].literal) { - return bFirst; - } - return as[i2].wildcard ? bFirst : aFirst; + let { paths, censor = CENSOR, remove } = opts; + if (Array.isArray(paths) === false) { + throw Error("pino \u2013 redact must contain an array of strings"); } - }; + if (remove === true) censor = void 0; + validate({ paths, censor }); + return { paths, censor }; + } + module14.exports = redaction; } }); -var require_client2 = __commonJS({ - "node_modules/.deno/@hapi+catbox@12.1.1/node_modules/@hapi/catbox/lib/client.js"(exports2, module14) { +var require_time = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/time.js"(exports2, module14) { "use strict"; - var Hoek = require_lib(); - var Boom5 = require_lib2(); - var internals = { - validate: Symbol("validate") - }; - internals.defaults = { - partition: "catbox" - }; - module14.exports = class { - constructor(engine, options2) { - Hoek.assert(engine, "Missing catbox client engine"); - Hoek.assert(typeof engine === "object" && typeof engine.start === "function" || typeof engine === "function", "engine must be an engine object or engine prototype (function)"); - Hoek.assert(typeof engine === "function" || !options2, "Can only specify options with function engine config"); - const settings = Object.assign({}, internals.defaults, options2); - Hoek.assert(settings.partition.match(/^[\w\-]+$/), "Invalid partition name:" + settings.partition); - this.connection = typeof engine === "object" ? engine : new engine(settings); - } - async start() { - await this.connection.start(); - } - async stop() { - await this.connection.stop(); - } - isReady() { - return this.connection.isReady(); - } - validateSegmentName(name) { - return this.connection.validateSegmentName(name); - } - async get(key) { - this[internals.validate](key, null); - if (key === null) { - return null; - } - const result = await this.connection.get(key); - if (!result || result.item === void 0 || result.item === null) { - return null; - } - const now = Date.now(); - const expires = result.stored + result.ttl; - const ttl = expires - now; - if (ttl <= 0) { - return null; - } - const cached2 = { - item: result.item, - stored: result.stored, - ttl - }; - return cached2; - } - async set(key, value, ttl) { - this[internals.validate](key); - if (ttl <= 0) { - return; - } - await this.connection.set(key, value, ttl); - } - async drop(key) { - this[internals.validate](key); - await this.connection.drop(key); - } - [internals.validate](key, allow = {}) { - if (!this.isReady()) { - throw Boom5.internal("Disconnected"); - } - const isValidKey2 = key && typeof key.id === "string" && key.segment && typeof key.segment === "string"; - if (!isValidKey2 && key !== allow) { - throw Boom5.internal("Invalid key"); - } - } - }; + var nullTime = () => ""; + var epochTime = () => `,"time":${Date.now()}`; + var unixTime = () => `,"time":${Math.round(Date.now() / 1e3)}`; + var isoTime = () => `,"time":"${new Date(Date.now()).toISOString()}"`; + module14.exports = { nullTime, epochTime, unixTime, isoTime }; } }); -var require_lib15 = __commonJS({ - "node_modules/.deno/@hapi+podium@5.0.2/node_modules/@hapi/podium/lib/index.js"(exports2) { +var require_quick_format_unescaped = __commonJS({ + "node_modules/.deno/quick-format-unescaped@4.0.4/node_modules/quick-format-unescaped/index.js"(exports2, module14) { "use strict"; - var Hoek = require_lib(); - var Teamwork = require_lib11(); - var Validate = require_lib9(); - var internals = { - schema: { - base: Validate.object({ - name: Validate.string().required(), - clone: Validate.boolean(), - tags: Validate.boolean(), - spread: Validate.boolean(), - channels: Validate.array().items(Validate.string()).single().unique().min(1).cast("set") - }) - } - }; - internals.schema.event = internals.schema.base.keys({ - shared: Validate.boolean() - }); - internals.schema.listener = internals.schema.base.keys({ - listener: Validate.func().required(), - context: Validate.object(), - count: Validate.number().integer().min(1), - filter: { - tags: Validate.array().items(Validate.string()).single().unique().min(1).required(), - all: Validate.boolean() - } - }); - exports2.validate = function(events) { - const normalized = []; - events = [].concat(events); - for (let event of events) { - if (typeof event === "string") { - event = { name: event }; - } - normalized.push(Validate.attempt(event, internals.schema.event, "Invalid event options")); - } - return normalized; - }; - exports2.Podium = class { - /** @type {Map} */ - #listeners = /* @__PURE__ */ new Map(); - constructor(events, options2) { - if (events) { - this.registerEvent(events, options2); - } + function tryStringify(o2) { + try { + return JSON.stringify(o2); + } catch (e2) { + return '"[Circular]"'; } - registerEvent(events, options2) { - events = [].concat(events); - for (let event of events) { - if (typeof event === "string") { - event = { name: event }; - } - if (options2?.validate !== false) { - event = Validate.attempt(event, internals.schema.event, "Invalid event options"); - } - const name = event.name; - if (this.#listeners.has(name)) { - Hoek.assert(event.shared, `Event ${name} exists`); - continue; - } - this.#listeners.set(name, new internals.EventListener(event)); + } + module14.exports = format52; + function format52(f, args, opts) { + var ss = opts && opts.stringify || tryStringify; + var offset = 1; + if (typeof f === "object" && f !== null) { + var len = args.length + offset; + if (len === 1) return f; + var objects = new Array(len); + objects[0] = ss(f); + for (var index = 1; index < len; index++) { + objects[index] = ss(args[index]); } + return objects.join(" "); } - emit(criteria, data) { - let thrownErr; - this.#emitToEachListener(criteria, data, ([err]) => { - thrownErr = thrownErr ?? err; - }); - if (thrownErr) { - throw thrownErr; - } + if (typeof f !== "string") { + return f; } - async gauge(criteria, data) { - const promises = []; - this.#emitToEachListener(criteria, data, ([err, result]) => { - promises.push(err ? Promise.reject(err) : result); - }); - return await Promise.allSettled(promises); - } - #emitToEachListener(criteria, data, fn) { - criteria = internals.criteria(criteria); - const name = criteria.name; - Hoek.assert(name, "Criteria missing event name"); - const event = this.#listeners.get(name); - Hoek.assert(event, `Unknown event ${name}`); - if (!event.handlers) { - return; - } - Hoek.assert(!criteria.channel || typeof criteria.channel === "string", "Invalid channel name"); - Hoek.assert(!criteria.channel || !event.flags.channels || event.flags.channels.has(criteria.channel), `Unknown ${criteria.channel} channel`); - Hoek.assert(!event.flags.spread || Array.isArray(data) || typeof data === "function", "Data must be an array for spread event"); - if (typeof criteria.tags === "string") { - criteria = { ...criteria }; - criteria.tags = { [criteria.tags]: true }; - } - if (criteria.tags && Array.isArray(criteria.tags)) { - const tags = {}; - for (const tag3 of criteria.tags) { - tags[tag3] = true; - } - criteria = { ...criteria }; - criteria.tags = tags; - } - let generated = false; - for (const handler of event.handlers) { - if (handler.channels && !(criteria.channel && handler.channels.has(criteria.channel))) { - continue; - } - if (handler.filter) { - if (!criteria.tags) { - continue; - } - const match = Hoek.intersect(criteria.tags, handler.filter.tags, { first: !handler.filter.all }); - if (!match || handler.filter.all && match.length !== handler.filter.tags.length) { - continue; - } - } - if (handler.count) { - --handler.count; - if (handler.count < 1) { - event.removeListener(handler.listener); - } - } - if (!generated && typeof data === "function") { - data = data(); - generated = true; - } - const update = event.flagged("clone", handler) ? Hoek.clone(data) : data; - const args = event.flagged("spread", handler) && Array.isArray(update) ? update.slice(0) : [update]; - if (event.flagged("tags", handler) && criteria.tags) { - args.push(criteria.tags); - } - try { - if (handler.context) { - fn([null, handler.listener.apply(handler.context, args)]); - } else { - fn([null, handler.listener(...args)]); - } - } catch (err) { - fn([err, null]); + var argLen = args.length; + if (argLen === 0) return f; + var str = ""; + var a = 1 - offset; + var lastPos = -1; + var flen = f && f.length || 0; + for (var i2 = 0; i2 < flen; ) { + if (f.charCodeAt(i2) === 37 && i2 + 1 < flen) { + lastPos = lastPos > -1 ? lastPos : 0; + switch (f.charCodeAt(i2 + 1)) { + case 100: + // 'd' + case 102: + if (a >= argLen) + break; + if (args[a] == null) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += Number(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 105: + if (a >= argLen) + break; + if (args[a] == null) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += Math.floor(Number(args[a])); + lastPos = i2 + 2; + i2++; + break; + case 79: + // 'O' + case 111: + // 'o' + case 106: + if (a >= argLen) + break; + if (args[a] === void 0) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + var type = typeof args[a]; + if (type === "string") { + str += "'" + args[a] + "'"; + lastPos = i2 + 2; + i2++; + break; + } + if (type === "function") { + str += args[a].name || ""; + lastPos = i2 + 2; + i2++; + break; + } + str += ss(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 115: + if (a >= argLen) + break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += String(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 37: + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += "%"; + lastPos = i2 + 2; + i2++; + a--; + break; } + ++a; } + ++i2; } - addListener(criteria, listener, context) { - criteria = internals.criteria(criteria); - criteria.listener = listener; - criteria.context = context; - if (criteria.filter && (typeof criteria.filter === "string" || Array.isArray(criteria.filter))) { - criteria = { ...criteria }; - criteria.filter = { tags: criteria.filter }; - } - criteria = Validate.attempt(criteria, internals.schema.listener, "Invalid event listener options"); - const name = criteria.name; - const event = this.#listeners.get(name); - Hoek.assert(event, `Unknown event ${name}`); - event.addHandler(criteria); - return this; - } - on(criteria, listener, context) { - return this.addListener(criteria, listener, context); - } - once(criteria, listener, context) { - criteria = { ...internals.criteria(criteria), count: 1 }; - if (listener) { - return this.addListener(criteria, listener, context); - } - return new Promise((resolve82) => { - this.addListener(criteria, (...args) => resolve82(args)); - }); - } - few(criteria) { - Hoek.assert(typeof criteria === "object", "Criteria must be an object"); - Hoek.assert(criteria.count, "Criteria must include a count limit"); - const team = new Teamwork.Team({ meetings: criteria.count }); - this.addListener(criteria, (...args) => team.attend(args)); - return team.work; - } - removeListener(name, listener) { - Hoek.assert(this.#listeners.has(name), `Unknown event ${name}`); - Hoek.assert(typeof listener === "function", "Listener must be a function"); - this.#listeners.get(name).removeListener(listener); - return this; - } - off(name, listener) { - return this.removeListener(name, listener); - } - removeAllListeners(name) { - Hoek.assert(this.#listeners.has(name), `Unknown event ${name}`); - this.#listeners.get(name).handlers = null; - return this; - } - hasListeners(name) { - Hoek.assert(this.#listeners.has(name), `Unknown event ${name}`); - return !!this.#listeners.get(name).handlers; - } - }; - internals.EventListener = class { - constructor(flags) { - this.flags = flags; - this.handlers = null; - } - addHandler(handler) { - Hoek.assert(!handler.channels || !this.flags.channels || Hoek.intersect(this.flags.channels, handler.channels).length === handler.channels.size, `Unknown event channels ${handler.channels && [...handler.channels].join(", ")}`); - this.handlers = this.handlers ? [...this.handlers, handler] : [handler]; - } - removeListener(listener) { - const filtered = this.handlers?.filter((item) => item.listener !== listener); - this.handlers = filtered?.length ? filtered : null; - } - flagged(name, handler) { - return handler[name] ?? this.flags[name] ?? false; - } - }; - internals.criteria = function(criteria) { - if (typeof criteria === "string") { - return { name: criteria }; + if (lastPos === -1) + return f; + else if (lastPos < flen) { + str += f.slice(lastPos); } - return criteria; - }; + return str; + } } }); -var require_pending = __commonJS({ - "node_modules/.deno/@hapi+catbox@12.1.1/node_modules/@hapi/catbox/lib/pending.js"(exports2, module14) { +var require_atomic_sleep = __commonJS({ + "node_modules/.deno/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module14) { "use strict"; - exports2 = module14.exports = class { - id = null; - timeout = null; - count = 1; - rule = null; - resolve = null; - reject = null; - constructor(id, rule) { - this.id = id; - this.rule = rule; - this.promise = new Promise((resolve82, reject) => { - this.resolve = resolve82; - this.reject = reject; - }); - } - join() { - ++this.count; - return this.promise; - } - send(err, value, cached2, report) { - clearTimeout(this.timeout); - if (err && !cached2) { - this.reject(err); - return; + if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") { + let sleep = function(ms) { + const valid = ms > 0 && ms < Infinity; + if (valid === false) { + if (typeof ms !== "number" && typeof ms !== "bigint") { + throw TypeError("sleep: ms must be a number"); + } + throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); } - if (!this.rule.getDecoratedValue) { - this.resolve(value); - return; + Atomics.wait(nil, 0, 0, Number(ms)); + }; + const nil = new Int32Array(new SharedArrayBuffer(4)); + module14.exports = sleep; + } else { + let sleep = function(ms) { + const valid = ms > 0 && ms < Infinity; + if (valid === false) { + if (typeof ms !== "number" && typeof ms !== "bigint") { + throw TypeError("sleep: ms must be a number"); + } + throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); } - if (err) { - report.error = err; + const target = Date.now() + Number(ms); + while (target > Date.now()) { } - this.resolve({ value, cached: cached2, report }); - } - setTimeout(fn, timeoutMs) { - clearTimeout(this.timeout); - this.timeout = setTimeout(fn, timeoutMs); - } - }; + }; + module14.exports = sleep; + } } }); -var require_policy = __commonJS({ - "node_modules/.deno/@hapi+catbox@12.1.1/node_modules/@hapi/catbox/lib/policy.js"(exports2, module14) { +var require_sonic_boom = __commonJS({ + "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports2, module14) { "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Podium = require_lib15(); - var Validate = require_lib9(); - var Pending = require_pending(); - var internals = { - day: 24 * 60 * 60 * 1e3, - events: Podium.validate([ - { name: "error", channels: ["generate", "persist"] } - ]) - }; - internals.schema = Validate.object({ - expiresIn: Validate.number().integer().min(1), - expiresAt: Validate.string().regex(/^\d\d?\:\d\d$/), - staleIn: [ - Validate.number().integer().min(1).when("expiresAt", { is: Validate.required(), then: Validate.number().max(864e5 - 1) }), - // One day - 1 (max is inclusive) - Validate.func() - ], - staleTimeout: Validate.number().integer().min(1), - generateFunc: Validate.func(), - generateTimeout: Validate.number().integer().min(1).allow(false), - generateOnReadError: Validate.boolean(), - generateIgnoreWriteError: Validate.boolean(), - dropOnError: Validate.boolean(), - pendingGenerateTimeout: Validate.number().integer().min(1), - getDecoratedValue: Validate.boolean().default(false), - // Ignored external keys (hapi) - privacy: Validate.any(), - cache: Validate.any(), - segment: Validate.any(), - shared: Validate.any() - }).without("expiresIn", "expiresAt").with("staleIn", "generateFunc").with("generateOnReadError", "generateFunc").with("generateIgnoreWriteError", "generateFunc").with("dropOnError", "generateFunc").and("generateFunc", "generateTimeout").and("staleIn", "staleTimeout"); - exports2 = module14.exports = internals.Policy = class { - rule = null; - stats = { - sets: 0, - gets: 0, - hits: 0, - stales: 0, - generates: 0, - errors: 0 - }; - _events = null; - _cache = null; - _segment = null; - _pendings = /* @__PURE__ */ new Map(); - // id -> Pending - _pendingGenerateCall = /* @__PURE__ */ new Map(); - // id -> timer - constructor(options2, cache2, segment) { - this._cache = cache2; - this.rules(options2); - if (cache2) { - const nameErr = cache2.validateSegmentName(segment); - Hoek.assert(nameErr === null, "Invalid segment name: " + segment + (nameErr ? " (" + nameErr.message + ")" : "")); - this._segment = segment; - } - } - get client() { - return this._cache; - } - get events() { - if (!this._events) { - this._events = new Podium.Podium(internals.events, { validate: false }); - } - return this._events; - } - _error(source, error2) { - if (!this._events) { - return; - } - this._events.emit({ name: "error", channel: source }, { source, error: error2 }); - } - rules(options2) { - this.rule = internals.Policy.compile(options2, !!this._cache); - } - async get(key) { - ++this.stats.gets; - if (!key || typeof key === "string") { - key = { id: key, string: true }; - } - let pending = this._pendings.get(key.id); - if (pending !== void 0) { - return pending.join(); - } - pending = new Pending(key.id, this.rule); - this._pendings.set(key.id, pending); - try { - await this._get(pending, key); - } catch (err) { - this._send(key, err); - } - return pending.promise; - } - async _get(pending, key) { - const report = {}; - const timer2 = new Hoek.Bench(); - if (this._cache) { - try { - var cached2 = await this._cache.get({ segment: this._segment, id: key.id }); - } catch (err) { - report.error = err; - ++this.stats.errors; - this._error("persist", err); - } - } - report.msec = timer2.elapsed(); - if (cached2) { - report.stored = cached2.stored; - report.ttl = cached2.ttl; - const staleIn = typeof this.rule.staleIn === "function" ? this.rule.staleIn(cached2.stored, cached2.ttl) : this.rule.staleIn; - cached2.isStale = staleIn ? Date.now() - cached2.stored >= staleIn : false; - report.isStale = cached2.isStale; - if (cached2.isStale) { - ++this.stats.stales; + var fs = __require2("fs"); + var EventEmitter = __require2("events"); + var inherits = __require2("util").inherits; + var path8 = __require2("path"); + var sleep = require_atomic_sleep(); + var BUSY_WRITE_TIMEOUT = 100; + var kEmptyBuffer = Buffer.allocUnsafe(0); + var MAX_WRITE = 16 * 1024; + var kContentModeBuffer = "buffer"; + var kContentModeUtf8 = "utf8"; + function openFile(file, sonic) { + sonic._opening = true; + sonic._writing = true; + sonic._asyncDrainScheduled = false; + function fileOpened(err, fd) { + if (err) { + sonic._reopening = false; + sonic._writing = false; + sonic._opening = false; + if (sonic.sync) { + process.nextTick(() => { + if (sonic.listenerCount("error") > 0) { + sonic.emit("error", err); + } + }); + } else { + sonic.emit("error", err); } - } - if (!this.rule.generateFunc || report.error && !this.rule.generateOnReadError) { - this._send(key, report.error, cached2 ? cached2.item : null, cached2, report); - return; - } - if (cached2 && !cached2.isStale) { - this._send(key, null, cached2.item, cached2, report); - return; - } - return Promise.race([ - pending.promise, - this._generate(pending, key, cached2, report) - ]); - } - _generate(pending, key, cached2, report) { - if (cached2) { - cached2.ttl = cached2.ttl - this.rule.staleTimeout; - } - if (cached2 && cached2.ttl > 0) { - pending.setTimeout(() => this._send(key, null, cached2.item, cached2, report), this.rule.staleTimeout); - } else if (this.rule.generateTimeout) { - pending.setTimeout(() => this._send(key, Boom5.serverUnavailable(), null, null, report), this.rule.generateTimeout); - } - if (this._pendingGenerateCall.has(key.id)) { return; } - ++this.stats.generates; - if (this.rule.pendingGenerateTimeout) { - const timeout = setTimeout(() => this._pendingGenerateCall.delete(key.id), this.rule.pendingGenerateTimeout); - this._pendingGenerateCall.set(key.id, timeout); - } - return this._callGenerateFunc(key, cached2, report); - } - async _callGenerateFunc(key, cached2, report) { - const flags = {}; - try { - var value = await this.rule.generateFunc(key.string ? key.id : key, flags); - } catch (err) { - var generateError = err; - this._error("generate", err); - } - const pendingTimeout = this._pendingGenerateCall.get(key.id); - if (pendingTimeout) { - clearTimeout(pendingTimeout); - this._pendingGenerateCall.delete(key.id); - } - try { - if (flags.ttl === 0 || // null or undefined means use policy - generateError && this.rule.dropOnError) { - await this.drop(key.id); - } else if (!generateError) { - await this.set(key.id, value, flags.ttl); - } - } catch (err) { - var persistError = err; - this._error("persist", err); - } - const error2 = generateError || (this.rule.generateIgnoreWriteError ? null : persistError); - if (cached2 && error2 && !this.rule.dropOnError) { - this._send(key, error2, cached2.item, cached2, report); - return; + const reopening = sonic._reopening; + sonic.fd = fd; + sonic.file = file; + sonic._reopening = false; + sonic._opening = false; + sonic._writing = false; + if (sonic.sync) { + process.nextTick(() => sonic.emit("ready")); + } else { + sonic.emit("ready"); } - this._send(key, error2, value, null, report); - } - _send(key, err, value, cached2, report) { - const pending = this._pendings.get(key.id); - if (!pending) { + if (sonic.destroyed) { return; } - this._pendings.delete(key.id); - pending.send(err, value, cached2, report); - if (report?.isStale !== void 0) { - this.stats.hits = this.stats.hits + pending.count; + if (!sonic._writing && sonic._len > sonic.minLength || sonic._flushPending) { + sonic._actualWrite(); + } else if (reopening) { + process.nextTick(() => sonic.emit("drain")); } } - async set(key, value, ttl) { - ++this.stats.sets; - if (!this._cache) { - return; - } + const flags = sonic.append ? "a" : "w"; + const mode = sonic.mode; + if (sonic.sync) { try { - await this._cache.set({ segment: this._segment, id: internals.id(key) }, value, ttl || internals.Policy.ttl(this.rule)); + if (sonic.mkdir) fs.mkdirSync(path8.dirname(file), { recursive: true }); + const fd = fs.openSync(file, flags, mode); + fileOpened(null, fd); } catch (err) { - ++this.stats.errors; + fileOpened(err); throw err; } + } else if (sonic.mkdir) { + fs.mkdir(path8.dirname(file), { recursive: true }, (err) => { + if (err) return fileOpened(err); + fs.open(file, flags, mode, fileOpened); + }); + } else { + fs.open(file, flags, mode, fileOpened); } - async drop(key) { - if (!this._cache) { - return; - } - try { - await this._cache.drop({ segment: this._segment, id: internals.id(key) }); - return; - } catch (err) { - ++this.stats.errors; - throw err; - } + } + function SonicBoom(opts) { + if (!(this instanceof SonicBoom)) { + return new SonicBoom(opts); + } + let { fd, dest, minLength, maxLength, maxWrite, sync, append = true, mkdir: mkdir4, retryEAGAIN, fsync, contentMode, mode } = opts || {}; + fd = fd || dest; + this._len = 0; + this.fd = -1; + this._bufs = []; + this._lens = []; + this._writing = false; + this._ending = false; + this._reopening = false; + this._asyncDrainScheduled = false; + this._flushPending = false; + this._hwm = Math.max(minLength || 0, 16387); + this.file = null; + this.destroyed = false; + this.minLength = minLength || 0; + this.maxLength = maxLength || 0; + this.maxWrite = maxWrite || MAX_WRITE; + this.sync = sync || false; + this.writable = true; + this._fsync = fsync || false; + this.append = append || false; + this.mode = mode; + this.retryEAGAIN = retryEAGAIN || (() => true); + this.mkdir = mkdir4 || false; + let fsWriteSync; + let fsWrite; + if (contentMode === kContentModeBuffer) { + this._writingBuf = kEmptyBuffer; + this.write = writeBuffer; + this.flush = flushBuffer; + this.flushSync = flushBufferSync; + this._actualWrite = actualWriteBuffer; + fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf); + fsWrite = () => fs.write(this.fd, this._writingBuf, this.release); + } else if (contentMode === void 0 || contentMode === kContentModeUtf8) { + this._writingBuf = ""; + this.write = write; + this.flush = flush; + this.flushSync = flushSync; + this._actualWrite = actualWrite; + fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf, "utf8"); + fsWrite = () => fs.write(this.fd, this._writingBuf, "utf8", this.release); + } else { + throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`); } - ttl(created) { - return internals.Policy.ttl(this.rule, created); + if (typeof fd === "number") { + this.fd = fd; + process.nextTick(() => this.emit("ready")); + } else if (typeof fd === "string") { + openFile(fd, this); + } else { + throw new Error("SonicBoom supports only file descriptors and files"); } - isReady() { - if (!this._cache) { - return false; - } - return this._cache.connection.isReady(); - } - static compile(options2, serverSide) { - const rule = {}; - if (!options2 || !Object.keys(options2).length) { - return rule; - } - options2 = Validate.attempt(options2, internals.schema, "Invalid cache policy configuration"); - const hasExpiresIn = options2.expiresIn !== void 0 && options2.expiresIn !== null; - const hasExpiresAt = options2.expiresAt !== void 0 && options2.expiresAt !== null; - Hoek.assert(!hasExpiresIn || !options2.staleIn || typeof options2.staleIn === "function" || options2.staleIn < options2.expiresIn, "staleIn must be less than expiresIn"); - Hoek.assert(!options2.staleIn || serverSide, "Cannot use stale options without server-side caching"); - Hoek.assert(!options2.staleTimeout || !hasExpiresIn || options2.staleTimeout < options2.expiresIn, "staleTimeout must be less than expiresIn"); - Hoek.assert(!options2.staleTimeout || !hasExpiresIn || typeof options2.staleIn === "function" || options2.staleTimeout < options2.expiresIn - options2.staleIn, "staleTimeout must be less than the delta between expiresIn and staleIn"); - Hoek.assert(!options2.staleTimeout || !options2.pendingGenerateTimeout || options2.staleTimeout < options2.pendingGenerateTimeout, "pendingGenerateTimeout must be greater than staleTimeout if specified"); - if (hasExpiresAt) { - const time3 = /^(\d\d?):(\d\d)$/.exec(options2.expiresAt); - rule.expiresAt = { - hours: parseInt(time3[1], 10), - minutes: parseInt(time3[2], 10) - }; - } else { - rule.expiresIn = options2.expiresIn ?? 0; - } - if (options2.generateFunc) { - rule.generateFunc = options2.generateFunc; - rule.generateTimeout = options2.generateTimeout; - if (options2.staleIn) { - rule.staleIn = options2.staleIn; - rule.staleTimeout = options2.staleTimeout; - } - rule.dropOnError = options2.dropOnError !== void 0 ? options2.dropOnError : true; - rule.pendingGenerateTimeout = options2.pendingGenerateTimeout !== void 0 ? options2.pendingGenerateTimeout : 0; - } - rule.generateOnReadError = options2.generateOnReadError !== void 0 ? options2.generateOnReadError : true; - rule.generateIgnoreWriteError = options2.generateIgnoreWriteError !== void 0 ? options2.generateIgnoreWriteError : true; - rule.getDecoratedValue = options2.getDecoratedValue; - return rule; - } - static ttl(rule, created, now) { - now = now ?? Date.now(); - created = created ?? now; - const age = now - created; - if (age < 0) { - return 0; - } - if (rule.expiresIn) { - return Math.max(rule.expiresIn - age, 0); - } - if (rule.expiresAt) { - if (age > internals.day) { - return 0; - } - const expiresAt = new Date(created); - expiresAt.setHours(rule.expiresAt.hours); - expiresAt.setMinutes(rule.expiresAt.minutes); - expiresAt.setSeconds(0); - expiresAt.setMilliseconds(0); - let expires = expiresAt.getTime(); - if (expires <= created) { - expires = expires + internals.day; - } - if (now >= expires) { - return 0; - } - return expires - now; - } - return 0; + if (this.minLength >= this.maxWrite) { + throw new Error(`minLength should be smaller than maxWrite (${this.maxWrite})`); } - }; - internals.id = function(key) { - return key && typeof key === "object" ? key.id : key; - }; - } -}); -var require_lib16 = __commonJS({ - "node_modules/.deno/@hapi+catbox@12.1.1/node_modules/@hapi/catbox/lib/index.js"(exports2) { - "use strict"; - var Client = require_client2(); - var Policy = require_policy(); - exports2.Client = Client; - exports2.Policy = exports2.policy = Policy; - } -}); -var require_lib17 = __commonJS({ - "node_modules/.deno/@hapi+catbox-memory@6.0.2/node_modules/@hapi/catbox-memory/lib/index.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var internals = { - maxTimer: 2147483647, - // 2 ^ 31 - 1 - entrySize: 144 - // Approximate cache entry size without value: 144 bytes - }; - internals.defaults = { - maxByteSize: 100 * 1024 * 1024, - // 100MB - minCleanupIntervalMsec: 1e3, - cloneBuffersOnGet: false - }; - exports2.Engine = class CatboxMemoryEngine { - constructor(options2 = {}) { - Hoek.assert(options2.maxByteSize === void 0 || options2.maxByteSize >= 0, "Invalid cache maxByteSize value"); - Hoek.assert(options2.allowMixedContent === void 0, "allowMixedContent no longer supported"); - Hoek.assert(options2.minCleanupIntervalMsec === void 0 || options2.minCleanupIntervalMsec < internals.maxTimer, "Invalid cache minCleanupIntervalMsec value"); - Hoek.assert(options2.cloneBuffersOnGet === void 0 || typeof options2.cloneBuffersOnGet === "boolean", "Invalid cloneBuffersOnGet value"); - this.settings = Hoek.applyToDefaults(internals.defaults, options2); - this.cache = null; - this._timer = null; - this._timerDue = null; - } - start() { - if (!this.cache) { - this.cache = /* @__PURE__ */ new Map(); - this.byteSize = 0; - } - } - _scheduleCleanup(msec) { - const cleanup = () => { - this._timer = null; - this._timerDue = null; - const now2 = Date.now(); - let next = Infinity; - for (const [, segment] of this.cache) { - for (const [id, envelope] of segment) { - const ttl = envelope.stored + envelope.ttl - now2; - if (ttl <= 0) { - segment.delete(id); - this.byteSize -= envelope.byteSize; - } else { - next = Math.min(next, ttl); + this.release = (err, n) => { + if (err) { + if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) { + if (this.sync) { + try { + sleep(BUSY_WRITE_TIMEOUT); + this.release(void 0, 0); + } catch (err2) { + this.release(err2); } + } else { + setTimeout(fsWrite, BUSY_WRITE_TIMEOUT); } + } else { + this._writing = false; + this.emit("error", err); } - if (next !== Infinity) { - this._scheduleCleanup(next); - } - }; - const now = Date.now(); - const timeout = Math.min(Math.max(this.settings.minCleanupIntervalMsec, msec), internals.maxTimer); - if (this._timer) { - if (this._timerDue - now < msec) { - return; - } - clearTimeout(this._timer); + return; } - this._timerDue = now + timeout; - this._timer = setTimeout(cleanup, timeout); - } - stop() { - clearTimeout(this._timer); - this._timer = null; - this._timerDue = null; - this.cache = null; - this.byteSize = 0; - } - isReady() { - return !!this.cache; - } - validateSegmentName(name) { - if (!name) { - throw new Boom5.Boom("Empty string"); - } - if (name.indexOf("\0") !== -1) { - throw new Boom5.Boom("Includes null character"); - } - return null; - } - get(key) { - if (!this.cache) { - throw new Boom5.Boom("Connection not started"); - } - const segment = this.cache.get(key.segment); - if (!segment) { - return null; - } - const envelope = segment.get(key.id); - if (!envelope) { - return null; + this.emit("write", n); + const releasedBufObj = releaseWritingBuf(this._writingBuf, this._len, n); + this._len = releasedBufObj.len; + this._writingBuf = releasedBufObj.writingBuf; + if (this._writingBuf.length) { + if (!this.sync) { + fsWrite(); + return; + } + try { + do { + const n2 = fsWriteSync(); + const releasedBufObj2 = releaseWritingBuf(this._writingBuf, this._len, n2); + this._len = releasedBufObj2.len; + this._writingBuf = releasedBufObj2.writingBuf; + } while (this._writingBuf.length); + } catch (err2) { + this.release(err2); + return; + } } - if (envelope.stored + envelope.ttl < Date.now()) { - this.drop(key); - return null; + if (this._fsync) { + fs.fsyncSync(this.fd); } - let item = null; - if (Buffer.isBuffer(envelope.item)) { - item = envelope.item; - if (this.settings.cloneBuffersOnGet) { - const copy2 = Buffer.alloc(item.length); - item.copy(copy2); - item = copy2; + const len = this._len; + if (this._reopening) { + this._writing = false; + this._reopening = false; + this.reopen(); + } else if (len > this.minLength) { + this._actualWrite(); + } else if (this._ending) { + if (len > 0) { + this._actualWrite(); + } else { + this._writing = false; + actualClose(this); } } else { - try { - item = JSON.parse(envelope.item); - } catch (err) { - throw new Boom5.Boom("Bad value content"); + this._writing = false; + if (this.sync) { + if (!this._asyncDrainScheduled) { + this._asyncDrainScheduled = true; + process.nextTick(emitDrain, this); + } + } else { + this.emit("drain"); } } - const result = { - item, - stored: envelope.stored, - ttl: envelope.ttl - }; - return result; + }; + this.on("newListener", function(name) { + if (name === "drain") { + this._asyncDrainScheduled = false; + } + }); + } + function releaseWritingBuf(writingBuf, len, n) { + if (typeof writingBuf === "string" && Buffer.byteLength(writingBuf) !== n) { + n = Buffer.from(writingBuf).subarray(0, n).toString().length; + } + len = Math.max(len - n, 0); + writingBuf = writingBuf.slice(n); + return { writingBuf, len }; + } + function emitDrain(sonic) { + const hasListeners = sonic.listenerCount("drain") > 0; + if (!hasListeners) return; + sonic._asyncDrainScheduled = false; + sonic.emit("drain"); + } + inherits(SonicBoom, EventEmitter); + function mergeBuf(bufs, len) { + if (bufs.length === 0) { + return kEmptyBuffer; + } + if (bufs.length === 1) { + return bufs[0]; + } + return Buffer.concat(bufs, len); + } + function write(data) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + const len = this._len + data.length; + const bufs = this._bufs; + if (this.maxLength && len > this.maxLength) { + this.emit("drop", data); + return this._len < this._hwm; + } + if (bufs.length === 0 || bufs[bufs.length - 1].length + data.length > this.maxWrite) { + bufs.push("" + data); + } else { + bufs[bufs.length - 1] += data; + } + this._len = len; + if (!this._writing && this._len >= this.minLength) { + this._actualWrite(); + } + return this._len < this._hwm; + } + function writeBuffer(data) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + const len = this._len + data.length; + const bufs = this._bufs; + const lens = this._lens; + if (this.maxLength && len > this.maxLength) { + this.emit("drop", data); + return this._len < this._hwm; + } + if (bufs.length === 0 || lens[lens.length - 1] + data.length > this.maxWrite) { + bufs.push([data]); + lens.push(data.length); + } else { + bufs[bufs.length - 1].push(data); + lens[lens.length - 1] += data.length; + } + this._len = len; + if (!this._writing && this._len >= this.minLength) { + this._actualWrite(); } - set(key, value, ttl) { - if (!this.cache) { - throw new Boom5.Boom("Connection not started"); + return this._len < this._hwm; + } + function callFlushCallbackOnDrain(cb) { + this._flushPending = true; + const onDrain = () => { + if (!this._fsync) { + fs.fsync(this.fd, (err) => { + this._flushPending = false; + cb(err); + }); + } else { + this._flushPending = false; + cb(); } - const envelope = new internals.MemoryCacheEntry(key, value, ttl); - let segment = this.cache.get(key.segment); - if (!segment) { - segment = /* @__PURE__ */ new Map(); - this.cache.set(key.segment, segment); + this.off("error", onError); + }; + const onError = (err) => { + this._flushPending = false; + cb(err); + this.off("drain", onDrain); + }; + this.once("drain", onDrain); + this.once("error", onError); + } + function flush(cb) { + if (cb != null && typeof cb !== "function") { + throw new Error("flush cb must be a function"); + } + if (this.destroyed) { + const error2 = new Error("SonicBoom destroyed"); + if (cb) { + cb(error2); + return; } - const cachedItem = segment.get(key.id); - if (cachedItem) { - this.byteSize -= cachedItem.byteSize; + throw error2; + } + if (this.minLength <= 0) { + cb?.(); + return; + } + if (cb) { + callFlushCallbackOnDrain.call(this, cb); + } + if (this._writing) { + return; + } + if (this._bufs.length === 0) { + this._bufs.push(""); + } + this._actualWrite(); + } + function flushBuffer(cb) { + if (cb != null && typeof cb !== "function") { + throw new Error("flush cb must be a function"); + } + if (this.destroyed) { + const error2 = new Error("SonicBoom destroyed"); + if (cb) { + cb(error2); + return; } - if (this.settings.maxByteSize && this.byteSize + envelope.byteSize > this.settings.maxByteSize) { - throw new Boom5.Boom("Cache size limit reached"); + throw error2; + } + if (this.minLength <= 0) { + cb?.(); + return; + } + if (cb) { + callFlushCallbackOnDrain.call(this, cb); + } + if (this._writing) { + return; + } + if (this._bufs.length === 0) { + this._bufs.push([]); + this._lens.push(0); + } + this._actualWrite(); + } + SonicBoom.prototype.reopen = function(file) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + if (this._opening) { + this.once("ready", () => { + this.reopen(file); + }); + return; + } + if (this._ending) { + return; + } + if (!this.file) { + throw new Error("Unable to reopen a file descriptor, you must pass a file to SonicBoom"); + } + if (file) { + this.file = file; + } + this._reopening = true; + if (this._writing) { + return; + } + const fd = this.fd; + this.once("ready", () => { + if (fd !== this.fd) { + fs.close(fd, (err) => { + if (err) { + return this.emit("error", err); + } + }); } - this._scheduleCleanup(ttl); - segment.set(key.id, envelope); - this.byteSize += envelope.byteSize; + }); + openFile(this.file, this); + }; + SonicBoom.prototype.end = function() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + if (this._opening) { + this.once("ready", () => { + this.end(); + }); + return; + } + if (this._ending) { + return; + } + this._ending = true; + if (this._writing) { + return; } - drop(key) { - if (!this.cache) { - throw new Boom5.Boom("Connection not started"); + if (this._len > 0 && this.fd >= 0) { + this._actualWrite(); + } else { + actualClose(this); + } + }; + function flushSync() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + if (this.fd < 0) { + throw new Error("sonic boom is not ready yet"); + } + if (!this._writing && this._writingBuf.length > 0) { + this._bufs.unshift(this._writingBuf); + this._writingBuf = ""; + } + let buf2 = ""; + while (this._bufs.length || buf2) { + if (buf2.length <= 0) { + buf2 = this._bufs[0]; } - const segment = this.cache.get(key.segment); - if (segment) { - const item = segment.get(key.id); - if (item) { - this.byteSize -= item.byteSize; - segment.delete(key.id); + try { + const n = fs.writeSync(this.fd, buf2, "utf8"); + const releasedBufObj = releaseWritingBuf(buf2, this._len, n); + buf2 = releasedBufObj.writingBuf; + this._len = releasedBufObj.len; + if (buf2.length <= 0) { + this._bufs.shift(); + } + } catch (err) { + const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; + if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { + throw err; } + sleep(BUSY_WRITE_TIMEOUT); } } - }; - internals.MemoryCacheEntry = class { - constructor(key, value, ttl) { - let valueByteSize = 0; - if (Buffer.isBuffer(value)) { - this.item = Buffer.alloc(value.length); - value.copy(this.item); - valueByteSize = this.item.length; - } else { - this.item = JSON.stringify(value); - valueByteSize = Buffer.byteLength(this.item); - } - this.stored = Date.now(); - this.ttl = ttl; - this.byteSize = internals.entrySize + valueByteSize + Buffer.byteLength(key.segment) + Buffer.byteLength(key.id); - this.timeoutId = null; - } - }; - } -}); -var require_lib18 = __commonJS({ - "node_modules/.deno/@hapi+heavy@8.0.1/node_modules/@hapi/heavy/lib/index.js"(exports2) { - "use strict"; - var PerfHooks = __require2("perf_hooks"); - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Validate = require_lib9(); - var internals = {}; - internals.schema = Validate.object({ - sampleInterval: Validate.number().min(0), - maxHeapUsedBytes: Validate.number().min(0), - maxEventLoopDelay: Validate.number().min(0), - maxEventLoopUtilization: Validate.number().min(0), - maxRssBytes: Validate.number().min(0) - }).unknown(); - internals.defaults = { - sampleInterval: 0, - // Frequency of load sampling in milliseconds (zero is no sampling) - maxHeapUsedBytes: 0, - // Reject requests when V8 heap is over size in bytes (zero is no max) - maxRssBytes: 0, - // Reject requests when process RSS is over size in bytes (zero is no max) - maxEventLoopDelay: 0, - // Milliseconds of delay after which requests are rejected (zero is no max) - maxEventLoopUtilization: 0 - // Max event loop utilization value after which requests are rejected (zero is no max) - }; - exports2.Heavy = class Heavy { - constructor(options2) { - options2 = options2 || {}; - Validate.assert(options2, internals.schema, "Invalid load monitoring options"); - this.settings = Hoek.applyToDefaults(internals.defaults, options2); - Hoek.assert(this.settings.sampleInterval || !this.settings.maxEventLoopDelay && !this.settings.maxHeapUsedBytes && !this.settings.maxRssBytes && !this.settings.maxEventLoopUtilization, "Load sample interval must be set to enable load limits"); - this._eventLoopTimer = null; - this._eventLoopUtilization = PerfHooks.performance.eventLoopUtilization(); - this._loadBench = new Hoek.Bench(); - this.load = { - eventLoopDelay: 0, - eventLoopUtilization: 0, - heapUsed: 0, - rss: 0 - }; + try { + fs.fsyncSync(this.fd); + } catch { } - start() { - if (!this.settings.sampleInterval) { - return; + } + function flushBufferSync() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + if (this.fd < 0) { + throw new Error("sonic boom is not ready yet"); + } + if (!this._writing && this._writingBuf.length > 0) { + this._bufs.unshift([this._writingBuf]); + this._writingBuf = kEmptyBuffer; + } + let buf2 = kEmptyBuffer; + while (this._bufs.length || buf2.length) { + if (buf2.length <= 0) { + buf2 = mergeBuf(this._bufs[0], this._lens[0]); + } + try { + const n = fs.writeSync(this.fd, buf2); + buf2 = buf2.subarray(n); + this._len = Math.max(this._len - n, 0); + if (buf2.length <= 0) { + this._bufs.shift(); + this._lens.shift(); + } + } catch (err) { + const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; + if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { + throw err; + } + sleep(BUSY_WRITE_TIMEOUT); } - const loopSample = () => { - this._loadBench.reset(); - const measure = () => { - const mem = process.memoryUsage(); - this._eventLoopUtilization = PerfHooks.performance.eventLoopUtilization(this._eventLoopUtilization); - this.load.eventLoopDelay = this._loadBench.elapsed() - this.settings.sampleInterval; - this.load.eventLoopUtilization = this._eventLoopUtilization.utilization; - this.load.heapUsed = mem.heapUsed; - this.load.rss = mem.rss; - loopSample(); - }; - this._eventLoopTimer = setTimeout(measure, this.settings.sampleInterval); - }; - loopSample(); } - stop() { - clearTimeout(this._eventLoopTimer); - this._eventLoopTimer = null; + } + SonicBoom.prototype.destroy = function() { + if (this.destroyed) { + return; } - check() { - if (!this.settings.sampleInterval) { - return; + actualClose(this); + }; + function actualWrite() { + const release = this.release; + this._writing = true; + this._writingBuf = this._writingBuf || this._bufs.shift() || ""; + if (this.sync) { + try { + const written = fs.writeSync(this.fd, this._writingBuf, "utf8"); + release(null, written); + } catch (err) { + release(err); } - Hoek.assert(this._eventLoopTimer, "Cannot check load when sampler is not started"); - const elapsed = this._loadBench.elapsed(); - const load = this.load; - if (elapsed > this.settings.sampleInterval) { - this._eventLoopUtilization = PerfHooks.performance.eventLoopUtilization(this._eventLoopUtilization); - load.eventLoopDelay = Math.max(load.eventLoopDelay, elapsed - this.settings.sampleInterval); - load.eventLoopUtilization = this._eventLoopUtilization.utilization; + } else { + fs.write(this.fd, this._writingBuf, "utf8", release); + } + } + function actualWriteBuffer() { + const release = this.release; + this._writing = true; + this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift()); + if (this.sync) { + try { + const written = fs.writeSync(this.fd, this._writingBuf); + release(null, written); + } catch (err) { + release(err); } - if (this.settings.maxEventLoopDelay && load.eventLoopDelay > this.settings.maxEventLoopDelay) { - throw Boom5.serverUnavailable("Server under heavy load (event loop)", load); + } else { + fs.write(this.fd, this._writingBuf, release); + } + } + function actualClose(sonic) { + if (sonic.fd === -1) { + sonic.once("ready", actualClose.bind(null, sonic)); + return; + } + sonic.destroyed = true; + sonic._bufs = []; + sonic._lens = []; + fs.fsync(sonic.fd, closeWrapped); + function closeWrapped() { + if (sonic.fd !== 1 && sonic.fd !== 2) { + fs.close(sonic.fd, done); + } else { + done(); } - if (this.settings.maxEventLoopUtilization && load.eventLoopUtilization > this.settings.maxEventLoopUtilization) { - throw Boom5.serverUnavailable("Server under heavy load (event loop utilization)", load); + } + function done(err) { + if (err) { + sonic.emit("error", err); + return; } - if (this.settings.maxHeapUsedBytes && load.heapUsed > this.settings.maxHeapUsedBytes) { - throw Boom5.serverUnavailable("Server under heavy load (heap)", load); + if (sonic._ending && !sonic._writing) { + sonic.emit("finish"); } - if (this.settings.maxRssBytes && load.rss > this.settings.maxRssBytes) { - throw Boom5.serverUnavailable("Server under heavy load (rss)", load); + sonic.emit("close"); + } + } + SonicBoom.SonicBoom = SonicBoom; + SonicBoom.default = SonicBoom; + module14.exports = SonicBoom; + } +}); +var require_on_exit_leak_free = __commonJS({ + "node_modules/.deno/on-exit-leak-free@2.1.2/node_modules/on-exit-leak-free/index.js"(exports2, module14) { + "use strict"; + var refs = { + exit: [], + beforeExit: [] + }; + var functions = { + exit: onExit, + beforeExit: onBeforeExit + }; + var registry2; + function ensureRegistry() { + if (registry2 === void 0) { + registry2 = new FinalizationRegistry(clear); + } + } + function install(event) { + if (refs[event].length > 0) { + return; + } + process.on(event, functions[event]); + } + function uninstall(event) { + if (refs[event].length > 0) { + return; + } + process.removeListener(event, functions[event]); + if (refs.exit.length === 0 && refs.beforeExit.length === 0) { + registry2 = void 0; + } + } + function onExit() { + callRefs("exit"); + } + function onBeforeExit() { + callRefs("beforeExit"); + } + function callRefs(event) { + for (const ref of refs[event]) { + const obj = ref.deref(); + const fn = ref.fn; + if (obj !== void 0) { + fn(obj, event); } } + refs[event] = []; + } + function clear(ref) { + for (const event of ["exit", "beforeExit"]) { + const index = refs[event].indexOf(ref); + refs[event].splice(index, index + 1); + uninstall(event); + } + } + function _register(event, obj, fn) { + if (obj === void 0) { + throw new Error("the object can't be undefined"); + } + install(event); + const ref = new WeakRef(obj); + ref.fn = fn; + ensureRegistry(); + registry2.register(obj, ref); + refs[event].push(ref); + } + function register2(obj, fn) { + _register("exit", obj, fn); + } + function registerBeforeExit(obj, fn) { + _register("beforeExit", obj, fn); + } + function unregister(obj) { + if (registry2 === void 0) { + return; + } + registry2.unregister(obj); + for (const event of ["exit", "beforeExit"]) { + refs[event] = refs[event].filter((ref) => { + const _obj = ref.deref(); + return _obj && _obj !== obj; + }); + uninstall(event); + } + } + module14.exports = { + register: register2, + registerBeforeExit, + unregister }; } }); -var require_db = __commonJS({ - "node_modules/.deno/mime-db@1.54.0/node_modules/mime-db/db.json"(exports2, module14) { +var require_package3 = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/package.json"(exports2, module14) { module14.exports = { - "application/1d-interleaved-parityfec": { - source: "iana" - }, - "application/3gpdash-qoe-report+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/3gpp-ims+xml": { - source: "iana", - compressible: true - }, - "application/3gpphal+json": { - source: "iana", - compressible: true - }, - "application/3gpphalforms+json": { - source: "iana", - compressible: true + name: "thread-stream", + version: "2.7.0", + description: "A streaming way to send data to a Node.js Worker Thread", + main: "index.js", + types: "index.d.ts", + dependencies: { + "real-require": "^0.2.0" }, - "application/a2l": { - source: "iana" + devDependencies: { + "@types/node": "^20.1.0", + "@types/tap": "^15.0.0", + "@yao-pkg/pkg": "^5.11.5", + desm: "^1.3.0", + fastbench: "^1.0.1", + husky: "^9.0.6", + "pino-elasticsearch": "^8.0.0", + "sonic-boom": "^3.0.0", + standard: "^17.0.0", + tap: "^16.2.0", + "ts-node": "^10.8.0", + typescript: "^5.3.2", + "why-is-node-running": "^2.2.2" }, - "application/ace+cbor": { - source: "iana" - }, - "application/ace+json": { - source: "iana", - compressible: true - }, - "application/ace-groupcomm+cbor": { - source: "iana" - }, - "application/ace-trl+cbor": { - source: "iana" - }, - "application/activemessage": { - source: "iana" - }, - "application/activity+json": { - source: "iana", - compressible: true - }, - "application/aif+cbor": { - source: "iana" - }, - "application/aif+json": { - source: "iana", - compressible: true - }, - "application/alto-cdni+json": { - source: "iana", - compressible: true - }, - "application/alto-cdnifilter+json": { - source: "iana", - compressible: true - }, - "application/alto-costmap+json": { - source: "iana", - compressible: true - }, - "application/alto-costmapfilter+json": { - source: "iana", - compressible: true - }, - "application/alto-directory+json": { - source: "iana", - compressible: true - }, - "application/alto-endpointcost+json": { - source: "iana", - compressible: true - }, - "application/alto-endpointcostparams+json": { - source: "iana", - compressible: true - }, - "application/alto-endpointprop+json": { - source: "iana", - compressible: true - }, - "application/alto-endpointpropparams+json": { - source: "iana", - compressible: true - }, - "application/alto-error+json": { - source: "iana", - compressible: true - }, - "application/alto-networkmap+json": { - source: "iana", - compressible: true - }, - "application/alto-networkmapfilter+json": { - source: "iana", - compressible: true - }, - "application/alto-propmap+json": { - source: "iana", - compressible: true - }, - "application/alto-propmapparams+json": { - source: "iana", - compressible: true - }, - "application/alto-tips+json": { - source: "iana", - compressible: true - }, - "application/alto-tipsparams+json": { - source: "iana", - compressible: true - }, - "application/alto-updatestreamcontrol+json": { - source: "iana", - compressible: true - }, - "application/alto-updatestreamparams+json": { - source: "iana", - compressible: true - }, - "application/aml": { - source: "iana" - }, - "application/andrew-inset": { - source: "iana", - extensions: ["ez"] - }, - "application/appinstaller": { - compressible: false, - extensions: ["appinstaller"] - }, - "application/applefile": { - source: "iana" - }, - "application/applixware": { - source: "apache", - extensions: ["aw"] - }, - "application/appx": { - compressible: false, - extensions: ["appx"] - }, - "application/appxbundle": { - compressible: false, - extensions: ["appxbundle"] - }, - "application/at+jwt": { - source: "iana" - }, - "application/atf": { - source: "iana" - }, - "application/atfx": { - source: "iana" - }, - "application/atom+xml": { - source: "iana", - compressible: true, - extensions: ["atom"] - }, - "application/atomcat+xml": { - source: "iana", - compressible: true, - extensions: ["atomcat"] - }, - "application/atomdeleted+xml": { - source: "iana", - compressible: true, - extensions: ["atomdeleted"] - }, - "application/atomicmail": { - source: "iana" - }, - "application/atomsvc+xml": { - source: "iana", - compressible: true, - extensions: ["atomsvc"] - }, - "application/atsc-dwd+xml": { - source: "iana", - compressible: true, - extensions: ["dwd"] - }, - "application/atsc-dynamic-event-message": { - source: "iana" - }, - "application/atsc-held+xml": { - source: "iana", - compressible: true, - extensions: ["held"] - }, - "application/atsc-rdt+json": { - source: "iana", - compressible: true - }, - "application/atsc-rsat+xml": { - source: "iana", - compressible: true, - extensions: ["rsat"] - }, - "application/atxml": { - source: "iana" - }, - "application/auth-policy+xml": { - source: "iana", - compressible: true - }, - "application/automationml-aml+xml": { - source: "iana", - compressible: true, - extensions: ["aml"] - }, - "application/automationml-amlx+zip": { - source: "iana", - compressible: false, - extensions: ["amlx"] - }, - "application/bacnet-xdd+zip": { - source: "iana", - compressible: false - }, - "application/batch-smtp": { - source: "iana" - }, - "application/bdoc": { - compressible: false, - extensions: ["bdoc"] - }, - "application/beep+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/bufr": { - source: "iana" - }, - "application/c2pa": { - source: "iana" - }, - "application/calendar+json": { - source: "iana", - compressible: true - }, - "application/calendar+xml": { - source: "iana", - compressible: true, - extensions: ["xcs"] - }, - "application/call-completion": { - source: "iana" - }, - "application/cals-1840": { - source: "iana" - }, - "application/captive+json": { - source: "iana", - compressible: true - }, - "application/cbor": { - source: "iana" - }, - "application/cbor-seq": { - source: "iana" - }, - "application/cccex": { - source: "iana" - }, - "application/ccmp+xml": { - source: "iana", - compressible: true - }, - "application/ccxml+xml": { - source: "iana", - compressible: true, - extensions: ["ccxml"] - }, - "application/cda+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/cdfx+xml": { - source: "iana", - compressible: true, - extensions: ["cdfx"] - }, - "application/cdmi-capability": { - source: "iana", - extensions: ["cdmia"] - }, - "application/cdmi-container": { - source: "iana", - extensions: ["cdmic"] - }, - "application/cdmi-domain": { - source: "iana", - extensions: ["cdmid"] - }, - "application/cdmi-object": { - source: "iana", - extensions: ["cdmio"] - }, - "application/cdmi-queue": { - source: "iana", - extensions: ["cdmiq"] - }, - "application/cdni": { - source: "iana" - }, - "application/ce+cbor": { - source: "iana" - }, - "application/cea": { - source: "iana" - }, - "application/cea-2018+xml": { - source: "iana", - compressible: true - }, - "application/cellml+xml": { - source: "iana", - compressible: true - }, - "application/cfw": { - source: "iana" - }, - "application/cid-edhoc+cbor-seq": { - source: "iana" - }, - "application/city+json": { - source: "iana", - compressible: true - }, - "application/city+json-seq": { - source: "iana" - }, - "application/clr": { - source: "iana" - }, - "application/clue+xml": { - source: "iana", - compressible: true - }, - "application/clue_info+xml": { - source: "iana", - compressible: true - }, - "application/cms": { - source: "iana" - }, - "application/cnrp+xml": { - source: "iana", - compressible: true - }, - "application/coap-eap": { - source: "iana" - }, - "application/coap-group+json": { - source: "iana", - compressible: true - }, - "application/coap-payload": { - source: "iana" - }, - "application/commonground": { - source: "iana" - }, - "application/concise-problem-details+cbor": { - source: "iana" - }, - "application/conference-info+xml": { - source: "iana", - compressible: true - }, - "application/cose": { - source: "iana" - }, - "application/cose-key": { - source: "iana" - }, - "application/cose-key-set": { - source: "iana" - }, - "application/cose-x509": { - source: "iana" - }, - "application/cpl+xml": { - source: "iana", - compressible: true, - extensions: ["cpl"] - }, - "application/csrattrs": { - source: "iana" - }, - "application/csta+xml": { - source: "iana", - compressible: true - }, - "application/cstadata+xml": { - source: "iana", - compressible: true - }, - "application/csvm+json": { - source: "iana", - compressible: true - }, - "application/cu-seeme": { - source: "apache", - extensions: ["cu"] - }, - "application/cwl": { - source: "iana", - extensions: ["cwl"] - }, - "application/cwl+json": { - source: "iana", - compressible: true - }, - "application/cwl+yaml": { - source: "iana" - }, - "application/cwt": { - source: "iana" - }, - "application/cybercash": { - source: "iana" - }, - "application/dart": { - compressible: true - }, - "application/dash+xml": { - source: "iana", - compressible: true, - extensions: ["mpd"] - }, - "application/dash-patch+xml": { - source: "iana", - compressible: true, - extensions: ["mpp"] - }, - "application/dashdelta": { - source: "iana" - }, - "application/davmount+xml": { - source: "iana", - compressible: true, - extensions: ["davmount"] - }, - "application/dca-rft": { - source: "iana" - }, - "application/dcd": { - source: "iana" - }, - "application/dec-dx": { - source: "iana" - }, - "application/dialog-info+xml": { - source: "iana", - compressible: true - }, - "application/dicom": { - source: "iana", - extensions: ["dcm"] - }, - "application/dicom+json": { - source: "iana", - compressible: true - }, - "application/dicom+xml": { - source: "iana", - compressible: true - }, - "application/dii": { - source: "iana" - }, - "application/dit": { - source: "iana" - }, - "application/dns": { - source: "iana" - }, - "application/dns+json": { - source: "iana", - compressible: true - }, - "application/dns-message": { - source: "iana" - }, - "application/docbook+xml": { - source: "apache", - compressible: true, - extensions: ["dbk"] - }, - "application/dots+cbor": { - source: "iana" - }, - "application/dpop+jwt": { - source: "iana" - }, - "application/dskpp+xml": { - source: "iana", - compressible: true - }, - "application/dssc+der": { - source: "iana", - extensions: ["dssc"] - }, - "application/dssc+xml": { - source: "iana", - compressible: true, - extensions: ["xdssc"] - }, - "application/dvcs": { - source: "iana" - }, - "application/eat+cwt": { - source: "iana" - }, - "application/eat+jwt": { - source: "iana" - }, - "application/eat-bun+cbor": { - source: "iana" - }, - "application/eat-bun+json": { - source: "iana", - compressible: true - }, - "application/eat-ucs+cbor": { - source: "iana" - }, - "application/eat-ucs+json": { - source: "iana", - compressible: true - }, - "application/ecmascript": { - source: "apache", - compressible: true, - extensions: ["ecma"] - }, - "application/edhoc+cbor-seq": { - source: "iana" - }, - "application/edi-consent": { - source: "iana" - }, - "application/edi-x12": { - source: "iana", - compressible: false - }, - "application/edifact": { - source: "iana", - compressible: false - }, - "application/efi": { - source: "iana" - }, - "application/elm+json": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/elm+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.cap+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/emergencycalldata.comment+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.control+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.deviceinfo+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.ecall.msd": { - source: "iana" - }, - "application/emergencycalldata.legacyesn+json": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.providerinfo+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.serviceinfo+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.subscriberinfo+xml": { - source: "iana", - compressible: true - }, - "application/emergencycalldata.veds+xml": { - source: "iana", - compressible: true - }, - "application/emma+xml": { - source: "iana", - compressible: true, - extensions: ["emma"] - }, - "application/emotionml+xml": { - source: "iana", - compressible: true, - extensions: ["emotionml"] - }, - "application/encaprtp": { - source: "iana" - }, - "application/entity-statement+jwt": { - source: "iana" - }, - "application/epp+xml": { - source: "iana", - compressible: true - }, - "application/epub+zip": { - source: "iana", - compressible: false, - extensions: ["epub"] - }, - "application/eshop": { - source: "iana" - }, - "application/exi": { - source: "iana", - extensions: ["exi"] - }, - "application/expect-ct-report+json": { - source: "iana", - compressible: true - }, - "application/express": { - source: "iana", - extensions: ["exp"] - }, - "application/fastinfoset": { - source: "iana" - }, - "application/fastsoap": { - source: "iana" - }, - "application/fdf": { - source: "iana", - extensions: ["fdf"] - }, - "application/fdt+xml": { - source: "iana", - compressible: true, - extensions: ["fdt"] - }, - "application/fhir+json": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/fhir+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/fido.trusted-apps+json": { - compressible: true - }, - "application/fits": { - source: "iana" - }, - "application/flexfec": { - source: "iana" - }, - "application/font-sfnt": { - source: "iana" - }, - "application/font-tdpfr": { - source: "iana", - extensions: ["pfr"] - }, - "application/font-woff": { - source: "iana", - compressible: false - }, - "application/framework-attributes+xml": { - source: "iana", - compressible: true - }, - "application/geo+json": { - source: "iana", - compressible: true, - extensions: ["geojson"] - }, - "application/geo+json-seq": { - source: "iana" - }, - "application/geopackage+sqlite3": { - source: "iana" - }, - "application/geopose+json": { - source: "iana", - compressible: true - }, - "application/geoxacml+json": { - source: "iana", - compressible: true - }, - "application/geoxacml+xml": { - source: "iana", - compressible: true - }, - "application/gltf-buffer": { - source: "iana" - }, - "application/gml+xml": { - source: "iana", - compressible: true, - extensions: ["gml"] - }, - "application/gnap-binding-jws": { - source: "iana" - }, - "application/gnap-binding-jwsd": { - source: "iana" - }, - "application/gnap-binding-rotation-jws": { - source: "iana" - }, - "application/gnap-binding-rotation-jwsd": { - source: "iana" - }, - "application/gpx+xml": { - source: "apache", - compressible: true, - extensions: ["gpx"] - }, - "application/grib": { - source: "iana" - }, - "application/gxf": { - source: "apache", - extensions: ["gxf"] - }, - "application/gzip": { - source: "iana", - compressible: false, - extensions: ["gz"] - }, - "application/h224": { - source: "iana" - }, - "application/held+xml": { - source: "iana", - compressible: true - }, - "application/hjson": { - extensions: ["hjson"] - }, - "application/hl7v2+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/http": { - source: "iana" - }, - "application/hyperstudio": { - source: "iana", - extensions: ["stk"] - }, - "application/ibe-key-request+xml": { - source: "iana", - compressible: true - }, - "application/ibe-pkg-reply+xml": { - source: "iana", - compressible: true - }, - "application/ibe-pp-data": { - source: "iana" - }, - "application/iges": { - source: "iana" - }, - "application/im-iscomposing+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/index": { - source: "iana" - }, - "application/index.cmd": { - source: "iana" - }, - "application/index.obj": { - source: "iana" - }, - "application/index.response": { - source: "iana" - }, - "application/index.vnd": { - source: "iana" - }, - "application/inkml+xml": { - source: "iana", - compressible: true, - extensions: ["ink", "inkml"] - }, - "application/iotp": { - source: "iana" - }, - "application/ipfix": { - source: "iana", - extensions: ["ipfix"] - }, - "application/ipp": { - source: "iana" - }, - "application/isup": { - source: "iana" - }, - "application/its+xml": { - source: "iana", - compressible: true, - extensions: ["its"] - }, - "application/java-archive": { - source: "iana", - compressible: false, - extensions: ["jar", "war", "ear"] - }, - "application/java-serialized-object": { - source: "apache", - compressible: false, - extensions: ["ser"] - }, - "application/java-vm": { - source: "apache", - compressible: false, - extensions: ["class"] - }, - "application/javascript": { - source: "apache", - charset: "UTF-8", - compressible: true, - extensions: ["js"] - }, - "application/jf2feed+json": { - source: "iana", - compressible: true - }, - "application/jose": { - source: "iana" - }, - "application/jose+json": { - source: "iana", - compressible: true - }, - "application/jrd+json": { - source: "iana", - compressible: true - }, - "application/jscalendar+json": { - source: "iana", - compressible: true - }, - "application/jscontact+json": { - source: "iana", - compressible: true - }, - "application/json": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["json", "map"] - }, - "application/json-patch+json": { - source: "iana", - compressible: true - }, - "application/json-seq": { - source: "iana" - }, - "application/json5": { - extensions: ["json5"] - }, - "application/jsonml+json": { - source: "apache", - compressible: true, - extensions: ["jsonml"] - }, - "application/jsonpath": { - source: "iana" - }, - "application/jwk+json": { - source: "iana", - compressible: true - }, - "application/jwk-set+json": { - source: "iana", - compressible: true - }, - "application/jwk-set+jwt": { - source: "iana" - }, - "application/jwt": { - source: "iana" - }, - "application/kpml-request+xml": { - source: "iana", - compressible: true - }, - "application/kpml-response+xml": { - source: "iana", - compressible: true - }, - "application/ld+json": { - source: "iana", - compressible: true, - extensions: ["jsonld"] - }, - "application/lgr+xml": { - source: "iana", - compressible: true, - extensions: ["lgr"] - }, - "application/link-format": { - source: "iana" - }, - "application/linkset": { - source: "iana" - }, - "application/linkset+json": { - source: "iana", - compressible: true - }, - "application/load-control+xml": { - source: "iana", - compressible: true - }, - "application/logout+jwt": { - source: "iana" - }, - "application/lost+xml": { - source: "iana", - compressible: true, - extensions: ["lostxml"] - }, - "application/lostsync+xml": { - source: "iana", - compressible: true - }, - "application/lpf+zip": { - source: "iana", - compressible: false - }, - "application/lxf": { - source: "iana" - }, - "application/mac-binhex40": { - source: "iana", - extensions: ["hqx"] - }, - "application/mac-compactpro": { - source: "apache", - extensions: ["cpt"] - }, - "application/macwriteii": { - source: "iana" - }, - "application/mads+xml": { - source: "iana", - compressible: true, - extensions: ["mads"] - }, - "application/manifest+json": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["webmanifest"] - }, - "application/marc": { - source: "iana", - extensions: ["mrc"] - }, - "application/marcxml+xml": { - source: "iana", - compressible: true, - extensions: ["mrcx"] - }, - "application/mathematica": { - source: "iana", - extensions: ["ma", "nb", "mb"] - }, - "application/mathml+xml": { - source: "iana", - compressible: true, - extensions: ["mathml"] - }, - "application/mathml-content+xml": { - source: "iana", - compressible: true - }, - "application/mathml-presentation+xml": { - source: "iana", - compressible: true - }, - "application/mbms-associated-procedure-description+xml": { - source: "iana", - compressible: true - }, - "application/mbms-deregister+xml": { - source: "iana", - compressible: true - }, - "application/mbms-envelope+xml": { - source: "iana", - compressible: true - }, - "application/mbms-msk+xml": { - source: "iana", - compressible: true - }, - "application/mbms-msk-response+xml": { - source: "iana", - compressible: true - }, - "application/mbms-protection-description+xml": { - source: "iana", - compressible: true - }, - "application/mbms-reception-report+xml": { - source: "iana", - compressible: true - }, - "application/mbms-register+xml": { - source: "iana", - compressible: true - }, - "application/mbms-register-response+xml": { - source: "iana", - compressible: true - }, - "application/mbms-schedule+xml": { - source: "iana", - compressible: true - }, - "application/mbms-user-service-description+xml": { - source: "iana", - compressible: true - }, - "application/mbox": { - source: "iana", - extensions: ["mbox"] - }, - "application/media-policy-dataset+xml": { - source: "iana", - compressible: true, - extensions: ["mpf"] - }, - "application/media_control+xml": { - source: "iana", - compressible: true - }, - "application/mediaservercontrol+xml": { - source: "iana", - compressible: true, - extensions: ["mscml"] - }, - "application/merge-patch+json": { - source: "iana", - compressible: true - }, - "application/metalink+xml": { - source: "apache", - compressible: true, - extensions: ["metalink"] - }, - "application/metalink4+xml": { - source: "iana", - compressible: true, - extensions: ["meta4"] - }, - "application/mets+xml": { - source: "iana", - compressible: true, - extensions: ["mets"] - }, - "application/mf4": { - source: "iana" - }, - "application/mikey": { - source: "iana" - }, - "application/mipc": { - source: "iana" - }, - "application/missing-blocks+cbor-seq": { - source: "iana" - }, - "application/mmt-aei+xml": { - source: "iana", - compressible: true, - extensions: ["maei"] - }, - "application/mmt-usd+xml": { - source: "iana", - compressible: true, - extensions: ["musd"] - }, - "application/mods+xml": { - source: "iana", - compressible: true, - extensions: ["mods"] - }, - "application/moss-keys": { - source: "iana" - }, - "application/moss-signature": { - source: "iana" - }, - "application/mosskey-data": { - source: "iana" - }, - "application/mosskey-request": { - source: "iana" - }, - "application/mp21": { - source: "iana", - extensions: ["m21", "mp21"] - }, - "application/mp4": { - source: "iana", - extensions: ["mp4", "mpg4", "mp4s", "m4p"] - }, - "application/mpeg4-generic": { - source: "iana" - }, - "application/mpeg4-iod": { - source: "iana" - }, - "application/mpeg4-iod-xmt": { - source: "iana" - }, - "application/mrb-consumer+xml": { - source: "iana", - compressible: true - }, - "application/mrb-publish+xml": { - source: "iana", - compressible: true - }, - "application/msc-ivr+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/msc-mixer+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/msix": { - compressible: false, - extensions: ["msix"] - }, - "application/msixbundle": { - compressible: false, - extensions: ["msixbundle"] - }, - "application/msword": { - source: "iana", - compressible: false, - extensions: ["doc", "dot"] - }, - "application/mud+json": { - source: "iana", - compressible: true - }, - "application/multipart-core": { - source: "iana" - }, - "application/mxf": { - source: "iana", - extensions: ["mxf"] - }, - "application/n-quads": { - source: "iana", - extensions: ["nq"] - }, - "application/n-triples": { - source: "iana", - extensions: ["nt"] - }, - "application/nasdata": { - source: "iana" - }, - "application/news-checkgroups": { - source: "iana", - charset: "US-ASCII" - }, - "application/news-groupinfo": { - source: "iana", - charset: "US-ASCII" - }, - "application/news-transmission": { - source: "iana" - }, - "application/nlsml+xml": { - source: "iana", - compressible: true - }, - "application/node": { - source: "iana", - extensions: ["cjs"] - }, - "application/nss": { - source: "iana" - }, - "application/oauth-authz-req+jwt": { - source: "iana" - }, - "application/oblivious-dns-message": { - source: "iana" - }, - "application/ocsp-request": { - source: "iana" - }, - "application/ocsp-response": { - source: "iana" - }, - "application/octet-stream": { - source: "iana", - compressible: true, - extensions: ["bin", "dms", "lrf", "mar", "so", "dist", "distz", "pkg", "bpk", "dump", "elc", "deploy", "exe", "dll", "deb", "dmg", "iso", "img", "msi", "msp", "msm", "buffer"] - }, - "application/oda": { - source: "iana", - extensions: ["oda"] - }, - "application/odm+xml": { - source: "iana", - compressible: true - }, - "application/odx": { - source: "iana" - }, - "application/oebps-package+xml": { - source: "iana", - compressible: true, - extensions: ["opf"] - }, - "application/ogg": { - source: "iana", - compressible: false, - extensions: ["ogx"] - }, - "application/ohttp-keys": { - source: "iana" - }, - "application/omdoc+xml": { - source: "apache", - compressible: true, - extensions: ["omdoc"] - }, - "application/onenote": { - source: "apache", - extensions: ["onetoc", "onetoc2", "onetmp", "onepkg", "one", "onea"] - }, - "application/opc-nodeset+xml": { - source: "iana", - compressible: true - }, - "application/oscore": { - source: "iana" - }, - "application/oxps": { - source: "iana", - extensions: ["oxps"] - }, - "application/p21": { - source: "iana" - }, - "application/p21+zip": { - source: "iana", - compressible: false - }, - "application/p2p-overlay+xml": { - source: "iana", - compressible: true, - extensions: ["relo"] - }, - "application/parityfec": { - source: "iana" - }, - "application/passport": { - source: "iana" - }, - "application/patch-ops-error+xml": { - source: "iana", - compressible: true, - extensions: ["xer"] - }, - "application/pdf": { - source: "iana", - compressible: false, - extensions: ["pdf"] - }, - "application/pdx": { - source: "iana" - }, - "application/pem-certificate-chain": { - source: "iana" - }, - "application/pgp-encrypted": { - source: "iana", - compressible: false, - extensions: ["pgp"] - }, - "application/pgp-keys": { - source: "iana", - extensions: ["asc"] - }, - "application/pgp-signature": { - source: "iana", - extensions: ["sig", "asc"] - }, - "application/pics-rules": { - source: "apache", - extensions: ["prf"] - }, - "application/pidf+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/pidf-diff+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/pkcs10": { - source: "iana", - extensions: ["p10"] - }, - "application/pkcs12": { - source: "iana" - }, - "application/pkcs7-mime": { - source: "iana", - extensions: ["p7m", "p7c"] - }, - "application/pkcs7-signature": { - source: "iana", - extensions: ["p7s"] - }, - "application/pkcs8": { - source: "iana", - extensions: ["p8"] - }, - "application/pkcs8-encrypted": { - source: "iana" - }, - "application/pkix-attr-cert": { - source: "iana", - extensions: ["ac"] - }, - "application/pkix-cert": { - source: "iana", - extensions: ["cer"] - }, - "application/pkix-crl": { - source: "iana", - extensions: ["crl"] - }, - "application/pkix-pkipath": { - source: "iana", - extensions: ["pkipath"] - }, - "application/pkixcmp": { - source: "iana", - extensions: ["pki"] - }, - "application/pls+xml": { - source: "iana", - compressible: true, - extensions: ["pls"] - }, - "application/poc-settings+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/postscript": { - source: "iana", - compressible: true, - extensions: ["ai", "eps", "ps"] - }, - "application/ppsp-tracker+json": { - source: "iana", - compressible: true - }, - "application/private-token-issuer-directory": { - source: "iana" - }, - "application/private-token-request": { - source: "iana" - }, - "application/private-token-response": { - source: "iana" - }, - "application/problem+json": { - source: "iana", - compressible: true - }, - "application/problem+xml": { - source: "iana", - compressible: true - }, - "application/provenance+xml": { - source: "iana", - compressible: true, - extensions: ["provx"] - }, - "application/provided-claims+jwt": { - source: "iana" - }, - "application/prs.alvestrand.titrax-sheet": { - source: "iana" - }, - "application/prs.cww": { - source: "iana", - extensions: ["cww"] - }, - "application/prs.cyn": { - source: "iana", - charset: "7-BIT" - }, - "application/prs.hpub+zip": { - source: "iana", - compressible: false - }, - "application/prs.implied-document+xml": { - source: "iana", - compressible: true - }, - "application/prs.implied-executable": { - source: "iana" - }, - "application/prs.implied-object+json": { - source: "iana", - compressible: true - }, - "application/prs.implied-object+json-seq": { - source: "iana" - }, - "application/prs.implied-object+yaml": { - source: "iana" - }, - "application/prs.implied-structure": { - source: "iana" - }, - "application/prs.mayfile": { - source: "iana" - }, - "application/prs.nprend": { - source: "iana" - }, - "application/prs.plucker": { - source: "iana" - }, - "application/prs.rdf-xml-crypt": { - source: "iana" - }, - "application/prs.vcfbzip2": { - source: "iana" - }, - "application/prs.xsf+xml": { - source: "iana", - compressible: true, - extensions: ["xsf"] - }, - "application/pskc+xml": { - source: "iana", - compressible: true, - extensions: ["pskcxml"] - }, - "application/pvd+json": { - source: "iana", - compressible: true - }, - "application/qsig": { - source: "iana" - }, - "application/raml+yaml": { - compressible: true, - extensions: ["raml"] - }, - "application/raptorfec": { - source: "iana" - }, - "application/rdap+json": { - source: "iana", - compressible: true - }, - "application/rdf+xml": { - source: "iana", - compressible: true, - extensions: ["rdf", "owl"] - }, - "application/reginfo+xml": { - source: "iana", - compressible: true, - extensions: ["rif"] - }, - "application/relax-ng-compact-syntax": { - source: "iana", - extensions: ["rnc"] - }, - "application/remote-printing": { - source: "apache" - }, - "application/reputon+json": { - source: "iana", - compressible: true - }, - "application/resolve-response+jwt": { - source: "iana" - }, - "application/resource-lists+xml": { - source: "iana", - compressible: true, - extensions: ["rl"] - }, - "application/resource-lists-diff+xml": { - source: "iana", - compressible: true, - extensions: ["rld"] - }, - "application/rfc+xml": { - source: "iana", - compressible: true - }, - "application/riscos": { - source: "iana" - }, - "application/rlmi+xml": { - source: "iana", - compressible: true - }, - "application/rls-services+xml": { - source: "iana", - compressible: true, - extensions: ["rs"] - }, - "application/route-apd+xml": { - source: "iana", - compressible: true, - extensions: ["rapd"] - }, - "application/route-s-tsid+xml": { - source: "iana", - compressible: true, - extensions: ["sls"] - }, - "application/route-usd+xml": { - source: "iana", - compressible: true, - extensions: ["rusd"] - }, - "application/rpki-checklist": { - source: "iana" - }, - "application/rpki-ghostbusters": { - source: "iana", - extensions: ["gbr"] - }, - "application/rpki-manifest": { - source: "iana", - extensions: ["mft"] - }, - "application/rpki-publication": { - source: "iana" - }, - "application/rpki-roa": { - source: "iana", - extensions: ["roa"] - }, - "application/rpki-signed-tal": { - source: "iana" - }, - "application/rpki-updown": { - source: "iana" - }, - "application/rsd+xml": { - source: "apache", - compressible: true, - extensions: ["rsd"] - }, - "application/rss+xml": { - source: "apache", - compressible: true, - extensions: ["rss"] - }, - "application/rtf": { - source: "iana", - compressible: true, - extensions: ["rtf"] - }, - "application/rtploopback": { - source: "iana" - }, - "application/rtx": { - source: "iana" - }, - "application/samlassertion+xml": { - source: "iana", - compressible: true - }, - "application/samlmetadata+xml": { - source: "iana", - compressible: true - }, - "application/sarif+json": { - source: "iana", - compressible: true - }, - "application/sarif-external-properties+json": { - source: "iana", - compressible: true - }, - "application/sbe": { - source: "iana" - }, - "application/sbml+xml": { - source: "iana", - compressible: true, - extensions: ["sbml"] - }, - "application/scaip+xml": { - source: "iana", - compressible: true - }, - "application/scim+json": { - source: "iana", - compressible: true - }, - "application/scvp-cv-request": { - source: "iana", - extensions: ["scq"] - }, - "application/scvp-cv-response": { - source: "iana", - extensions: ["scs"] - }, - "application/scvp-vp-request": { - source: "iana", - extensions: ["spq"] - }, - "application/scvp-vp-response": { - source: "iana", - extensions: ["spp"] - }, - "application/sdp": { - source: "iana", - extensions: ["sdp"] - }, - "application/secevent+jwt": { - source: "iana" - }, - "application/senml+cbor": { - source: "iana" - }, - "application/senml+json": { - source: "iana", - compressible: true - }, - "application/senml+xml": { - source: "iana", - compressible: true, - extensions: ["senmlx"] - }, - "application/senml-etch+cbor": { - source: "iana" - }, - "application/senml-etch+json": { - source: "iana", - compressible: true - }, - "application/senml-exi": { - source: "iana" - }, - "application/sensml+cbor": { - source: "iana" - }, - "application/sensml+json": { - source: "iana", - compressible: true - }, - "application/sensml+xml": { - source: "iana", - compressible: true, - extensions: ["sensmlx"] - }, - "application/sensml-exi": { - source: "iana" - }, - "application/sep+xml": { - source: "iana", - compressible: true - }, - "application/sep-exi": { - source: "iana" - }, - "application/session-info": { - source: "iana" - }, - "application/set-payment": { - source: "iana" - }, - "application/set-payment-initiation": { - source: "iana", - extensions: ["setpay"] - }, - "application/set-registration": { - source: "iana" - }, - "application/set-registration-initiation": { - source: "iana", - extensions: ["setreg"] - }, - "application/sgml": { - source: "iana" - }, - "application/sgml-open-catalog": { - source: "iana" - }, - "application/shf+xml": { - source: "iana", - compressible: true, - extensions: ["shf"] - }, - "application/sieve": { - source: "iana", - extensions: ["siv", "sieve"] - }, - "application/simple-filter+xml": { - source: "iana", - compressible: true - }, - "application/simple-message-summary": { - source: "iana" - }, - "application/simplesymbolcontainer": { - source: "iana" - }, - "application/sipc": { - source: "iana" - }, - "application/slate": { - source: "iana" - }, - "application/smil": { - source: "apache" - }, - "application/smil+xml": { - source: "iana", - compressible: true, - extensions: ["smi", "smil"] - }, - "application/smpte336m": { - source: "iana" - }, - "application/soap+fastinfoset": { - source: "iana" - }, - "application/soap+xml": { - source: "iana", - compressible: true - }, - "application/sparql-query": { - source: "iana", - extensions: ["rq"] - }, - "application/sparql-results+xml": { - source: "iana", - compressible: true, - extensions: ["srx"] - }, - "application/spdx+json": { - source: "iana", - compressible: true - }, - "application/spirits-event+xml": { - source: "iana", - compressible: true - }, - "application/sql": { - source: "iana", - extensions: ["sql"] - }, - "application/srgs": { - source: "iana", - extensions: ["gram"] - }, - "application/srgs+xml": { - source: "iana", - compressible: true, - extensions: ["grxml"] - }, - "application/sru+xml": { - source: "iana", - compressible: true, - extensions: ["sru"] - }, - "application/ssdl+xml": { - source: "apache", - compressible: true, - extensions: ["ssdl"] - }, - "application/sslkeylogfile": { - source: "iana" - }, - "application/ssml+xml": { - source: "iana", - compressible: true, - extensions: ["ssml"] - }, - "application/st2110-41": { - source: "iana" - }, - "application/stix+json": { - source: "iana", - compressible: true - }, - "application/stratum": { - source: "iana" - }, - "application/swid+cbor": { - source: "iana" - }, - "application/swid+xml": { - source: "iana", - compressible: true, - extensions: ["swidtag"] - }, - "application/tamp-apex-update": { - source: "iana" - }, - "application/tamp-apex-update-confirm": { - source: "iana" - }, - "application/tamp-community-update": { - source: "iana" - }, - "application/tamp-community-update-confirm": { - source: "iana" - }, - "application/tamp-error": { - source: "iana" - }, - "application/tamp-sequence-adjust": { - source: "iana" - }, - "application/tamp-sequence-adjust-confirm": { - source: "iana" - }, - "application/tamp-status-query": { - source: "iana" - }, - "application/tamp-status-response": { - source: "iana" - }, - "application/tamp-update": { - source: "iana" - }, - "application/tamp-update-confirm": { - source: "iana" - }, - "application/tar": { - compressible: true - }, - "application/taxii+json": { - source: "iana", - compressible: true - }, - "application/td+json": { - source: "iana", - compressible: true - }, - "application/tei+xml": { - source: "iana", - compressible: true, - extensions: ["tei", "teicorpus"] - }, - "application/tetra_isi": { - source: "iana" - }, - "application/thraud+xml": { - source: "iana", - compressible: true, - extensions: ["tfi"] - }, - "application/timestamp-query": { - source: "iana" - }, - "application/timestamp-reply": { - source: "iana" - }, - "application/timestamped-data": { - source: "iana", - extensions: ["tsd"] - }, - "application/tlsrpt+gzip": { - source: "iana" - }, - "application/tlsrpt+json": { - source: "iana", - compressible: true - }, - "application/tm+json": { - source: "iana", - compressible: true - }, - "application/tnauthlist": { - source: "iana" - }, - "application/toc+cbor": { - source: "iana" - }, - "application/token-introspection+jwt": { - source: "iana" - }, - "application/toml": { - source: "iana", - compressible: true, - extensions: ["toml"] - }, - "application/trickle-ice-sdpfrag": { - source: "iana" - }, - "application/trig": { - source: "iana", - extensions: ["trig"] - }, - "application/trust-chain+json": { - source: "iana", - compressible: true - }, - "application/trust-mark+jwt": { - source: "iana" - }, - "application/trust-mark-delegation+jwt": { - source: "iana" - }, - "application/ttml+xml": { - source: "iana", - compressible: true, - extensions: ["ttml"] - }, - "application/tve-trigger": { - source: "iana" - }, - "application/tzif": { - source: "iana" - }, - "application/tzif-leap": { - source: "iana" - }, - "application/ubjson": { - compressible: false, - extensions: ["ubj"] - }, - "application/uccs+cbor": { - source: "iana" - }, - "application/ujcs+json": { - source: "iana", - compressible: true - }, - "application/ulpfec": { - source: "iana" - }, - "application/urc-grpsheet+xml": { - source: "iana", - compressible: true - }, - "application/urc-ressheet+xml": { - source: "iana", - compressible: true, - extensions: ["rsheet"] - }, - "application/urc-targetdesc+xml": { - source: "iana", - compressible: true, - extensions: ["td"] - }, - "application/urc-uisocketdesc+xml": { - source: "iana", - compressible: true - }, - "application/vc": { - source: "iana" - }, - "application/vc+cose": { - source: "iana" - }, - "application/vc+jwt": { - source: "iana" - }, - "application/vcard+json": { - source: "iana", - compressible: true - }, - "application/vcard+xml": { - source: "iana", - compressible: true - }, - "application/vemmi": { - source: "iana" - }, - "application/vividence.scriptfile": { - source: "apache" - }, - "application/vnd.1000minds.decision-model+xml": { - source: "iana", - compressible: true, - extensions: ["1km"] - }, - "application/vnd.1ob": { - source: "iana" - }, - "application/vnd.3gpp-prose+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp-prose-pc3a+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp-prose-pc3ach+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp-prose-pc3ch+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp-prose-pc8+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp-v2x-local-service-information": { - source: "iana" - }, - "application/vnd.3gpp.5gnas": { - source: "iana" - }, - "application/vnd.3gpp.5gsa2x": { - source: "iana" - }, - "application/vnd.3gpp.5gsa2x-local-service-information": { - source: "iana" - }, - "application/vnd.3gpp.5gsv2x": { - source: "iana" - }, - "application/vnd.3gpp.5gsv2x-local-service-information": { - source: "iana" - }, - "application/vnd.3gpp.access-transfer-events+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.bsf+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.crs+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.current-location-discovery+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.gmop+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.gtpc": { - source: "iana" - }, - "application/vnd.3gpp.interworking-data": { - source: "iana" - }, - "application/vnd.3gpp.lpp": { - source: "iana" - }, - "application/vnd.3gpp.mc-signalling-ear": { - source: "iana" - }, - "application/vnd.3gpp.mcdata-affiliation-command+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-msgstore-ctrl-request+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-payload": { - source: "iana" - }, - "application/vnd.3gpp.mcdata-regroup+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-service-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-signalling": { - source: "iana" - }, - "application/vnd.3gpp.mcdata-ue-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcdata-user-profile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-affiliation-command+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-floor-request+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-location-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-mbms-usage-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-regroup+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-service-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-signed+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-ue-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-ue-init-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcptt-user-profile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-affiliation-command+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-location-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-mbms-usage-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-regroup+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-service-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-transmission-request+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-ue-config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mcvideo-user-profile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.mid-call+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.ngap": { - source: "iana" - }, - "application/vnd.3gpp.pfcp": { - source: "iana" - }, - "application/vnd.3gpp.pic-bw-large": { - source: "iana", - extensions: ["plb"] - }, - "application/vnd.3gpp.pic-bw-small": { - source: "iana", - extensions: ["psb"] - }, - "application/vnd.3gpp.pic-bw-var": { - source: "iana", - extensions: ["pvb"] - }, - "application/vnd.3gpp.pinapp-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.s1ap": { - source: "iana" - }, - "application/vnd.3gpp.seal-group-doc+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-location-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-mbms-usage-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-network-qos-management-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-ue-config-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-unicast-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.seal-user-profile-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.sms": { - source: "iana" - }, - "application/vnd.3gpp.sms+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.srvcc-ext+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.srvcc-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.state-and-event-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.ussd+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp.v2x": { - source: "iana" - }, - "application/vnd.3gpp.vae-info+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp2.bcmcsinfo+xml": { - source: "iana", - compressible: true - }, - "application/vnd.3gpp2.sms": { - source: "iana" - }, - "application/vnd.3gpp2.tcap": { - source: "iana", - extensions: ["tcap"] - }, - "application/vnd.3lightssoftware.imagescal": { - source: "iana" - }, - "application/vnd.3m.post-it-notes": { - source: "iana", - extensions: ["pwn"] - }, - "application/vnd.accpac.simply.aso": { - source: "iana", - extensions: ["aso"] - }, - "application/vnd.accpac.simply.imp": { - source: "iana", - extensions: ["imp"] - }, - "application/vnd.acm.addressxfer+json": { - source: "iana", - compressible: true - }, - "application/vnd.acm.chatbot+json": { - source: "iana", - compressible: true - }, - "application/vnd.acucobol": { - source: "iana", - extensions: ["acu"] - }, - "application/vnd.acucorp": { - source: "iana", - extensions: ["atc", "acutc"] - }, - "application/vnd.adobe.air-application-installer-package+zip": { - source: "apache", - compressible: false, - extensions: ["air"] - }, - "application/vnd.adobe.flash.movie": { - source: "iana" - }, - "application/vnd.adobe.formscentral.fcdt": { - source: "iana", - extensions: ["fcdt"] - }, - "application/vnd.adobe.fxp": { - source: "iana", - extensions: ["fxp", "fxpl"] - }, - "application/vnd.adobe.partial-upload": { - source: "iana" - }, - "application/vnd.adobe.xdp+xml": { - source: "iana", - compressible: true, - extensions: ["xdp"] - }, - "application/vnd.adobe.xfdf": { - source: "apache", - extensions: ["xfdf"] - }, - "application/vnd.aether.imp": { - source: "iana" - }, - "application/vnd.afpc.afplinedata": { - source: "iana" - }, - "application/vnd.afpc.afplinedata-pagedef": { - source: "iana" - }, - "application/vnd.afpc.cmoca-cmresource": { - source: "iana" - }, - "application/vnd.afpc.foca-charset": { - source: "iana" - }, - "application/vnd.afpc.foca-codedfont": { - source: "iana" - }, - "application/vnd.afpc.foca-codepage": { - source: "iana" - }, - "application/vnd.afpc.modca": { - source: "iana" - }, - "application/vnd.afpc.modca-cmtable": { - source: "iana" - }, - "application/vnd.afpc.modca-formdef": { - source: "iana" - }, - "application/vnd.afpc.modca-mediummap": { - source: "iana" - }, - "application/vnd.afpc.modca-objectcontainer": { - source: "iana" - }, - "application/vnd.afpc.modca-overlay": { - source: "iana" - }, - "application/vnd.afpc.modca-pagesegment": { - source: "iana" - }, - "application/vnd.age": { - source: "iana", - extensions: ["age"] - }, - "application/vnd.ah-barcode": { - source: "apache" - }, - "application/vnd.ahead.space": { - source: "iana", - extensions: ["ahead"] - }, - "application/vnd.airzip.filesecure.azf": { - source: "iana", - extensions: ["azf"] - }, - "application/vnd.airzip.filesecure.azs": { - source: "iana", - extensions: ["azs"] - }, - "application/vnd.amadeus+json": { - source: "iana", - compressible: true - }, - "application/vnd.amazon.ebook": { - source: "apache", - extensions: ["azw"] - }, - "application/vnd.amazon.mobi8-ebook": { - source: "iana" - }, - "application/vnd.americandynamics.acc": { - source: "iana", - extensions: ["acc"] - }, - "application/vnd.amiga.ami": { - source: "iana", - extensions: ["ami"] - }, - "application/vnd.amundsen.maze+xml": { - source: "iana", - compressible: true - }, - "application/vnd.android.ota": { - source: "iana" - }, - "application/vnd.android.package-archive": { - source: "apache", - compressible: false, - extensions: ["apk"] - }, - "application/vnd.anki": { - source: "iana" - }, - "application/vnd.anser-web-certificate-issue-initiation": { - source: "iana", - extensions: ["cii"] - }, - "application/vnd.anser-web-funds-transfer-initiation": { - source: "apache", - extensions: ["fti"] - }, - "application/vnd.antix.game-component": { - source: "iana", - extensions: ["atx"] - }, - "application/vnd.apache.arrow.file": { - source: "iana" - }, - "application/vnd.apache.arrow.stream": { - source: "iana" - }, - "application/vnd.apache.parquet": { - source: "iana" - }, - "application/vnd.apache.thrift.binary": { - source: "iana" - }, - "application/vnd.apache.thrift.compact": { - source: "iana" - }, - "application/vnd.apache.thrift.json": { - source: "iana" - }, - "application/vnd.apexlang": { - source: "iana" - }, - "application/vnd.api+json": { - source: "iana", - compressible: true - }, - "application/vnd.aplextor.warrp+json": { - source: "iana", - compressible: true - }, - "application/vnd.apothekende.reservation+json": { - source: "iana", - compressible: true - }, - "application/vnd.apple.installer+xml": { - source: "iana", - compressible: true, - extensions: ["mpkg"] - }, - "application/vnd.apple.keynote": { - source: "iana", - extensions: ["key"] - }, - "application/vnd.apple.mpegurl": { - source: "iana", - extensions: ["m3u8"] - }, - "application/vnd.apple.numbers": { - source: "iana", - extensions: ["numbers"] - }, - "application/vnd.apple.pages": { - source: "iana", - extensions: ["pages"] - }, - "application/vnd.apple.pkpass": { - compressible: false, - extensions: ["pkpass"] - }, - "application/vnd.arastra.swi": { - source: "apache" - }, - "application/vnd.aristanetworks.swi": { - source: "iana", - extensions: ["swi"] - }, - "application/vnd.artisan+json": { - source: "iana", - compressible: true - }, - "application/vnd.artsquare": { - source: "iana" - }, - "application/vnd.astraea-software.iota": { - source: "iana", - extensions: ["iota"] - }, - "application/vnd.audiograph": { - source: "iana", - extensions: ["aep"] - }, - "application/vnd.autodesk.fbx": { - extensions: ["fbx"] - }, - "application/vnd.autopackage": { - source: "iana" - }, - "application/vnd.avalon+json": { - source: "iana", - compressible: true - }, - "application/vnd.avistar+xml": { - source: "iana", - compressible: true - }, - "application/vnd.balsamiq.bmml+xml": { - source: "iana", - compressible: true, - extensions: ["bmml"] - }, - "application/vnd.balsamiq.bmpr": { - source: "iana" - }, - "application/vnd.banana-accounting": { - source: "iana" - }, - "application/vnd.bbf.usp.error": { - source: "iana" - }, - "application/vnd.bbf.usp.msg": { - source: "iana" - }, - "application/vnd.bbf.usp.msg+json": { - source: "iana", - compressible: true - }, - "application/vnd.bekitzur-stech+json": { - source: "iana", - compressible: true - }, - "application/vnd.belightsoft.lhzd+zip": { - source: "iana", - compressible: false - }, - "application/vnd.belightsoft.lhzl+zip": { - source: "iana", - compressible: false - }, - "application/vnd.bint.med-content": { - source: "iana" - }, - "application/vnd.biopax.rdf+xml": { - source: "iana", - compressible: true - }, - "application/vnd.blink-idb-value-wrapper": { - source: "iana" - }, - "application/vnd.blueice.multipass": { - source: "iana", - extensions: ["mpm"] - }, - "application/vnd.bluetooth.ep.oob": { - source: "iana" - }, - "application/vnd.bluetooth.le.oob": { - source: "iana" - }, - "application/vnd.bmi": { - source: "iana", - extensions: ["bmi"] - }, - "application/vnd.bpf": { - source: "iana" - }, - "application/vnd.bpf3": { - source: "iana" - }, - "application/vnd.businessobjects": { - source: "iana", - extensions: ["rep"] - }, - "application/vnd.byu.uapi+json": { - source: "iana", - compressible: true - }, - "application/vnd.bzip3": { - source: "iana" - }, - "application/vnd.c3voc.schedule+xml": { - source: "iana", - compressible: true - }, - "application/vnd.cab-jscript": { - source: "iana" - }, - "application/vnd.canon-cpdl": { - source: "iana" - }, - "application/vnd.canon-lips": { - source: "iana" - }, - "application/vnd.capasystems-pg+json": { - source: "iana", - compressible: true - }, - "application/vnd.cendio.thinlinc.clientconf": { - source: "iana" - }, - "application/vnd.century-systems.tcp_stream": { - source: "iana" - }, - "application/vnd.chemdraw+xml": { - source: "iana", - compressible: true, - extensions: ["cdxml"] - }, - "application/vnd.chess-pgn": { - source: "iana" - }, - "application/vnd.chipnuts.karaoke-mmd": { - source: "iana", - extensions: ["mmd"] - }, - "application/vnd.ciedi": { - source: "iana" - }, - "application/vnd.cinderella": { - source: "iana", - extensions: ["cdy"] - }, - "application/vnd.cirpack.isdn-ext": { - source: "iana" - }, - "application/vnd.citationstyles.style+xml": { - source: "iana", - compressible: true, - extensions: ["csl"] - }, - "application/vnd.claymore": { - source: "iana", - extensions: ["cla"] - }, - "application/vnd.cloanto.rp9": { - source: "iana", - extensions: ["rp9"] - }, - "application/vnd.clonk.c4group": { - source: "iana", - extensions: ["c4g", "c4d", "c4f", "c4p", "c4u"] - }, - "application/vnd.cluetrust.cartomobile-config": { - source: "iana", - extensions: ["c11amc"] - }, - "application/vnd.cluetrust.cartomobile-config-pkg": { - source: "iana", - extensions: ["c11amz"] - }, - "application/vnd.cncf.helm.chart.content.v1.tar+gzip": { - source: "iana" - }, - "application/vnd.cncf.helm.chart.provenance.v1.prov": { - source: "iana" - }, - "application/vnd.cncf.helm.config.v1+json": { - source: "iana", - compressible: true - }, - "application/vnd.coffeescript": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.document": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.document-template": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.presentation": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.presentation-template": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.spreadsheet": { - source: "iana" - }, - "application/vnd.collabio.xodocuments.spreadsheet-template": { - source: "iana" - }, - "application/vnd.collection+json": { - source: "iana", - compressible: true - }, - "application/vnd.collection.doc+json": { - source: "iana", - compressible: true - }, - "application/vnd.collection.next+json": { - source: "iana", - compressible: true - }, - "application/vnd.comicbook+zip": { - source: "iana", - compressible: false - }, - "application/vnd.comicbook-rar": { - source: "iana" - }, - "application/vnd.commerce-battelle": { - source: "iana" - }, - "application/vnd.commonspace": { - source: "iana", - extensions: ["csp"] - }, - "application/vnd.contact.cmsg": { - source: "iana", - extensions: ["cdbcmsg"] - }, - "application/vnd.coreos.ignition+json": { - source: "iana", - compressible: true - }, - "application/vnd.cosmocaller": { - source: "iana", - extensions: ["cmc"] - }, - "application/vnd.crick.clicker": { - source: "iana", - extensions: ["clkx"] - }, - "application/vnd.crick.clicker.keyboard": { - source: "iana", - extensions: ["clkk"] - }, - "application/vnd.crick.clicker.palette": { - source: "iana", - extensions: ["clkp"] - }, - "application/vnd.crick.clicker.template": { - source: "iana", - extensions: ["clkt"] - }, - "application/vnd.crick.clicker.wordbank": { - source: "iana", - extensions: ["clkw"] - }, - "application/vnd.criticaltools.wbs+xml": { - source: "iana", - compressible: true, - extensions: ["wbs"] - }, - "application/vnd.cryptii.pipe+json": { - source: "iana", - compressible: true - }, - "application/vnd.crypto-shade-file": { - source: "iana" - }, - "application/vnd.cryptomator.encrypted": { - source: "iana" - }, - "application/vnd.cryptomator.vault": { - source: "iana" - }, - "application/vnd.ctc-posml": { - source: "iana", - extensions: ["pml"] - }, - "application/vnd.ctct.ws+xml": { - source: "iana", - compressible: true - }, - "application/vnd.cups-pdf": { - source: "iana" - }, - "application/vnd.cups-postscript": { - source: "iana" - }, - "application/vnd.cups-ppd": { - source: "iana", - extensions: ["ppd"] - }, - "application/vnd.cups-raster": { - source: "iana" - }, - "application/vnd.cups-raw": { - source: "iana" - }, - "application/vnd.curl": { - source: "iana" - }, - "application/vnd.curl.car": { - source: "apache", - extensions: ["car"] - }, - "application/vnd.curl.pcurl": { - source: "apache", - extensions: ["pcurl"] - }, - "application/vnd.cyan.dean.root+xml": { - source: "iana", - compressible: true - }, - "application/vnd.cybank": { - source: "iana" - }, - "application/vnd.cyclonedx+json": { - source: "iana", - compressible: true - }, - "application/vnd.cyclonedx+xml": { - source: "iana", - compressible: true - }, - "application/vnd.d2l.coursepackage1p0+zip": { - source: "iana", - compressible: false - }, - "application/vnd.d3m-dataset": { - source: "iana" - }, - "application/vnd.d3m-problem": { - source: "iana" - }, - "application/vnd.dart": { - source: "iana", - compressible: true, - extensions: ["dart"] - }, - "application/vnd.data-vision.rdz": { - source: "iana", - extensions: ["rdz"] - }, - "application/vnd.datalog": { - source: "iana" - }, - "application/vnd.datapackage+json": { - source: "iana", - compressible: true - }, - "application/vnd.dataresource+json": { - source: "iana", - compressible: true - }, - "application/vnd.dbf": { - source: "iana", - extensions: ["dbf"] - }, - "application/vnd.dcmp+xml": { - source: "iana", - compressible: true, - extensions: ["dcmp"] - }, - "application/vnd.debian.binary-package": { - source: "iana" - }, - "application/vnd.dece.data": { - source: "iana", - extensions: ["uvf", "uvvf", "uvd", "uvvd"] - }, - "application/vnd.dece.ttml+xml": { - source: "iana", - compressible: true, - extensions: ["uvt", "uvvt"] - }, - "application/vnd.dece.unspecified": { - source: "iana", - extensions: ["uvx", "uvvx"] - }, - "application/vnd.dece.zip": { - source: "iana", - extensions: ["uvz", "uvvz"] - }, - "application/vnd.denovo.fcselayout-link": { - source: "iana", - extensions: ["fe_launch"] - }, - "application/vnd.desmume.movie": { - source: "iana" - }, - "application/vnd.dir-bi.plate-dl-nosuffix": { - source: "iana" - }, - "application/vnd.dm.delegation+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dna": { - source: "iana", - extensions: ["dna"] - }, - "application/vnd.document+json": { - source: "iana", - compressible: true - }, - "application/vnd.dolby.mlp": { - source: "apache", - extensions: ["mlp"] - }, - "application/vnd.dolby.mobile.1": { - source: "iana" - }, - "application/vnd.dolby.mobile.2": { - source: "iana" - }, - "application/vnd.doremir.scorecloud-binary-document": { - source: "iana" - }, - "application/vnd.dpgraph": { - source: "iana", - extensions: ["dpg"] - }, - "application/vnd.dreamfactory": { - source: "iana", - extensions: ["dfac"] - }, - "application/vnd.drive+json": { - source: "iana", - compressible: true - }, - "application/vnd.ds-keypoint": { - source: "apache", - extensions: ["kpxx"] - }, - "application/vnd.dtg.local": { - source: "iana" - }, - "application/vnd.dtg.local.flash": { - source: "iana" - }, - "application/vnd.dtg.local.html": { - source: "iana" - }, - "application/vnd.dvb.ait": { - source: "iana", - extensions: ["ait"] - }, - "application/vnd.dvb.dvbisl+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.dvbj": { - source: "iana" - }, - "application/vnd.dvb.esgcontainer": { - source: "iana" - }, - "application/vnd.dvb.ipdcdftnotifaccess": { - source: "iana" - }, - "application/vnd.dvb.ipdcesgaccess": { - source: "iana" - }, - "application/vnd.dvb.ipdcesgaccess2": { - source: "iana" - }, - "application/vnd.dvb.ipdcesgpdd": { - source: "iana" - }, - "application/vnd.dvb.ipdcroaming": { - source: "iana" - }, - "application/vnd.dvb.iptv.alfec-base": { - source: "iana" - }, - "application/vnd.dvb.iptv.alfec-enhancement": { - source: "iana" - }, - "application/vnd.dvb.notif-aggregate-root+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-container+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-generic+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-ia-msglist+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-ia-registration-request+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-ia-registration-response+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.notif-init+xml": { - source: "iana", - compressible: true - }, - "application/vnd.dvb.pfr": { - source: "iana" - }, - "application/vnd.dvb.service": { - source: "iana", - extensions: ["svc"] - }, - "application/vnd.dxr": { - source: "iana" - }, - "application/vnd.dynageo": { - source: "iana", - extensions: ["geo"] - }, - "application/vnd.dzr": { - source: "iana" - }, - "application/vnd.easykaraoke.cdgdownload": { - source: "iana" - }, - "application/vnd.ecdis-update": { - source: "iana" - }, - "application/vnd.ecip.rlp": { - source: "iana" - }, - "application/vnd.eclipse.ditto+json": { - source: "iana", - compressible: true - }, - "application/vnd.ecowin.chart": { - source: "iana", - extensions: ["mag"] - }, - "application/vnd.ecowin.filerequest": { - source: "iana" - }, - "application/vnd.ecowin.fileupdate": { - source: "iana" - }, - "application/vnd.ecowin.series": { - source: "iana" - }, - "application/vnd.ecowin.seriesrequest": { - source: "iana" - }, - "application/vnd.ecowin.seriesupdate": { - source: "iana" - }, - "application/vnd.efi.img": { - source: "iana" - }, - "application/vnd.efi.iso": { - source: "iana" - }, - "application/vnd.eln+zip": { - source: "iana", - compressible: false - }, - "application/vnd.emclient.accessrequest+xml": { - source: "iana", - compressible: true - }, - "application/vnd.enliven": { - source: "iana", - extensions: ["nml"] - }, - "application/vnd.enphase.envoy": { - source: "iana" - }, - "application/vnd.eprints.data+xml": { - source: "iana", - compressible: true - }, - "application/vnd.epson.esf": { - source: "iana", - extensions: ["esf"] - }, - "application/vnd.epson.msf": { - source: "iana", - extensions: ["msf"] - }, - "application/vnd.epson.quickanime": { - source: "iana", - extensions: ["qam"] - }, - "application/vnd.epson.salt": { - source: "iana", - extensions: ["slt"] - }, - "application/vnd.epson.ssf": { - source: "iana", - extensions: ["ssf"] - }, - "application/vnd.ericsson.quickcall": { - source: "iana" - }, - "application/vnd.erofs": { - source: "iana" - }, - "application/vnd.espass-espass+zip": { - source: "iana", - compressible: false - }, - "application/vnd.eszigno3+xml": { - source: "iana", - compressible: true, - extensions: ["es3", "et3"] - }, - "application/vnd.etsi.aoc+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.asic-e+zip": { - source: "iana", - compressible: false - }, - "application/vnd.etsi.asic-s+zip": { - source: "iana", - compressible: false - }, - "application/vnd.etsi.cug+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvcommand+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvdiscovery+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvprofile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvsad-bc+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvsad-cod+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvsad-npvr+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvservice+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvsync+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.iptvueprofile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.mcid+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.mheg5": { - source: "iana" - }, - "application/vnd.etsi.overload-control-policy-dataset+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.pstn+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.sci+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.simservs+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.timestamp-token": { - source: "iana" - }, - "application/vnd.etsi.tsl+xml": { - source: "iana", - compressible: true - }, - "application/vnd.etsi.tsl.der": { - source: "iana" - }, - "application/vnd.eu.kasparian.car+json": { - source: "iana", - compressible: true - }, - "application/vnd.eudora.data": { - source: "iana" - }, - "application/vnd.evolv.ecig.profile": { - source: "iana" - }, - "application/vnd.evolv.ecig.settings": { - source: "iana" - }, - "application/vnd.evolv.ecig.theme": { - source: "iana" - }, - "application/vnd.exstream-empower+zip": { - source: "iana", - compressible: false - }, - "application/vnd.exstream-package": { - source: "iana" - }, - "application/vnd.ezpix-album": { - source: "iana", - extensions: ["ez2"] - }, - "application/vnd.ezpix-package": { - source: "iana", - extensions: ["ez3"] - }, - "application/vnd.f-secure.mobile": { - source: "iana" - }, - "application/vnd.familysearch.gedcom+zip": { - source: "iana", - compressible: false - }, - "application/vnd.fastcopy-disk-image": { - source: "iana" - }, - "application/vnd.fdf": { - source: "apache", - extensions: ["fdf"] - }, - "application/vnd.fdsn.mseed": { - source: "iana", - extensions: ["mseed"] - }, - "application/vnd.fdsn.seed": { - source: "iana", - extensions: ["seed", "dataless"] - }, - "application/vnd.fdsn.stationxml+xml": { - source: "iana", - charset: "XML-BASED", - compressible: true - }, - "application/vnd.ffsns": { - source: "iana" - }, - "application/vnd.ficlab.flb+zip": { - source: "iana", - compressible: false - }, - "application/vnd.filmit.zfc": { - source: "iana" - }, - "application/vnd.fints": { - source: "iana" - }, - "application/vnd.firemonkeys.cloudcell": { - source: "iana" - }, - "application/vnd.flographit": { - source: "iana", - extensions: ["gph"] - }, - "application/vnd.fluxtime.clip": { - source: "iana", - extensions: ["ftc"] - }, - "application/vnd.font-fontforge-sfd": { - source: "iana" - }, - "application/vnd.framemaker": { - source: "iana", - extensions: ["fm", "frame", "maker", "book"] - }, - "application/vnd.freelog.comic": { - source: "iana" - }, - "application/vnd.frogans.fnc": { - source: "apache", - extensions: ["fnc"] - }, - "application/vnd.frogans.ltf": { - source: "apache", - extensions: ["ltf"] - }, - "application/vnd.fsc.weblaunch": { - source: "iana", - extensions: ["fsc"] - }, - "application/vnd.fujifilm.fb.docuworks": { - source: "iana" - }, - "application/vnd.fujifilm.fb.docuworks.binder": { - source: "iana" - }, - "application/vnd.fujifilm.fb.docuworks.container": { - source: "iana" - }, - "application/vnd.fujifilm.fb.jfi+xml": { - source: "iana", - compressible: true - }, - "application/vnd.fujitsu.oasys": { - source: "iana", - extensions: ["oas"] - }, - "application/vnd.fujitsu.oasys2": { - source: "iana", - extensions: ["oa2"] - }, - "application/vnd.fujitsu.oasys3": { - source: "iana", - extensions: ["oa3"] - }, - "application/vnd.fujitsu.oasysgp": { - source: "iana", - extensions: ["fg5"] - }, - "application/vnd.fujitsu.oasysprs": { - source: "iana", - extensions: ["bh2"] - }, - "application/vnd.fujixerox.art-ex": { - source: "iana" - }, - "application/vnd.fujixerox.art4": { - source: "iana" - }, - "application/vnd.fujixerox.ddd": { - source: "iana", - extensions: ["ddd"] - }, - "application/vnd.fujixerox.docuworks": { - source: "iana", - extensions: ["xdw"] - }, - "application/vnd.fujixerox.docuworks.binder": { - source: "iana", - extensions: ["xbd"] - }, - "application/vnd.fujixerox.docuworks.container": { - source: "iana" - }, - "application/vnd.fujixerox.hbpl": { - source: "iana" - }, - "application/vnd.fut-misnet": { - source: "iana" - }, - "application/vnd.futoin+cbor": { - source: "iana" - }, - "application/vnd.futoin+json": { - source: "iana", - compressible: true - }, - "application/vnd.fuzzysheet": { - source: "iana", - extensions: ["fzs"] - }, - "application/vnd.ga4gh.passport+jwt": { - source: "iana" - }, - "application/vnd.genomatix.tuxedo": { - source: "iana", - extensions: ["txd"] - }, - "application/vnd.genozip": { - source: "iana" - }, - "application/vnd.gentics.grd+json": { - source: "iana", - compressible: true - }, - "application/vnd.gentoo.catmetadata+xml": { - source: "iana", - compressible: true - }, - "application/vnd.gentoo.ebuild": { - source: "iana" - }, - "application/vnd.gentoo.eclass": { - source: "iana" - }, - "application/vnd.gentoo.gpkg": { - source: "iana" - }, - "application/vnd.gentoo.manifest": { - source: "iana" - }, - "application/vnd.gentoo.pkgmetadata+xml": { - source: "iana", - compressible: true - }, - "application/vnd.gentoo.xpak": { - source: "iana" - }, - "application/vnd.geo+json": { - source: "apache", - compressible: true - }, - "application/vnd.geocube+xml": { - source: "apache", - compressible: true - }, - "application/vnd.geogebra.file": { - source: "iana", - extensions: ["ggb"] - }, - "application/vnd.geogebra.pinboard": { - source: "iana" - }, - "application/vnd.geogebra.slides": { - source: "iana", - extensions: ["ggs"] - }, - "application/vnd.geogebra.tool": { - source: "iana", - extensions: ["ggt"] - }, - "application/vnd.geometry-explorer": { - source: "iana", - extensions: ["gex", "gre"] - }, - "application/vnd.geonext": { - source: "iana", - extensions: ["gxt"] - }, - "application/vnd.geoplan": { - source: "iana", - extensions: ["g2w"] - }, - "application/vnd.geospace": { - source: "iana", - extensions: ["g3w"] - }, - "application/vnd.gerber": { - source: "iana" - }, - "application/vnd.globalplatform.card-content-mgt": { - source: "iana" - }, - "application/vnd.globalplatform.card-content-mgt-response": { - source: "iana" - }, - "application/vnd.gmx": { - source: "iana", - extensions: ["gmx"] - }, - "application/vnd.gnu.taler.exchange+json": { - source: "iana", - compressible: true - }, - "application/vnd.gnu.taler.merchant+json": { - source: "iana", - compressible: true - }, - "application/vnd.google-apps.audio": {}, - "application/vnd.google-apps.document": { - compressible: false, - extensions: ["gdoc"] - }, - "application/vnd.google-apps.drawing": { - compressible: false, - extensions: ["gdraw"] - }, - "application/vnd.google-apps.drive-sdk": { - compressible: false - }, - "application/vnd.google-apps.file": {}, - "application/vnd.google-apps.folder": { - compressible: false - }, - "application/vnd.google-apps.form": { - compressible: false, - extensions: ["gform"] - }, - "application/vnd.google-apps.fusiontable": {}, - "application/vnd.google-apps.jam": { - compressible: false, - extensions: ["gjam"] - }, - "application/vnd.google-apps.mail-layout": {}, - "application/vnd.google-apps.map": { - compressible: false, - extensions: ["gmap"] - }, - "application/vnd.google-apps.photo": {}, - "application/vnd.google-apps.presentation": { - compressible: false, - extensions: ["gslides"] - }, - "application/vnd.google-apps.script": { - compressible: false, - extensions: ["gscript"] - }, - "application/vnd.google-apps.shortcut": {}, - "application/vnd.google-apps.site": { - compressible: false, - extensions: ["gsite"] - }, - "application/vnd.google-apps.spreadsheet": { - compressible: false, - extensions: ["gsheet"] - }, - "application/vnd.google-apps.unknown": {}, - "application/vnd.google-apps.video": {}, - "application/vnd.google-earth.kml+xml": { - source: "iana", - compressible: true, - extensions: ["kml"] - }, - "application/vnd.google-earth.kmz": { - source: "iana", - compressible: false, - extensions: ["kmz"] - }, - "application/vnd.gov.sk.e-form+xml": { - source: "apache", - compressible: true - }, - "application/vnd.gov.sk.e-form+zip": { - source: "iana", - compressible: false - }, - "application/vnd.gov.sk.xmldatacontainer+xml": { - source: "iana", - compressible: true, - extensions: ["xdcf"] - }, - "application/vnd.gpxsee.map+xml": { - source: "iana", - compressible: true - }, - "application/vnd.grafeq": { - source: "iana", - extensions: ["gqf", "gqs"] - }, - "application/vnd.gridmp": { - source: "iana" - }, - "application/vnd.groove-account": { - source: "iana", - extensions: ["gac"] - }, - "application/vnd.groove-help": { - source: "iana", - extensions: ["ghf"] - }, - "application/vnd.groove-identity-message": { - source: "iana", - extensions: ["gim"] - }, - "application/vnd.groove-injector": { - source: "iana", - extensions: ["grv"] - }, - "application/vnd.groove-tool-message": { - source: "iana", - extensions: ["gtm"] - }, - "application/vnd.groove-tool-template": { - source: "iana", - extensions: ["tpl"] - }, - "application/vnd.groove-vcard": { - source: "iana", - extensions: ["vcg"] - }, - "application/vnd.hal+json": { - source: "iana", - compressible: true - }, - "application/vnd.hal+xml": { - source: "iana", - compressible: true, - extensions: ["hal"] - }, - "application/vnd.handheld-entertainment+xml": { - source: "iana", - compressible: true, - extensions: ["zmm"] - }, - "application/vnd.hbci": { - source: "iana", - extensions: ["hbci"] - }, - "application/vnd.hc+json": { - source: "iana", - compressible: true - }, - "application/vnd.hcl-bireports": { - source: "iana" - }, - "application/vnd.hdt": { - source: "iana" - }, - "application/vnd.heroku+json": { - source: "iana", - compressible: true - }, - "application/vnd.hhe.lesson-player": { - source: "iana", - extensions: ["les"] - }, - "application/vnd.hp-hpgl": { - source: "iana", - extensions: ["hpgl"] - }, - "application/vnd.hp-hpid": { - source: "iana", - extensions: ["hpid"] - }, - "application/vnd.hp-hps": { - source: "iana", - extensions: ["hps"] - }, - "application/vnd.hp-jlyt": { - source: "iana", - extensions: ["jlt"] - }, - "application/vnd.hp-pcl": { - source: "iana", - extensions: ["pcl"] - }, - "application/vnd.hp-pclxl": { - source: "iana", - extensions: ["pclxl"] - }, - "application/vnd.hsl": { - source: "iana" - }, - "application/vnd.httphone": { - source: "iana" - }, - "application/vnd.hydrostatix.sof-data": { - source: "iana", - extensions: ["sfd-hdstx"] - }, - "application/vnd.hyper+json": { - source: "iana", - compressible: true - }, - "application/vnd.hyper-item+json": { - source: "iana", - compressible: true - }, - "application/vnd.hyperdrive+json": { - source: "iana", - compressible: true - }, - "application/vnd.hzn-3d-crossword": { - source: "iana" - }, - "application/vnd.ibm.afplinedata": { - source: "apache" - }, - "application/vnd.ibm.electronic-media": { - source: "iana" - }, - "application/vnd.ibm.minipay": { - source: "iana", - extensions: ["mpy"] - }, - "application/vnd.ibm.modcap": { - source: "apache", - extensions: ["afp", "listafp", "list3820"] - }, - "application/vnd.ibm.rights-management": { - source: "iana", - extensions: ["irm"] - }, - "application/vnd.ibm.secure-container": { - source: "iana", - extensions: ["sc"] - }, - "application/vnd.iccprofile": { - source: "iana", - extensions: ["icc", "icm"] - }, - "application/vnd.ieee.1905": { - source: "iana" - }, - "application/vnd.igloader": { - source: "iana", - extensions: ["igl"] - }, - "application/vnd.imagemeter.folder+zip": { - source: "iana", - compressible: false - }, - "application/vnd.imagemeter.image+zip": { - source: "iana", - compressible: false - }, - "application/vnd.immervision-ivp": { - source: "iana", - extensions: ["ivp"] - }, - "application/vnd.immervision-ivu": { - source: "iana", - extensions: ["ivu"] - }, - "application/vnd.ims.imsccv1p1": { - source: "iana" - }, - "application/vnd.ims.imsccv1p2": { - source: "iana" - }, - "application/vnd.ims.imsccv1p3": { - source: "iana" - }, - "application/vnd.ims.lis.v2.result+json": { - source: "iana", - compressible: true - }, - "application/vnd.ims.lti.v2.toolconsumerprofile+json": { - source: "iana", - compressible: true - }, - "application/vnd.ims.lti.v2.toolproxy+json": { - source: "iana", - compressible: true - }, - "application/vnd.ims.lti.v2.toolproxy.id+json": { - source: "iana", - compressible: true - }, - "application/vnd.ims.lti.v2.toolsettings+json": { - source: "iana", - compressible: true - }, - "application/vnd.ims.lti.v2.toolsettings.simple+json": { - source: "iana", - compressible: true - }, - "application/vnd.informedcontrol.rms+xml": { - source: "iana", - compressible: true - }, - "application/vnd.informix-visionary": { - source: "apache" - }, - "application/vnd.infotech.project": { - source: "iana" - }, - "application/vnd.infotech.project+xml": { - source: "iana", - compressible: true - }, - "application/vnd.innopath.wamp.notification": { - source: "iana" - }, - "application/vnd.insors.igm": { - source: "iana", - extensions: ["igm"] - }, - "application/vnd.intercon.formnet": { - source: "iana", - extensions: ["xpw", "xpx"] - }, - "application/vnd.intergeo": { - source: "iana", - extensions: ["i2g"] - }, - "application/vnd.intertrust.digibox": { - source: "iana" - }, - "application/vnd.intertrust.nncp": { - source: "iana" - }, - "application/vnd.intu.qbo": { - source: "iana", - extensions: ["qbo"] - }, - "application/vnd.intu.qfx": { - source: "iana", - extensions: ["qfx"] - }, - "application/vnd.ipfs.ipns-record": { - source: "iana" - }, - "application/vnd.ipld.car": { - source: "iana" - }, - "application/vnd.ipld.dag-cbor": { - source: "iana" - }, - "application/vnd.ipld.dag-json": { - source: "iana" - }, - "application/vnd.ipld.raw": { - source: "iana" - }, - "application/vnd.iptc.g2.catalogitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.conceptitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.knowledgeitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.newsitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.newsmessage+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.packageitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.iptc.g2.planningitem+xml": { - source: "iana", - compressible: true - }, - "application/vnd.ipunplugged.rcprofile": { - source: "iana", - extensions: ["rcprofile"] - }, - "application/vnd.irepository.package+xml": { - source: "iana", - compressible: true, - extensions: ["irp"] - }, - "application/vnd.is-xpr": { - source: "iana", - extensions: ["xpr"] - }, - "application/vnd.isac.fcs": { - source: "iana", - extensions: ["fcs"] - }, - "application/vnd.iso11783-10+zip": { - source: "iana", - compressible: false - }, - "application/vnd.jam": { - source: "iana", - extensions: ["jam"] - }, - "application/vnd.japannet-directory-service": { - source: "iana" - }, - "application/vnd.japannet-jpnstore-wakeup": { - source: "iana" - }, - "application/vnd.japannet-payment-wakeup": { - source: "iana" - }, - "application/vnd.japannet-registration": { - source: "iana" - }, - "application/vnd.japannet-registration-wakeup": { - source: "iana" - }, - "application/vnd.japannet-setstore-wakeup": { - source: "iana" - }, - "application/vnd.japannet-verification": { - source: "iana" - }, - "application/vnd.japannet-verification-wakeup": { - source: "iana" - }, - "application/vnd.jcp.javame.midlet-rms": { - source: "iana", - extensions: ["rms"] - }, - "application/vnd.jisp": { - source: "iana", - extensions: ["jisp"] - }, - "application/vnd.joost.joda-archive": { - source: "iana", - extensions: ["joda"] - }, - "application/vnd.jsk.isdn-ngn": { - source: "iana" - }, - "application/vnd.kahootz": { - source: "iana", - extensions: ["ktz", "ktr"] - }, - "application/vnd.kde.karbon": { - source: "iana", - extensions: ["karbon"] - }, - "application/vnd.kde.kchart": { - source: "iana", - extensions: ["chrt"] - }, - "application/vnd.kde.kformula": { - source: "iana", - extensions: ["kfo"] - }, - "application/vnd.kde.kivio": { - source: "iana", - extensions: ["flw"] - }, - "application/vnd.kde.kontour": { - source: "iana", - extensions: ["kon"] - }, - "application/vnd.kde.kpresenter": { - source: "iana", - extensions: ["kpr", "kpt"] - }, - "application/vnd.kde.kspread": { - source: "iana", - extensions: ["ksp"] - }, - "application/vnd.kde.kword": { - source: "iana", - extensions: ["kwd", "kwt"] - }, - "application/vnd.kdl": { - source: "iana" - }, - "application/vnd.kenameaapp": { - source: "iana", - extensions: ["htke"] - }, - "application/vnd.keyman.kmp+zip": { - source: "iana", - compressible: false - }, - "application/vnd.keyman.kmx": { - source: "iana" - }, - "application/vnd.kidspiration": { - source: "iana", - extensions: ["kia"] - }, - "application/vnd.kinar": { - source: "iana", - extensions: ["kne", "knp"] - }, - "application/vnd.koan": { - source: "iana", - extensions: ["skp", "skd", "skt", "skm"] - }, - "application/vnd.kodak-descriptor": { - source: "iana", - extensions: ["sse"] - }, - "application/vnd.las": { - source: "iana" - }, - "application/vnd.las.las+json": { - source: "iana", - compressible: true - }, - "application/vnd.las.las+xml": { - source: "iana", - compressible: true, - extensions: ["lasxml"] - }, - "application/vnd.laszip": { - source: "iana" - }, - "application/vnd.ldev.productlicensing": { - source: "iana" - }, - "application/vnd.leap+json": { - source: "iana", - compressible: true - }, - "application/vnd.liberty-request+xml": { - source: "iana", - compressible: true - }, - "application/vnd.llamagraphics.life-balance.desktop": { - source: "iana", - extensions: ["lbd"] - }, - "application/vnd.llamagraphics.life-balance.exchange+xml": { - source: "iana", - compressible: true, - extensions: ["lbe"] - }, - "application/vnd.logipipe.circuit+zip": { - source: "iana", - compressible: false - }, - "application/vnd.loom": { - source: "iana" - }, - "application/vnd.lotus-1-2-3": { - source: "iana", - extensions: ["123"] - }, - "application/vnd.lotus-approach": { - source: "iana", - extensions: ["apr"] - }, - "application/vnd.lotus-freelance": { - source: "iana", - extensions: ["pre"] - }, - "application/vnd.lotus-notes": { - source: "iana", - extensions: ["nsf"] - }, - "application/vnd.lotus-organizer": { - source: "iana", - extensions: ["org"] - }, - "application/vnd.lotus-screencam": { - source: "iana", - extensions: ["scm"] - }, - "application/vnd.lotus-wordpro": { - source: "iana", - extensions: ["lwp"] - }, - "application/vnd.macports.portpkg": { - source: "iana", - extensions: ["portpkg"] - }, - "application/vnd.mapbox-vector-tile": { - source: "iana", - extensions: ["mvt"] - }, - "application/vnd.marlin.drm.actiontoken+xml": { - source: "iana", - compressible: true - }, - "application/vnd.marlin.drm.conftoken+xml": { - source: "iana", - compressible: true - }, - "application/vnd.marlin.drm.license+xml": { - source: "iana", - compressible: true - }, - "application/vnd.marlin.drm.mdcf": { - source: "iana" - }, - "application/vnd.mason+json": { - source: "iana", - compressible: true - }, - "application/vnd.maxar.archive.3tz+zip": { - source: "iana", - compressible: false - }, - "application/vnd.maxmind.maxmind-db": { - source: "iana" - }, - "application/vnd.mcd": { - source: "iana", - extensions: ["mcd"] - }, - "application/vnd.mdl": { - source: "iana" - }, - "application/vnd.mdl-mbsdf": { - source: "iana" - }, - "application/vnd.medcalcdata": { - source: "iana", - extensions: ["mc1"] - }, - "application/vnd.mediastation.cdkey": { - source: "iana", - extensions: ["cdkey"] - }, - "application/vnd.medicalholodeck.recordxr": { - source: "iana" - }, - "application/vnd.meridian-slingshot": { - source: "iana" - }, - "application/vnd.mermaid": { - source: "iana" - }, - "application/vnd.mfer": { - source: "iana", - extensions: ["mwf"] - }, - "application/vnd.mfmp": { - source: "iana", - extensions: ["mfm"] - }, - "application/vnd.micro+json": { - source: "iana", - compressible: true - }, - "application/vnd.micrografx.flo": { - source: "iana", - extensions: ["flo"] - }, - "application/vnd.micrografx.igx": { - source: "iana", - extensions: ["igx"] - }, - "application/vnd.microsoft.portable-executable": { - source: "iana" - }, - "application/vnd.microsoft.windows.thumbnail-cache": { - source: "iana" - }, - "application/vnd.miele+json": { - source: "iana", - compressible: true - }, - "application/vnd.mif": { - source: "iana", - extensions: ["mif"] - }, - "application/vnd.minisoft-hp3000-save": { - source: "iana" - }, - "application/vnd.mitsubishi.misty-guard.trustweb": { - source: "iana" - }, - "application/vnd.mobius.daf": { - source: "iana", - extensions: ["daf"] - }, - "application/vnd.mobius.dis": { - source: "iana", - extensions: ["dis"] - }, - "application/vnd.mobius.mbk": { - source: "iana", - extensions: ["mbk"] - }, - "application/vnd.mobius.mqy": { - source: "iana", - extensions: ["mqy"] - }, - "application/vnd.mobius.msl": { - source: "iana", - extensions: ["msl"] - }, - "application/vnd.mobius.plc": { - source: "iana", - extensions: ["plc"] - }, - "application/vnd.mobius.txf": { - source: "iana", - extensions: ["txf"] - }, - "application/vnd.modl": { - source: "iana" - }, - "application/vnd.mophun.application": { - source: "iana", - extensions: ["mpn"] - }, - "application/vnd.mophun.certificate": { - source: "iana", - extensions: ["mpc"] - }, - "application/vnd.motorola.flexsuite": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.adsi": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.fis": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.gotap": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.kmr": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.ttc": { - source: "iana" - }, - "application/vnd.motorola.flexsuite.wem": { - source: "iana" - }, - "application/vnd.motorola.iprm": { - source: "iana" - }, - "application/vnd.mozilla.xul+xml": { - source: "iana", - compressible: true, - extensions: ["xul"] - }, - "application/vnd.ms-3mfdocument": { - source: "iana" - }, - "application/vnd.ms-artgalry": { - source: "iana", - extensions: ["cil"] - }, - "application/vnd.ms-asf": { - source: "iana" - }, - "application/vnd.ms-cab-compressed": { - source: "iana", - extensions: ["cab"] - }, - "application/vnd.ms-color.iccprofile": { - source: "apache" - }, - "application/vnd.ms-excel": { - source: "iana", - compressible: false, - extensions: ["xls", "xlm", "xla", "xlc", "xlt", "xlw"] - }, - "application/vnd.ms-excel.addin.macroenabled.12": { - source: "iana", - extensions: ["xlam"] - }, - "application/vnd.ms-excel.sheet.binary.macroenabled.12": { - source: "iana", - extensions: ["xlsb"] - }, - "application/vnd.ms-excel.sheet.macroenabled.12": { - source: "iana", - extensions: ["xlsm"] - }, - "application/vnd.ms-excel.template.macroenabled.12": { - source: "iana", - extensions: ["xltm"] - }, - "application/vnd.ms-fontobject": { - source: "iana", - compressible: true, - extensions: ["eot"] - }, - "application/vnd.ms-htmlhelp": { - source: "iana", - extensions: ["chm"] - }, - "application/vnd.ms-ims": { - source: "iana", - extensions: ["ims"] - }, - "application/vnd.ms-lrm": { - source: "iana", - extensions: ["lrm"] - }, - "application/vnd.ms-office.activex+xml": { - source: "iana", - compressible: true - }, - "application/vnd.ms-officetheme": { - source: "iana", - extensions: ["thmx"] - }, - "application/vnd.ms-opentype": { - source: "apache", - compressible: true - }, - "application/vnd.ms-outlook": { - compressible: false, - extensions: ["msg"] - }, - "application/vnd.ms-package.obfuscated-opentype": { - source: "apache" - }, - "application/vnd.ms-pki.seccat": { - source: "apache", - extensions: ["cat"] - }, - "application/vnd.ms-pki.stl": { - source: "apache", - extensions: ["stl"] - }, - "application/vnd.ms-playready.initiator+xml": { - source: "iana", - compressible: true - }, - "application/vnd.ms-powerpoint": { - source: "iana", - compressible: false, - extensions: ["ppt", "pps", "pot"] - }, - "application/vnd.ms-powerpoint.addin.macroenabled.12": { - source: "iana", - extensions: ["ppam"] - }, - "application/vnd.ms-powerpoint.presentation.macroenabled.12": { - source: "iana", - extensions: ["pptm"] - }, - "application/vnd.ms-powerpoint.slide.macroenabled.12": { - source: "iana", - extensions: ["sldm"] - }, - "application/vnd.ms-powerpoint.slideshow.macroenabled.12": { - source: "iana", - extensions: ["ppsm"] - }, - "application/vnd.ms-powerpoint.template.macroenabled.12": { - source: "iana", - extensions: ["potm"] - }, - "application/vnd.ms-printdevicecapabilities+xml": { - source: "iana", - compressible: true - }, - "application/vnd.ms-printing.printticket+xml": { - source: "apache", - compressible: true - }, - "application/vnd.ms-printschematicket+xml": { - source: "iana", - compressible: true - }, - "application/vnd.ms-project": { - source: "iana", - extensions: ["mpp", "mpt"] - }, - "application/vnd.ms-tnef": { - source: "iana" - }, - "application/vnd.ms-visio.viewer": { - extensions: ["vdx"] - }, - "application/vnd.ms-windows.devicepairing": { - source: "iana" - }, - "application/vnd.ms-windows.nwprinting.oob": { - source: "iana" - }, - "application/vnd.ms-windows.printerpairing": { - source: "iana" - }, - "application/vnd.ms-windows.wsd.oob": { - source: "iana" - }, - "application/vnd.ms-wmdrm.lic-chlg-req": { - source: "iana" - }, - "application/vnd.ms-wmdrm.lic-resp": { - source: "iana" - }, - "application/vnd.ms-wmdrm.meter-chlg-req": { - source: "iana" - }, - "application/vnd.ms-wmdrm.meter-resp": { - source: "iana" - }, - "application/vnd.ms-word.document.macroenabled.12": { - source: "iana", - extensions: ["docm"] - }, - "application/vnd.ms-word.template.macroenabled.12": { - source: "iana", - extensions: ["dotm"] - }, - "application/vnd.ms-works": { - source: "iana", - extensions: ["wps", "wks", "wcm", "wdb"] - }, - "application/vnd.ms-wpl": { - source: "iana", - extensions: ["wpl"] - }, - "application/vnd.ms-xpsdocument": { - source: "iana", - compressible: false, - extensions: ["xps"] - }, - "application/vnd.msa-disk-image": { - source: "iana" - }, - "application/vnd.mseq": { - source: "iana", - extensions: ["mseq"] - }, - "application/vnd.msgpack": { - source: "iana" - }, - "application/vnd.msign": { - source: "iana" - }, - "application/vnd.multiad.creator": { - source: "iana" - }, - "application/vnd.multiad.creator.cif": { - source: "iana" - }, - "application/vnd.music-niff": { - source: "iana" - }, - "application/vnd.musician": { - source: "iana", - extensions: ["mus"] - }, - "application/vnd.muvee.style": { - source: "iana", - extensions: ["msty"] - }, - "application/vnd.mynfc": { - source: "iana", - extensions: ["taglet"] - }, - "application/vnd.nacamar.ybrid+json": { - source: "iana", - compressible: true - }, - "application/vnd.nato.bindingdataobject+cbor": { - source: "iana" - }, - "application/vnd.nato.bindingdataobject+json": { - source: "iana", - compressible: true - }, - "application/vnd.nato.bindingdataobject+xml": { - source: "iana", - compressible: true, - extensions: ["bdo"] - }, - "application/vnd.nato.openxmlformats-package.iepd+zip": { - source: "iana", - compressible: false - }, - "application/vnd.ncd.control": { - source: "iana" - }, - "application/vnd.ncd.reference": { - source: "iana" - }, - "application/vnd.nearst.inv+json": { - source: "iana", - compressible: true - }, - "application/vnd.nebumind.line": { - source: "iana" - }, - "application/vnd.nervana": { - source: "iana" - }, - "application/vnd.netfpx": { - source: "iana" - }, - "application/vnd.neurolanguage.nlu": { - source: "iana", - extensions: ["nlu"] - }, - "application/vnd.nimn": { - source: "iana" - }, - "application/vnd.nintendo.nitro.rom": { - source: "iana" - }, - "application/vnd.nintendo.snes.rom": { - source: "iana" - }, - "application/vnd.nitf": { - source: "iana", - extensions: ["ntf", "nitf"] - }, - "application/vnd.noblenet-directory": { - source: "iana", - extensions: ["nnd"] - }, - "application/vnd.noblenet-sealer": { - source: "iana", - extensions: ["nns"] - }, - "application/vnd.noblenet-web": { - source: "iana", - extensions: ["nnw"] - }, - "application/vnd.nokia.catalogs": { - source: "iana" - }, - "application/vnd.nokia.conml+wbxml": { - source: "iana" - }, - "application/vnd.nokia.conml+xml": { - source: "iana", - compressible: true - }, - "application/vnd.nokia.iptv.config+xml": { - source: "iana", - compressible: true - }, - "application/vnd.nokia.isds-radio-presets": { - source: "iana" - }, - "application/vnd.nokia.landmark+wbxml": { - source: "iana" - }, - "application/vnd.nokia.landmark+xml": { - source: "iana", - compressible: true - }, - "application/vnd.nokia.landmarkcollection+xml": { - source: "iana", - compressible: true - }, - "application/vnd.nokia.n-gage.ac+xml": { - source: "iana", - compressible: true, - extensions: ["ac"] - }, - "application/vnd.nokia.n-gage.data": { - source: "iana", - extensions: ["ngdat"] - }, - "application/vnd.nokia.n-gage.symbian.install": { - source: "apache", - extensions: ["n-gage"] - }, - "application/vnd.nokia.ncd": { - source: "iana" - }, - "application/vnd.nokia.pcd+wbxml": { - source: "iana" - }, - "application/vnd.nokia.pcd+xml": { - source: "iana", - compressible: true - }, - "application/vnd.nokia.radio-preset": { - source: "iana", - extensions: ["rpst"] - }, - "application/vnd.nokia.radio-presets": { - source: "iana", - extensions: ["rpss"] - }, - "application/vnd.novadigm.edm": { - source: "iana", - extensions: ["edm"] - }, - "application/vnd.novadigm.edx": { - source: "iana", - extensions: ["edx"] - }, - "application/vnd.novadigm.ext": { - source: "iana", - extensions: ["ext"] - }, - "application/vnd.ntt-local.content-share": { - source: "iana" - }, - "application/vnd.ntt-local.file-transfer": { - source: "iana" - }, - "application/vnd.ntt-local.ogw_remote-access": { - source: "iana" - }, - "application/vnd.ntt-local.sip-ta_remote": { - source: "iana" - }, - "application/vnd.ntt-local.sip-ta_tcp_stream": { - source: "iana" - }, - "application/vnd.oai.workflows": { - source: "iana" - }, - "application/vnd.oai.workflows+json": { - source: "iana", - compressible: true - }, - "application/vnd.oai.workflows+yaml": { - source: "iana" - }, - "application/vnd.oasis.opendocument.base": { - source: "iana" - }, - "application/vnd.oasis.opendocument.chart": { - source: "iana", - extensions: ["odc"] - }, - "application/vnd.oasis.opendocument.chart-template": { - source: "iana", - extensions: ["otc"] - }, - "application/vnd.oasis.opendocument.database": { - source: "apache", - extensions: ["odb"] - }, - "application/vnd.oasis.opendocument.formula": { - source: "iana", - extensions: ["odf"] - }, - "application/vnd.oasis.opendocument.formula-template": { - source: "iana", - extensions: ["odft"] - }, - "application/vnd.oasis.opendocument.graphics": { - source: "iana", - compressible: false, - extensions: ["odg"] - }, - "application/vnd.oasis.opendocument.graphics-template": { - source: "iana", - extensions: ["otg"] - }, - "application/vnd.oasis.opendocument.image": { - source: "iana", - extensions: ["odi"] - }, - "application/vnd.oasis.opendocument.image-template": { - source: "iana", - extensions: ["oti"] - }, - "application/vnd.oasis.opendocument.presentation": { - source: "iana", - compressible: false, - extensions: ["odp"] - }, - "application/vnd.oasis.opendocument.presentation-template": { - source: "iana", - extensions: ["otp"] - }, - "application/vnd.oasis.opendocument.spreadsheet": { - source: "iana", - compressible: false, - extensions: ["ods"] - }, - "application/vnd.oasis.opendocument.spreadsheet-template": { - source: "iana", - extensions: ["ots"] - }, - "application/vnd.oasis.opendocument.text": { - source: "iana", - compressible: false, - extensions: ["odt"] - }, - "application/vnd.oasis.opendocument.text-master": { - source: "iana", - extensions: ["odm"] - }, - "application/vnd.oasis.opendocument.text-master-template": { - source: "iana" - }, - "application/vnd.oasis.opendocument.text-template": { - source: "iana", - extensions: ["ott"] - }, - "application/vnd.oasis.opendocument.text-web": { - source: "iana", - extensions: ["oth"] - }, - "application/vnd.obn": { - source: "iana" - }, - "application/vnd.ocf+cbor": { - source: "iana" - }, - "application/vnd.oci.image.manifest.v1+json": { - source: "iana", - compressible: true - }, - "application/vnd.oftn.l10n+json": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.contentaccessdownload+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.contentaccessstreaming+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.cspg-hexbinary": { - source: "iana" - }, - "application/vnd.oipf.dae.svg+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.dae.xhtml+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.mippvcontrolmessage+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.pae.gem": { - source: "iana" - }, - "application/vnd.oipf.spdiscovery+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.spdlist+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.ueprofile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oipf.userprofile+xml": { - source: "iana", - compressible: true - }, - "application/vnd.olpc-sugar": { - source: "iana", - extensions: ["xo"] - }, - "application/vnd.oma-scws-config": { - source: "iana" - }, - "application/vnd.oma-scws-http-request": { - source: "iana" - }, - "application/vnd.oma-scws-http-response": { - source: "iana" - }, - "application/vnd.oma.bcast.associated-procedure-parameter+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.bcast.drm-trigger+xml": { - source: "apache", - compressible: true - }, - "application/vnd.oma.bcast.imd+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.bcast.ltkm": { - source: "iana" - }, - "application/vnd.oma.bcast.notification+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.bcast.provisioningtrigger": { - source: "iana" - }, - "application/vnd.oma.bcast.sgboot": { - source: "iana" - }, - "application/vnd.oma.bcast.sgdd+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.bcast.sgdu": { - source: "iana" - }, - "application/vnd.oma.bcast.simple-symbol-container": { - source: "iana" - }, - "application/vnd.oma.bcast.smartcard-trigger+xml": { - source: "apache", - compressible: true - }, - "application/vnd.oma.bcast.sprov+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.bcast.stkm": { - source: "iana" - }, - "application/vnd.oma.cab-address-book+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.cab-feature-handler+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.cab-pcc+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.cab-subs-invite+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.cab-user-prefs+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.dcd": { - source: "iana" - }, - "application/vnd.oma.dcdc": { - source: "iana" - }, - "application/vnd.oma.dd2+xml": { - source: "iana", - compressible: true, - extensions: ["dd2"] - }, - "application/vnd.oma.drm.risd+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.group-usage-list+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.lwm2m+cbor": { - source: "iana" - }, - "application/vnd.oma.lwm2m+json": { - source: "iana", - compressible: true - }, - "application/vnd.oma.lwm2m+tlv": { - source: "iana" - }, - "application/vnd.oma.pal+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.poc.detailed-progress-report+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.poc.final-report+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.poc.groups+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.poc.invocation-descriptor+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.poc.optimized-progress-report+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.push": { - source: "iana" - }, - "application/vnd.oma.scidm.messages+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oma.xcap-directory+xml": { - source: "iana", - compressible: true - }, - "application/vnd.omads-email+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/vnd.omads-file+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/vnd.omads-folder+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/vnd.omaloc-supl-init": { - source: "iana" - }, - "application/vnd.onepager": { - source: "iana" - }, - "application/vnd.onepagertamp": { - source: "iana" - }, - "application/vnd.onepagertamx": { - source: "iana" - }, - "application/vnd.onepagertat": { - source: "iana" - }, - "application/vnd.onepagertatp": { - source: "iana" - }, - "application/vnd.onepagertatx": { - source: "iana" - }, - "application/vnd.onvif.metadata": { - source: "iana" - }, - "application/vnd.openblox.game+xml": { - source: "iana", - compressible: true, - extensions: ["obgx"] - }, - "application/vnd.openblox.game-binary": { - source: "iana" - }, - "application/vnd.openeye.oeb": { - source: "iana" - }, - "application/vnd.openofficeorg.extension": { - source: "apache", - extensions: ["oxt"] - }, - "application/vnd.openstreetmap.data+xml": { - source: "iana", - compressible: true, - extensions: ["osm"] - }, - "application/vnd.opentimestamps.ots": { - source: "iana" - }, - "application/vnd.openvpi.dspx+json": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.custom-properties+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.customxmlproperties+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawing+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.extended-properties+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.comments+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.presentation": { - source: "iana", - compressible: false, - extensions: ["pptx"] - }, - "application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.presprops+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.slide": { - source: "iana", - extensions: ["sldx"] - }, - "application/vnd.openxmlformats-officedocument.presentationml.slide+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.slideshow": { - source: "iana", - extensions: ["ppsx"] - }, - "application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.tags+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.template": { - source: "iana", - extensions: ["potx"] - }, - "application/vnd.openxmlformats-officedocument.presentationml.template.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": { - source: "iana", - compressible: false, - extensions: ["xlsx"] - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.template": { - source: "iana", - extensions: ["xltx"] - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.theme+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.themeoverride+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.vmldrawing": { - source: "iana" - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.document": { - source: "iana", - compressible: false, - extensions: ["docx"] - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.template": { - source: "iana", - extensions: ["dotx"] - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-package.core-properties+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml": { - source: "iana", - compressible: true - }, - "application/vnd.openxmlformats-package.relationships+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oracle.resource+json": { - source: "iana", - compressible: true - }, - "application/vnd.orange.indata": { - source: "iana" - }, - "application/vnd.osa.netdeploy": { - source: "iana" - }, - "application/vnd.osgeo.mapguide.package": { - source: "iana", - extensions: ["mgp"] - }, - "application/vnd.osgi.bundle": { - source: "iana" - }, - "application/vnd.osgi.dp": { - source: "iana", - extensions: ["dp"] - }, - "application/vnd.osgi.subsystem": { - source: "iana", - extensions: ["esa"] - }, - "application/vnd.otps.ct-kip+xml": { - source: "iana", - compressible: true - }, - "application/vnd.oxli.countgraph": { - source: "iana" - }, - "application/vnd.pagerduty+json": { - source: "iana", - compressible: true - }, - "application/vnd.palm": { - source: "iana", - extensions: ["pdb", "pqa", "oprc"] - }, - "application/vnd.panoply": { - source: "iana" - }, - "application/vnd.paos.xml": { - source: "iana" - }, - "application/vnd.patentdive": { - source: "iana" - }, - "application/vnd.patientecommsdoc": { - source: "iana" - }, - "application/vnd.pawaafile": { - source: "iana", - extensions: ["paw"] - }, - "application/vnd.pcos": { - source: "iana" - }, - "application/vnd.pg.format": { - source: "iana", - extensions: ["str"] - }, - "application/vnd.pg.osasli": { - source: "iana", - extensions: ["ei6"] - }, - "application/vnd.piaccess.application-licence": { - source: "iana" - }, - "application/vnd.picsel": { - source: "iana", - extensions: ["efif"] - }, - "application/vnd.pmi.widget": { - source: "iana", - extensions: ["wg"] - }, - "application/vnd.poc.group-advertisement+xml": { - source: "iana", - compressible: true - }, - "application/vnd.pocketlearn": { - source: "iana", - extensions: ["plf"] - }, - "application/vnd.powerbuilder6": { - source: "iana", - extensions: ["pbd"] - }, - "application/vnd.powerbuilder6-s": { - source: "iana" - }, - "application/vnd.powerbuilder7": { - source: "iana" - }, - "application/vnd.powerbuilder7-s": { - source: "iana" - }, - "application/vnd.powerbuilder75": { - source: "iana" - }, - "application/vnd.powerbuilder75-s": { - source: "iana" - }, - "application/vnd.preminet": { - source: "iana" - }, - "application/vnd.previewsystems.box": { - source: "iana", - extensions: ["box"] - }, - "application/vnd.procrate.brushset": { - extensions: ["brushset"] - }, - "application/vnd.procreate.brush": { - extensions: ["brush"] - }, - "application/vnd.procreate.dream": { - extensions: ["drm"] - }, - "application/vnd.proteus.magazine": { - source: "iana", - extensions: ["mgz"] - }, - "application/vnd.psfs": { - source: "iana" - }, - "application/vnd.pt.mundusmundi": { - source: "iana" - }, - "application/vnd.publishare-delta-tree": { - source: "iana", - extensions: ["qps"] - }, - "application/vnd.pvi.ptid1": { - source: "iana", - extensions: ["ptid"] - }, - "application/vnd.pwg-multiplexed": { - source: "iana" - }, - "application/vnd.pwg-xhtml-print+xml": { - source: "iana", - compressible: true, - extensions: ["xhtm"] - }, - "application/vnd.qualcomm.brew-app-res": { - source: "iana" - }, - "application/vnd.quarantainenet": { - source: "iana" - }, - "application/vnd.quark.quarkxpress": { - source: "iana", - extensions: ["qxd", "qxt", "qwd", "qwt", "qxl", "qxb"] - }, - "application/vnd.quobject-quoxdocument": { - source: "iana" - }, - "application/vnd.radisys.moml+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-audit+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-audit-conf+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-audit-conn+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-audit-dialog+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-audit-stream+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-conf+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-base+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-fax-detect+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-fax-sendrecv+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-group+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-speech+xml": { - source: "iana", - compressible: true - }, - "application/vnd.radisys.msml-dialog-transform+xml": { - source: "iana", - compressible: true - }, - "application/vnd.rainstor.data": { - source: "iana" - }, - "application/vnd.rapid": { - source: "iana" - }, - "application/vnd.rar": { - source: "iana", - extensions: ["rar"] - }, - "application/vnd.realvnc.bed": { - source: "iana", - extensions: ["bed"] - }, - "application/vnd.recordare.musicxml": { - source: "iana", - extensions: ["mxl"] - }, - "application/vnd.recordare.musicxml+xml": { - source: "iana", - compressible: true, - extensions: ["musicxml"] - }, - "application/vnd.relpipe": { - source: "iana" - }, - "application/vnd.renlearn.rlprint": { - source: "iana" - }, - "application/vnd.resilient.logic": { - source: "iana" - }, - "application/vnd.restful+json": { - source: "iana", - compressible: true - }, - "application/vnd.rig.cryptonote": { - source: "iana", - extensions: ["cryptonote"] - }, - "application/vnd.rim.cod": { - source: "apache", - extensions: ["cod"] - }, - "application/vnd.rn-realmedia": { - source: "apache", - extensions: ["rm"] - }, - "application/vnd.rn-realmedia-vbr": { - source: "apache", - extensions: ["rmvb"] - }, - "application/vnd.route66.link66+xml": { - source: "iana", - compressible: true, - extensions: ["link66"] - }, - "application/vnd.rs-274x": { - source: "iana" - }, - "application/vnd.ruckus.download": { - source: "iana" - }, - "application/vnd.s3sms": { - source: "iana" - }, - "application/vnd.sailingtracker.track": { - source: "iana", - extensions: ["st"] - }, - "application/vnd.sar": { - source: "iana" - }, - "application/vnd.sbm.cid": { - source: "iana" - }, - "application/vnd.sbm.mid2": { - source: "iana" - }, - "application/vnd.scribus": { - source: "iana" - }, - "application/vnd.sealed.3df": { - source: "iana" - }, - "application/vnd.sealed.csf": { - source: "iana" - }, - "application/vnd.sealed.doc": { - source: "iana" - }, - "application/vnd.sealed.eml": { - source: "iana" - }, - "application/vnd.sealed.mht": { - source: "iana" - }, - "application/vnd.sealed.net": { - source: "iana" - }, - "application/vnd.sealed.ppt": { - source: "iana" - }, - "application/vnd.sealed.tiff": { - source: "iana" - }, - "application/vnd.sealed.xls": { - source: "iana" - }, - "application/vnd.sealedmedia.softseal.html": { - source: "iana" - }, - "application/vnd.sealedmedia.softseal.pdf": { - source: "iana" - }, - "application/vnd.seemail": { - source: "iana", - extensions: ["see"] - }, - "application/vnd.seis+json": { - source: "iana", - compressible: true - }, - "application/vnd.sema": { - source: "iana", - extensions: ["sema"] - }, - "application/vnd.semd": { - source: "iana", - extensions: ["semd"] - }, - "application/vnd.semf": { - source: "iana", - extensions: ["semf"] - }, - "application/vnd.shade-save-file": { - source: "iana" - }, - "application/vnd.shana.informed.formdata": { - source: "iana", - extensions: ["ifm"] - }, - "application/vnd.shana.informed.formtemplate": { - source: "iana", - extensions: ["itp"] - }, - "application/vnd.shana.informed.interchange": { - source: "iana", - extensions: ["iif"] - }, - "application/vnd.shana.informed.package": { - source: "iana", - extensions: ["ipk"] - }, - "application/vnd.shootproof+json": { - source: "iana", - compressible: true - }, - "application/vnd.shopkick+json": { - source: "iana", - compressible: true - }, - "application/vnd.shp": { - source: "iana" - }, - "application/vnd.shx": { - source: "iana" - }, - "application/vnd.sigrok.session": { - source: "iana" - }, - "application/vnd.simtech-mindmapper": { - source: "iana", - extensions: ["twd", "twds"] - }, - "application/vnd.siren+json": { - source: "iana", - compressible: true - }, - "application/vnd.sketchometry": { - source: "iana" - }, - "application/vnd.smaf": { - source: "iana", - extensions: ["mmf"] - }, - "application/vnd.smart.notebook": { - source: "iana" - }, - "application/vnd.smart.teacher": { - source: "iana", - extensions: ["teacher"] - }, - "application/vnd.smintio.portals.archive": { - source: "iana" - }, - "application/vnd.snesdev-page-table": { - source: "iana" - }, - "application/vnd.software602.filler.form+xml": { - source: "iana", - compressible: true, - extensions: ["fo"] - }, - "application/vnd.software602.filler.form-xml-zip": { - source: "iana" - }, - "application/vnd.solent.sdkm+xml": { - source: "iana", - compressible: true, - extensions: ["sdkm", "sdkd"] - }, - "application/vnd.spotfire.dxp": { - source: "iana", - extensions: ["dxp"] - }, - "application/vnd.spotfire.sfs": { - source: "iana", - extensions: ["sfs"] - }, - "application/vnd.sqlite3": { - source: "iana" - }, - "application/vnd.sss-cod": { - source: "iana" - }, - "application/vnd.sss-dtf": { - source: "iana" - }, - "application/vnd.sss-ntf": { - source: "iana" - }, - "application/vnd.stardivision.calc": { - source: "apache", - extensions: ["sdc"] - }, - "application/vnd.stardivision.draw": { - source: "apache", - extensions: ["sda"] - }, - "application/vnd.stardivision.impress": { - source: "apache", - extensions: ["sdd"] - }, - "application/vnd.stardivision.math": { - source: "apache", - extensions: ["smf"] - }, - "application/vnd.stardivision.writer": { - source: "apache", - extensions: ["sdw", "vor"] - }, - "application/vnd.stardivision.writer-global": { - source: "apache", - extensions: ["sgl"] - }, - "application/vnd.stepmania.package": { - source: "iana", - extensions: ["smzip"] - }, - "application/vnd.stepmania.stepchart": { - source: "iana", - extensions: ["sm"] - }, - "application/vnd.street-stream": { - source: "iana" - }, - "application/vnd.sun.wadl+xml": { - source: "iana", - compressible: true, - extensions: ["wadl"] - }, - "application/vnd.sun.xml.calc": { - source: "apache", - extensions: ["sxc"] - }, - "application/vnd.sun.xml.calc.template": { - source: "apache", - extensions: ["stc"] - }, - "application/vnd.sun.xml.draw": { - source: "apache", - extensions: ["sxd"] - }, - "application/vnd.sun.xml.draw.template": { - source: "apache", - extensions: ["std"] - }, - "application/vnd.sun.xml.impress": { - source: "apache", - extensions: ["sxi"] - }, - "application/vnd.sun.xml.impress.template": { - source: "apache", - extensions: ["sti"] - }, - "application/vnd.sun.xml.math": { - source: "apache", - extensions: ["sxm"] - }, - "application/vnd.sun.xml.writer": { - source: "apache", - extensions: ["sxw"] - }, - "application/vnd.sun.xml.writer.global": { - source: "apache", - extensions: ["sxg"] - }, - "application/vnd.sun.xml.writer.template": { - source: "apache", - extensions: ["stw"] - }, - "application/vnd.sus-calendar": { - source: "iana", - extensions: ["sus", "susp"] - }, - "application/vnd.svd": { - source: "iana", - extensions: ["svd"] - }, - "application/vnd.swiftview-ics": { - source: "iana" - }, - "application/vnd.sybyl.mol2": { - source: "iana" - }, - "application/vnd.sycle+xml": { - source: "iana", - compressible: true - }, - "application/vnd.syft+json": { - source: "iana", - compressible: true - }, - "application/vnd.symbian.install": { - source: "apache", - extensions: ["sis", "sisx"] - }, - "application/vnd.syncml+xml": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["xsm"] - }, - "application/vnd.syncml.dm+wbxml": { - source: "iana", - charset: "UTF-8", - extensions: ["bdm"] - }, - "application/vnd.syncml.dm+xml": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["xdm"] - }, - "application/vnd.syncml.dm.notification": { - source: "iana" - }, - "application/vnd.syncml.dmddf+wbxml": { - source: "iana" - }, - "application/vnd.syncml.dmddf+xml": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["ddf"] - }, - "application/vnd.syncml.dmtnds+wbxml": { - source: "iana" - }, - "application/vnd.syncml.dmtnds+xml": { - source: "iana", - charset: "UTF-8", - compressible: true - }, - "application/vnd.syncml.ds.notification": { - source: "iana" - }, - "application/vnd.tableschema+json": { - source: "iana", - compressible: true - }, - "application/vnd.tao.intent-module-archive": { - source: "iana", - extensions: ["tao"] - }, - "application/vnd.tcpdump.pcap": { - source: "iana", - extensions: ["pcap", "cap", "dmp"] - }, - "application/vnd.think-cell.ppttc+json": { - source: "iana", - compressible: true - }, - "application/vnd.tmd.mediaflex.api+xml": { - source: "iana", - compressible: true - }, - "application/vnd.tml": { - source: "iana" - }, - "application/vnd.tmobile-livetv": { - source: "iana", - extensions: ["tmo"] - }, - "application/vnd.tri.onesource": { - source: "iana" - }, - "application/vnd.trid.tpt": { - source: "iana", - extensions: ["tpt"] - }, - "application/vnd.triscape.mxs": { - source: "iana", - extensions: ["mxs"] - }, - "application/vnd.trueapp": { - source: "iana", - extensions: ["tra"] - }, - "application/vnd.truedoc": { - source: "iana" - }, - "application/vnd.ubisoft.webplayer": { - source: "iana" - }, - "application/vnd.ufdl": { - source: "iana", - extensions: ["ufd", "ufdl"] - }, - "application/vnd.uic.osdm+json": { - source: "iana", - compressible: true - }, - "application/vnd.uiq.theme": { - source: "iana", - extensions: ["utz"] - }, - "application/vnd.umajin": { - source: "iana", - extensions: ["umj"] - }, - "application/vnd.unity": { - source: "iana", - extensions: ["unityweb"] - }, - "application/vnd.uoml+xml": { - source: "iana", - compressible: true, - extensions: ["uoml", "uo"] - }, - "application/vnd.uplanet.alert": { - source: "iana" - }, - "application/vnd.uplanet.alert-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.bearer-choice": { - source: "iana" - }, - "application/vnd.uplanet.bearer-choice-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.cacheop": { - source: "iana" - }, - "application/vnd.uplanet.cacheop-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.channel": { - source: "iana" - }, - "application/vnd.uplanet.channel-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.list": { - source: "iana" - }, - "application/vnd.uplanet.list-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.listcmd": { - source: "iana" - }, - "application/vnd.uplanet.listcmd-wbxml": { - source: "iana" - }, - "application/vnd.uplanet.signal": { - source: "iana" - }, - "application/vnd.uri-map": { - source: "iana" - }, - "application/vnd.valve.source.material": { - source: "iana" - }, - "application/vnd.vcx": { - source: "iana", - extensions: ["vcx"] - }, - "application/vnd.vd-study": { - source: "iana" - }, - "application/vnd.vectorworks": { - source: "iana" - }, - "application/vnd.vel+json": { - source: "iana", - compressible: true - }, - "application/vnd.veraison.tsm-report+cbor": { - source: "iana" - }, - "application/vnd.veraison.tsm-report+json": { - source: "iana", - compressible: true - }, - "application/vnd.verimatrix.vcas": { - source: "iana" - }, - "application/vnd.veritone.aion+json": { - source: "iana", - compressible: true - }, - "application/vnd.veryant.thin": { - source: "iana" - }, - "application/vnd.ves.encrypted": { - source: "iana" - }, - "application/vnd.vidsoft.vidconference": { - source: "iana" - }, - "application/vnd.visio": { - source: "iana", - extensions: ["vsd", "vst", "vss", "vsw", "vsdx", "vtx"] - }, - "application/vnd.visionary": { - source: "iana", - extensions: ["vis"] - }, - "application/vnd.vividence.scriptfile": { - source: "iana" - }, - "application/vnd.vocalshaper.vsp4": { - source: "iana" - }, - "application/vnd.vsf": { - source: "iana", - extensions: ["vsf"] - }, - "application/vnd.wap.sic": { - source: "iana" - }, - "application/vnd.wap.slc": { - source: "iana" - }, - "application/vnd.wap.wbxml": { - source: "iana", - charset: "UTF-8", - extensions: ["wbxml"] - }, - "application/vnd.wap.wmlc": { - source: "iana", - extensions: ["wmlc"] - }, - "application/vnd.wap.wmlscriptc": { - source: "iana", - extensions: ["wmlsc"] - }, - "application/vnd.wasmflow.wafl": { - source: "iana" - }, - "application/vnd.webturbo": { - source: "iana", - extensions: ["wtb"] - }, - "application/vnd.wfa.dpp": { - source: "iana" - }, - "application/vnd.wfa.p2p": { - source: "iana" - }, - "application/vnd.wfa.wsc": { - source: "iana" - }, - "application/vnd.windows.devicepairing": { - source: "iana" - }, - "application/vnd.wmc": { - source: "iana" - }, - "application/vnd.wmf.bootstrap": { - source: "iana" - }, - "application/vnd.wolfram.mathematica": { - source: "iana" - }, - "application/vnd.wolfram.mathematica.package": { - source: "iana" - }, - "application/vnd.wolfram.player": { - source: "iana", - extensions: ["nbp"] - }, - "application/vnd.wordlift": { - source: "iana" - }, - "application/vnd.wordperfect": { - source: "iana", - extensions: ["wpd"] - }, - "application/vnd.wqd": { - source: "iana", - extensions: ["wqd"] - }, - "application/vnd.wrq-hp3000-labelled": { - source: "iana" - }, - "application/vnd.wt.stf": { - source: "iana", - extensions: ["stf"] - }, - "application/vnd.wv.csp+wbxml": { - source: "iana" - }, - "application/vnd.wv.csp+xml": { - source: "iana", - compressible: true - }, - "application/vnd.wv.ssp+xml": { - source: "iana", - compressible: true - }, - "application/vnd.xacml+json": { - source: "iana", - compressible: true - }, - "application/vnd.xara": { - source: "iana", - extensions: ["xar"] - }, - "application/vnd.xarin.cpj": { - source: "iana" - }, - "application/vnd.xecrets-encrypted": { - source: "iana" - }, - "application/vnd.xfdl": { - source: "iana", - extensions: ["xfdl"] - }, - "application/vnd.xfdl.webform": { - source: "iana" - }, - "application/vnd.xmi+xml": { - source: "iana", - compressible: true - }, - "application/vnd.xmpie.cpkg": { - source: "iana" - }, - "application/vnd.xmpie.dpkg": { - source: "iana" - }, - "application/vnd.xmpie.plan": { - source: "iana" - }, - "application/vnd.xmpie.ppkg": { - source: "iana" - }, - "application/vnd.xmpie.xlim": { - source: "iana" - }, - "application/vnd.yamaha.hv-dic": { - source: "iana", - extensions: ["hvd"] - }, - "application/vnd.yamaha.hv-script": { - source: "iana", - extensions: ["hvs"] - }, - "application/vnd.yamaha.hv-voice": { - source: "iana", - extensions: ["hvp"] - }, - "application/vnd.yamaha.openscoreformat": { - source: "iana", - extensions: ["osf"] - }, - "application/vnd.yamaha.openscoreformat.osfpvg+xml": { - source: "iana", - compressible: true, - extensions: ["osfpvg"] - }, - "application/vnd.yamaha.remote-setup": { - source: "iana" - }, - "application/vnd.yamaha.smaf-audio": { - source: "iana", - extensions: ["saf"] - }, - "application/vnd.yamaha.smaf-phrase": { - source: "iana", - extensions: ["spf"] - }, - "application/vnd.yamaha.through-ngn": { - source: "iana" - }, - "application/vnd.yamaha.tunnel-udpencap": { - source: "iana" - }, - "application/vnd.yaoweme": { - source: "iana" - }, - "application/vnd.yellowriver-custom-menu": { - source: "iana", - extensions: ["cmp"] - }, - "application/vnd.zul": { - source: "iana", - extensions: ["zir", "zirz"] - }, - "application/vnd.zzazz.deck+xml": { - source: "iana", - compressible: true, - extensions: ["zaz"] - }, - "application/voicexml+xml": { - source: "iana", - compressible: true, - extensions: ["vxml"] - }, - "application/voucher-cms+json": { - source: "iana", - compressible: true - }, - "application/voucher-jws+json": { - source: "iana", - compressible: true - }, - "application/vp": { - source: "iana" - }, - "application/vp+cose": { - source: "iana" - }, - "application/vp+jwt": { - source: "iana" - }, - "application/vq-rtcpxr": { - source: "iana" - }, - "application/wasm": { - source: "iana", - compressible: true, - extensions: ["wasm"] - }, - "application/watcherinfo+xml": { - source: "iana", - compressible: true, - extensions: ["wif"] - }, - "application/webpush-options+json": { - source: "iana", - compressible: true - }, - "application/whoispp-query": { - source: "iana" - }, - "application/whoispp-response": { - source: "iana" - }, - "application/widget": { - source: "iana", - extensions: ["wgt"] - }, - "application/winhlp": { - source: "apache", - extensions: ["hlp"] - }, - "application/wita": { - source: "iana" - }, - "application/wordperfect5.1": { - source: "iana" - }, - "application/wsdl+xml": { - source: "iana", - compressible: true, - extensions: ["wsdl"] - }, - "application/wspolicy+xml": { - source: "iana", - compressible: true, - extensions: ["wspolicy"] - }, - "application/x-7z-compressed": { - source: "apache", - compressible: false, - extensions: ["7z"] - }, - "application/x-abiword": { - source: "apache", - extensions: ["abw"] - }, - "application/x-ace-compressed": { - source: "apache", - extensions: ["ace"] - }, - "application/x-amf": { - source: "apache" - }, - "application/x-apple-diskimage": { - source: "apache", - extensions: ["dmg"] - }, - "application/x-arj": { - compressible: false, - extensions: ["arj"] - }, - "application/x-authorware-bin": { - source: "apache", - extensions: ["aab", "x32", "u32", "vox"] - }, - "application/x-authorware-map": { - source: "apache", - extensions: ["aam"] - }, - "application/x-authorware-seg": { - source: "apache", - extensions: ["aas"] - }, - "application/x-bcpio": { - source: "apache", - extensions: ["bcpio"] - }, - "application/x-bdoc": { - compressible: false, - extensions: ["bdoc"] - }, - "application/x-bittorrent": { - source: "apache", - extensions: ["torrent"] - }, - "application/x-blender": { - extensions: ["blend"] - }, - "application/x-blorb": { - source: "apache", - extensions: ["blb", "blorb"] - }, - "application/x-bzip": { - source: "apache", - compressible: false, - extensions: ["bz"] - }, - "application/x-bzip2": { - source: "apache", - compressible: false, - extensions: ["bz2", "boz"] - }, - "application/x-cbr": { - source: "apache", - extensions: ["cbr", "cba", "cbt", "cbz", "cb7"] - }, - "application/x-cdlink": { - source: "apache", - extensions: ["vcd"] - }, - "application/x-cfs-compressed": { - source: "apache", - extensions: ["cfs"] - }, - "application/x-chat": { - source: "apache", - extensions: ["chat"] - }, - "application/x-chess-pgn": { - source: "apache", - extensions: ["pgn"] - }, - "application/x-chrome-extension": { - extensions: ["crx"] - }, - "application/x-cocoa": { - source: "nginx", - extensions: ["cco"] - }, - "application/x-compress": { - source: "apache" - }, - "application/x-compressed": { - extensions: ["rar"] - }, - "application/x-conference": { - source: "apache", - extensions: ["nsc"] - }, - "application/x-cpio": { - source: "apache", - extensions: ["cpio"] - }, - "application/x-csh": { - source: "apache", - extensions: ["csh"] - }, - "application/x-deb": { - compressible: false - }, - "application/x-debian-package": { - source: "apache", - extensions: ["deb", "udeb"] - }, - "application/x-dgc-compressed": { - source: "apache", - extensions: ["dgc"] - }, - "application/x-director": { - source: "apache", - extensions: ["dir", "dcr", "dxr", "cst", "cct", "cxt", "w3d", "fgd", "swa"] - }, - "application/x-doom": { - source: "apache", - extensions: ["wad"] - }, - "application/x-dtbncx+xml": { - source: "apache", - compressible: true, - extensions: ["ncx"] - }, - "application/x-dtbook+xml": { - source: "apache", - compressible: true, - extensions: ["dtb"] - }, - "application/x-dtbresource+xml": { - source: "apache", - compressible: true, - extensions: ["res"] - }, - "application/x-dvi": { - source: "apache", - compressible: false, - extensions: ["dvi"] - }, - "application/x-envoy": { - source: "apache", - extensions: ["evy"] - }, - "application/x-eva": { - source: "apache", - extensions: ["eva"] - }, - "application/x-font-bdf": { - source: "apache", - extensions: ["bdf"] - }, - "application/x-font-dos": { - source: "apache" - }, - "application/x-font-framemaker": { - source: "apache" - }, - "application/x-font-ghostscript": { - source: "apache", - extensions: ["gsf"] - }, - "application/x-font-libgrx": { - source: "apache" - }, - "application/x-font-linux-psf": { - source: "apache", - extensions: ["psf"] - }, - "application/x-font-pcf": { - source: "apache", - extensions: ["pcf"] - }, - "application/x-font-snf": { - source: "apache", - extensions: ["snf"] - }, - "application/x-font-speedo": { - source: "apache" - }, - "application/x-font-sunos-news": { - source: "apache" - }, - "application/x-font-type1": { - source: "apache", - extensions: ["pfa", "pfb", "pfm", "afm"] - }, - "application/x-font-vfont": { - source: "apache" - }, - "application/x-freearc": { - source: "apache", - extensions: ["arc"] - }, - "application/x-futuresplash": { - source: "apache", - extensions: ["spl"] - }, - "application/x-gca-compressed": { - source: "apache", - extensions: ["gca"] - }, - "application/x-glulx": { - source: "apache", - extensions: ["ulx"] - }, - "application/x-gnumeric": { - source: "apache", - extensions: ["gnumeric"] - }, - "application/x-gramps-xml": { - source: "apache", - extensions: ["gramps"] - }, - "application/x-gtar": { - source: "apache", - extensions: ["gtar"] - }, - "application/x-gzip": { - source: "apache" - }, - "application/x-hdf": { - source: "apache", - extensions: ["hdf"] - }, - "application/x-httpd-php": { - compressible: true, - extensions: ["php"] - }, - "application/x-install-instructions": { - source: "apache", - extensions: ["install"] - }, - "application/x-ipynb+json": { - compressible: true, - extensions: ["ipynb"] - }, - "application/x-iso9660-image": { - source: "apache", - extensions: ["iso"] - }, - "application/x-iwork-keynote-sffkey": { - extensions: ["key"] - }, - "application/x-iwork-numbers-sffnumbers": { - extensions: ["numbers"] - }, - "application/x-iwork-pages-sffpages": { - extensions: ["pages"] - }, - "application/x-java-archive-diff": { - source: "nginx", - extensions: ["jardiff"] - }, - "application/x-java-jnlp-file": { - source: "apache", - compressible: false, - extensions: ["jnlp"] - }, - "application/x-javascript": { - compressible: true - }, - "application/x-keepass2": { - extensions: ["kdbx"] - }, - "application/x-latex": { - source: "apache", - compressible: false, - extensions: ["latex"] - }, - "application/x-lua-bytecode": { - extensions: ["luac"] - }, - "application/x-lzh-compressed": { - source: "apache", - extensions: ["lzh", "lha"] - }, - "application/x-makeself": { - source: "nginx", - extensions: ["run"] - }, - "application/x-mie": { - source: "apache", - extensions: ["mie"] - }, - "application/x-mobipocket-ebook": { - source: "apache", - extensions: ["prc", "mobi"] - }, - "application/x-mpegurl": { - compressible: false - }, - "application/x-ms-application": { - source: "apache", - extensions: ["application"] - }, - "application/x-ms-shortcut": { - source: "apache", - extensions: ["lnk"] - }, - "application/x-ms-wmd": { - source: "apache", - extensions: ["wmd"] - }, - "application/x-ms-wmz": { - source: "apache", - extensions: ["wmz"] - }, - "application/x-ms-xbap": { - source: "apache", - extensions: ["xbap"] - }, - "application/x-msaccess": { - source: "apache", - extensions: ["mdb"] - }, - "application/x-msbinder": { - source: "apache", - extensions: ["obd"] - }, - "application/x-mscardfile": { - source: "apache", - extensions: ["crd"] - }, - "application/x-msclip": { - source: "apache", - extensions: ["clp"] - }, - "application/x-msdos-program": { - extensions: ["exe"] - }, - "application/x-msdownload": { - source: "apache", - extensions: ["exe", "dll", "com", "bat", "msi"] - }, - "application/x-msmediaview": { - source: "apache", - extensions: ["mvb", "m13", "m14"] - }, - "application/x-msmetafile": { - source: "apache", - extensions: ["wmf", "wmz", "emf", "emz"] - }, - "application/x-msmoney": { - source: "apache", - extensions: ["mny"] - }, - "application/x-mspublisher": { - source: "apache", - extensions: ["pub"] - }, - "application/x-msschedule": { - source: "apache", - extensions: ["scd"] - }, - "application/x-msterminal": { - source: "apache", - extensions: ["trm"] - }, - "application/x-mswrite": { - source: "apache", - extensions: ["wri"] - }, - "application/x-netcdf": { - source: "apache", - extensions: ["nc", "cdf"] - }, - "application/x-ns-proxy-autoconfig": { - compressible: true, - extensions: ["pac"] - }, - "application/x-nzb": { - source: "apache", - extensions: ["nzb"] - }, - "application/x-perl": { - source: "nginx", - extensions: ["pl", "pm"] - }, - "application/x-pilot": { - source: "nginx", - extensions: ["prc", "pdb"] - }, - "application/x-pkcs12": { - source: "apache", - compressible: false, - extensions: ["p12", "pfx"] - }, - "application/x-pkcs7-certificates": { - source: "apache", - extensions: ["p7b", "spc"] - }, - "application/x-pkcs7-certreqresp": { - source: "apache", - extensions: ["p7r"] - }, - "application/x-pki-message": { - source: "iana" - }, - "application/x-rar-compressed": { - source: "apache", - compressible: false, - extensions: ["rar"] - }, - "application/x-redhat-package-manager": { - source: "nginx", - extensions: ["rpm"] - }, - "application/x-research-info-systems": { - source: "apache", - extensions: ["ris"] - }, - "application/x-sea": { - source: "nginx", - extensions: ["sea"] - }, - "application/x-sh": { - source: "apache", - compressible: true, - extensions: ["sh"] - }, - "application/x-shar": { - source: "apache", - extensions: ["shar"] - }, - "application/x-shockwave-flash": { - source: "apache", - compressible: false, - extensions: ["swf"] - }, - "application/x-silverlight-app": { - source: "apache", - extensions: ["xap"] - }, - "application/x-sql": { - source: "apache", - extensions: ["sql"] - }, - "application/x-stuffit": { - source: "apache", - compressible: false, - extensions: ["sit"] - }, - "application/x-stuffitx": { - source: "apache", - extensions: ["sitx"] - }, - "application/x-subrip": { - source: "apache", - extensions: ["srt"] - }, - "application/x-sv4cpio": { - source: "apache", - extensions: ["sv4cpio"] - }, - "application/x-sv4crc": { - source: "apache", - extensions: ["sv4crc"] - }, - "application/x-t3vm-image": { - source: "apache", - extensions: ["t3"] - }, - "application/x-tads": { - source: "apache", - extensions: ["gam"] - }, - "application/x-tar": { - source: "apache", - compressible: true, - extensions: ["tar"] - }, - "application/x-tcl": { - source: "apache", - extensions: ["tcl", "tk"] - }, - "application/x-tex": { - source: "apache", - extensions: ["tex"] - }, - "application/x-tex-tfm": { - source: "apache", - extensions: ["tfm"] - }, - "application/x-texinfo": { - source: "apache", - extensions: ["texinfo", "texi"] - }, - "application/x-tgif": { - source: "apache", - extensions: ["obj"] - }, - "application/x-ustar": { - source: "apache", - extensions: ["ustar"] - }, - "application/x-virtualbox-hdd": { - compressible: true, - extensions: ["hdd"] - }, - "application/x-virtualbox-ova": { - compressible: true, - extensions: ["ova"] - }, - "application/x-virtualbox-ovf": { - compressible: true, - extensions: ["ovf"] - }, - "application/x-virtualbox-vbox": { - compressible: true, - extensions: ["vbox"] - }, - "application/x-virtualbox-vbox-extpack": { - compressible: false, - extensions: ["vbox-extpack"] - }, - "application/x-virtualbox-vdi": { - compressible: true, - extensions: ["vdi"] - }, - "application/x-virtualbox-vhd": { - compressible: true, - extensions: ["vhd"] - }, - "application/x-virtualbox-vmdk": { - compressible: true, - extensions: ["vmdk"] - }, - "application/x-wais-source": { - source: "apache", - extensions: ["src"] - }, - "application/x-web-app-manifest+json": { - compressible: true, - extensions: ["webapp"] - }, - "application/x-www-form-urlencoded": { - source: "iana", - compressible: true - }, - "application/x-x509-ca-cert": { - source: "iana", - extensions: ["der", "crt", "pem"] - }, - "application/x-x509-ca-ra-cert": { - source: "iana" - }, - "application/x-x509-next-ca-cert": { - source: "iana" - }, - "application/x-xfig": { - source: "apache", - extensions: ["fig"] - }, - "application/x-xliff+xml": { - source: "apache", - compressible: true, - extensions: ["xlf"] - }, - "application/x-xpinstall": { - source: "apache", - compressible: false, - extensions: ["xpi"] - }, - "application/x-xz": { - source: "apache", - extensions: ["xz"] - }, - "application/x-zip-compressed": { - extensions: ["zip"] - }, - "application/x-zmachine": { - source: "apache", - extensions: ["z1", "z2", "z3", "z4", "z5", "z6", "z7", "z8"] - }, - "application/x400-bp": { - source: "iana" - }, - "application/xacml+xml": { - source: "iana", - compressible: true - }, - "application/xaml+xml": { - source: "apache", - compressible: true, - extensions: ["xaml"] - }, - "application/xcap-att+xml": { - source: "iana", - compressible: true, - extensions: ["xav"] - }, - "application/xcap-caps+xml": { - source: "iana", - compressible: true, - extensions: ["xca"] - }, - "application/xcap-diff+xml": { - source: "iana", - compressible: true, - extensions: ["xdf"] - }, - "application/xcap-el+xml": { - source: "iana", - compressible: true, - extensions: ["xel"] - }, - "application/xcap-error+xml": { - source: "iana", - compressible: true - }, - "application/xcap-ns+xml": { - source: "iana", - compressible: true, - extensions: ["xns"] - }, - "application/xcon-conference-info+xml": { - source: "iana", - compressible: true - }, - "application/xcon-conference-info-diff+xml": { - source: "iana", - compressible: true - }, - "application/xenc+xml": { - source: "iana", - compressible: true, - extensions: ["xenc"] - }, - "application/xfdf": { - source: "iana", - extensions: ["xfdf"] - }, - "application/xhtml+xml": { - source: "iana", - compressible: true, - extensions: ["xhtml", "xht"] - }, - "application/xhtml-voice+xml": { - source: "apache", - compressible: true - }, - "application/xliff+xml": { - source: "iana", - compressible: true, - extensions: ["xlf"] - }, - "application/xml": { - source: "iana", - compressible: true, - extensions: ["xml", "xsl", "xsd", "rng"] - }, - "application/xml-dtd": { - source: "iana", - compressible: true, - extensions: ["dtd"] - }, - "application/xml-external-parsed-entity": { - source: "iana" - }, - "application/xml-patch+xml": { - source: "iana", - compressible: true - }, - "application/xmpp+xml": { - source: "iana", - compressible: true - }, - "application/xop+xml": { - source: "iana", - compressible: true, - extensions: ["xop"] - }, - "application/xproc+xml": { - source: "apache", - compressible: true, - extensions: ["xpl"] - }, - "application/xslt+xml": { - source: "iana", - compressible: true, - extensions: ["xsl", "xslt"] - }, - "application/xspf+xml": { - source: "apache", - compressible: true, - extensions: ["xspf"] - }, - "application/xv+xml": { - source: "iana", - compressible: true, - extensions: ["mxml", "xhvml", "xvml", "xvm"] - }, - "application/yaml": { - source: "iana" - }, - "application/yang": { - source: "iana", - extensions: ["yang"] - }, - "application/yang-data+cbor": { - source: "iana" - }, - "application/yang-data+json": { - source: "iana", - compressible: true - }, - "application/yang-data+xml": { - source: "iana", - compressible: true - }, - "application/yang-patch+json": { - source: "iana", - compressible: true - }, - "application/yang-patch+xml": { - source: "iana", - compressible: true - }, - "application/yang-sid+json": { - source: "iana", - compressible: true - }, - "application/yin+xml": { - source: "iana", - compressible: true, - extensions: ["yin"] - }, - "application/zip": { - source: "iana", - compressible: false, - extensions: ["zip"] - }, - "application/zip+dotlottie": { - extensions: ["lottie"] - }, - "application/zlib": { - source: "iana" - }, - "application/zstd": { - source: "iana" - }, - "audio/1d-interleaved-parityfec": { - source: "iana" - }, - "audio/32kadpcm": { - source: "iana" - }, - "audio/3gpp": { - source: "iana", - compressible: false, - extensions: ["3gpp"] - }, - "audio/3gpp2": { - source: "iana" - }, - "audio/aac": { - source: "iana", - extensions: ["adts", "aac"] - }, - "audio/ac3": { - source: "iana" - }, - "audio/adpcm": { - source: "apache", - extensions: ["adp"] - }, - "audio/amr": { - source: "iana", - extensions: ["amr"] - }, - "audio/amr-wb": { - source: "iana" - }, - "audio/amr-wb+": { - source: "iana" - }, - "audio/aptx": { - source: "iana" - }, - "audio/asc": { - source: "iana" - }, - "audio/atrac-advanced-lossless": { - source: "iana" - }, - "audio/atrac-x": { - source: "iana" - }, - "audio/atrac3": { - source: "iana" - }, - "audio/basic": { - source: "iana", - compressible: false, - extensions: ["au", "snd"] - }, - "audio/bv16": { - source: "iana" - }, - "audio/bv32": { - source: "iana" - }, - "audio/clearmode": { - source: "iana" - }, - "audio/cn": { - source: "iana" - }, - "audio/dat12": { - source: "iana" - }, - "audio/dls": { - source: "iana" - }, - "audio/dsr-es201108": { - source: "iana" - }, - "audio/dsr-es202050": { - source: "iana" - }, - "audio/dsr-es202211": { - source: "iana" - }, - "audio/dsr-es202212": { - source: "iana" - }, - "audio/dv": { - source: "iana" - }, - "audio/dvi4": { - source: "iana" - }, - "audio/eac3": { - source: "iana" - }, - "audio/encaprtp": { - source: "iana" - }, - "audio/evrc": { - source: "iana" - }, - "audio/evrc-qcp": { - source: "iana" - }, - "audio/evrc0": { - source: "iana" - }, - "audio/evrc1": { - source: "iana" - }, - "audio/evrcb": { - source: "iana" - }, - "audio/evrcb0": { - source: "iana" - }, - "audio/evrcb1": { - source: "iana" - }, - "audio/evrcnw": { - source: "iana" - }, - "audio/evrcnw0": { - source: "iana" - }, - "audio/evrcnw1": { - source: "iana" - }, - "audio/evrcwb": { - source: "iana" - }, - "audio/evrcwb0": { - source: "iana" - }, - "audio/evrcwb1": { - source: "iana" - }, - "audio/evs": { - source: "iana" - }, - "audio/flac": { - source: "iana" - }, - "audio/flexfec": { - source: "iana" - }, - "audio/fwdred": { - source: "iana" - }, - "audio/g711-0": { - source: "iana" - }, - "audio/g719": { - source: "iana" - }, - "audio/g722": { - source: "iana" - }, - "audio/g7221": { - source: "iana" - }, - "audio/g723": { - source: "iana" - }, - "audio/g726-16": { - source: "iana" - }, - "audio/g726-24": { - source: "iana" - }, - "audio/g726-32": { - source: "iana" - }, - "audio/g726-40": { - source: "iana" - }, - "audio/g728": { - source: "iana" - }, - "audio/g729": { - source: "iana" - }, - "audio/g7291": { - source: "iana" - }, - "audio/g729d": { - source: "iana" - }, - "audio/g729e": { - source: "iana" - }, - "audio/gsm": { - source: "iana" - }, - "audio/gsm-efr": { - source: "iana" - }, - "audio/gsm-hr-08": { - source: "iana" - }, - "audio/ilbc": { - source: "iana" - }, - "audio/ip-mr_v2.5": { - source: "iana" - }, - "audio/isac": { - source: "apache" - }, - "audio/l16": { - source: "iana" - }, - "audio/l20": { - source: "iana" - }, - "audio/l24": { - source: "iana", - compressible: false - }, - "audio/l8": { - source: "iana" - }, - "audio/lpc": { - source: "iana" - }, - "audio/matroska": { - source: "iana" - }, - "audio/melp": { - source: "iana" - }, - "audio/melp1200": { - source: "iana" - }, - "audio/melp2400": { - source: "iana" - }, - "audio/melp600": { - source: "iana" - }, - "audio/mhas": { - source: "iana" - }, - "audio/midi": { - source: "apache", - extensions: ["mid", "midi", "kar", "rmi"] - }, - "audio/midi-clip": { - source: "iana" - }, - "audio/mobile-xmf": { - source: "iana", - extensions: ["mxmf"] - }, - "audio/mp3": { - compressible: false, - extensions: ["mp3"] - }, - "audio/mp4": { - source: "iana", - compressible: false, - extensions: ["m4a", "mp4a", "m4b"] - }, - "audio/mp4a-latm": { - source: "iana" - }, - "audio/mpa": { - source: "iana" - }, - "audio/mpa-robust": { - source: "iana" - }, - "audio/mpeg": { - source: "iana", - compressible: false, - extensions: ["mpga", "mp2", "mp2a", "mp3", "m2a", "m3a"] - }, - "audio/mpeg4-generic": { - source: "iana" - }, - "audio/musepack": { - source: "apache" - }, - "audio/ogg": { - source: "iana", - compressible: false, - extensions: ["oga", "ogg", "spx", "opus"] - }, - "audio/opus": { - source: "iana" - }, - "audio/parityfec": { - source: "iana" - }, - "audio/pcma": { - source: "iana" - }, - "audio/pcma-wb": { - source: "iana" - }, - "audio/pcmu": { - source: "iana" - }, - "audio/pcmu-wb": { - source: "iana" - }, - "audio/prs.sid": { - source: "iana" - }, - "audio/qcelp": { - source: "iana" - }, - "audio/raptorfec": { - source: "iana" - }, - "audio/red": { - source: "iana" - }, - "audio/rtp-enc-aescm128": { - source: "iana" - }, - "audio/rtp-midi": { - source: "iana" - }, - "audio/rtploopback": { - source: "iana" - }, - "audio/rtx": { - source: "iana" - }, - "audio/s3m": { - source: "apache", - extensions: ["s3m"] - }, - "audio/scip": { - source: "iana" - }, - "audio/silk": { - source: "apache", - extensions: ["sil"] - }, - "audio/smv": { - source: "iana" - }, - "audio/smv-qcp": { - source: "iana" - }, - "audio/smv0": { - source: "iana" - }, - "audio/sofa": { - source: "iana" - }, - "audio/sp-midi": { - source: "iana" - }, - "audio/speex": { - source: "iana" - }, - "audio/t140c": { - source: "iana" - }, - "audio/t38": { - source: "iana" - }, - "audio/telephone-event": { - source: "iana" - }, - "audio/tetra_acelp": { - source: "iana" - }, - "audio/tetra_acelp_bb": { - source: "iana" - }, - "audio/tone": { - source: "iana" - }, - "audio/tsvcis": { - source: "iana" - }, - "audio/uemclip": { - source: "iana" - }, - "audio/ulpfec": { - source: "iana" - }, - "audio/usac": { - source: "iana" - }, - "audio/vdvi": { - source: "iana" - }, - "audio/vmr-wb": { - source: "iana" - }, - "audio/vnd.3gpp.iufp": { - source: "iana" - }, - "audio/vnd.4sb": { - source: "iana" - }, - "audio/vnd.audiokoz": { - source: "iana" - }, - "audio/vnd.celp": { - source: "iana" - }, - "audio/vnd.cisco.nse": { - source: "iana" - }, - "audio/vnd.cmles.radio-events": { - source: "iana" - }, - "audio/vnd.cns.anp1": { - source: "iana" - }, - "audio/vnd.cns.inf1": { - source: "iana" - }, - "audio/vnd.dece.audio": { - source: "iana", - extensions: ["uva", "uvva"] - }, - "audio/vnd.digital-winds": { - source: "iana", - extensions: ["eol"] - }, - "audio/vnd.dlna.adts": { - source: "iana" - }, - "audio/vnd.dolby.heaac.1": { - source: "iana" - }, - "audio/vnd.dolby.heaac.2": { - source: "iana" - }, - "audio/vnd.dolby.mlp": { - source: "iana" - }, - "audio/vnd.dolby.mps": { - source: "iana" - }, - "audio/vnd.dolby.pl2": { - source: "iana" - }, - "audio/vnd.dolby.pl2x": { - source: "iana" - }, - "audio/vnd.dolby.pl2z": { - source: "iana" - }, - "audio/vnd.dolby.pulse.1": { - source: "iana" - }, - "audio/vnd.dra": { - source: "iana", - extensions: ["dra"] - }, - "audio/vnd.dts": { - source: "iana", - extensions: ["dts"] - }, - "audio/vnd.dts.hd": { - source: "iana", - extensions: ["dtshd"] - }, - "audio/vnd.dts.uhd": { - source: "iana" - }, - "audio/vnd.dvb.file": { - source: "iana" - }, - "audio/vnd.everad.plj": { - source: "iana" - }, - "audio/vnd.hns.audio": { - source: "iana" - }, - "audio/vnd.lucent.voice": { - source: "iana", - extensions: ["lvp"] - }, - "audio/vnd.ms-playready.media.pya": { - source: "iana", - extensions: ["pya"] - }, - "audio/vnd.nokia.mobile-xmf": { - source: "iana" - }, - "audio/vnd.nortel.vbk": { - source: "iana" - }, - "audio/vnd.nuera.ecelp4800": { - source: "iana", - extensions: ["ecelp4800"] - }, - "audio/vnd.nuera.ecelp7470": { - source: "iana", - extensions: ["ecelp7470"] - }, - "audio/vnd.nuera.ecelp9600": { - source: "iana", - extensions: ["ecelp9600"] - }, - "audio/vnd.octel.sbc": { - source: "iana" - }, - "audio/vnd.presonus.multitrack": { - source: "iana" - }, - "audio/vnd.qcelp": { - source: "apache" - }, - "audio/vnd.rhetorex.32kadpcm": { - source: "iana" - }, - "audio/vnd.rip": { - source: "iana", - extensions: ["rip"] - }, - "audio/vnd.rn-realaudio": { - compressible: false - }, - "audio/vnd.sealedmedia.softseal.mpeg": { - source: "iana" - }, - "audio/vnd.vmx.cvsd": { - source: "iana" - }, - "audio/vnd.wave": { - compressible: false - }, - "audio/vorbis": { - source: "iana", - compressible: false - }, - "audio/vorbis-config": { - source: "iana" - }, - "audio/wav": { - compressible: false, - extensions: ["wav"] - }, - "audio/wave": { - compressible: false, - extensions: ["wav"] - }, - "audio/webm": { - source: "apache", - compressible: false, - extensions: ["weba"] - }, - "audio/x-aac": { - source: "apache", - compressible: false, - extensions: ["aac"] - }, - "audio/x-aiff": { - source: "apache", - extensions: ["aif", "aiff", "aifc"] - }, - "audio/x-caf": { - source: "apache", - compressible: false, - extensions: ["caf"] - }, - "audio/x-flac": { - source: "apache", - extensions: ["flac"] - }, - "audio/x-m4a": { - source: "nginx", - extensions: ["m4a"] - }, - "audio/x-matroska": { - source: "apache", - extensions: ["mka"] - }, - "audio/x-mpegurl": { - source: "apache", - extensions: ["m3u"] - }, - "audio/x-ms-wax": { - source: "apache", - extensions: ["wax"] - }, - "audio/x-ms-wma": { - source: "apache", - extensions: ["wma"] - }, - "audio/x-pn-realaudio": { - source: "apache", - extensions: ["ram", "ra"] - }, - "audio/x-pn-realaudio-plugin": { - source: "apache", - extensions: ["rmp"] - }, - "audio/x-realaudio": { - source: "nginx", - extensions: ["ra"] - }, - "audio/x-tta": { - source: "apache" - }, - "audio/x-wav": { - source: "apache", - extensions: ["wav"] - }, - "audio/xm": { - source: "apache", - extensions: ["xm"] - }, - "chemical/x-cdx": { - source: "apache", - extensions: ["cdx"] - }, - "chemical/x-cif": { - source: "apache", - extensions: ["cif"] - }, - "chemical/x-cmdf": { - source: "apache", - extensions: ["cmdf"] - }, - "chemical/x-cml": { - source: "apache", - extensions: ["cml"] - }, - "chemical/x-csml": { - source: "apache", - extensions: ["csml"] - }, - "chemical/x-pdb": { - source: "apache" - }, - "chemical/x-xyz": { - source: "apache", - extensions: ["xyz"] - }, - "font/collection": { - source: "iana", - extensions: ["ttc"] - }, - "font/otf": { - source: "iana", - compressible: true, - extensions: ["otf"] - }, - "font/sfnt": { - source: "iana" - }, - "font/ttf": { - source: "iana", - compressible: true, - extensions: ["ttf"] - }, - "font/woff": { - source: "iana", - extensions: ["woff"] - }, - "font/woff2": { - source: "iana", - extensions: ["woff2"] - }, - "image/aces": { - source: "iana", - extensions: ["exr"] - }, - "image/apng": { - source: "iana", - compressible: false, - extensions: ["apng"] - }, - "image/avci": { - source: "iana", - extensions: ["avci"] - }, - "image/avcs": { - source: "iana", - extensions: ["avcs"] - }, - "image/avif": { - source: "iana", - compressible: false, - extensions: ["avif"] - }, - "image/bmp": { - source: "iana", - compressible: true, - extensions: ["bmp", "dib"] - }, - "image/cgm": { - source: "iana", - extensions: ["cgm"] - }, - "image/dicom-rle": { - source: "iana", - extensions: ["drle"] - }, - "image/dpx": { - source: "iana", - extensions: ["dpx"] - }, - "image/emf": { - source: "iana", - extensions: ["emf"] - }, - "image/fits": { - source: "iana", - extensions: ["fits"] - }, - "image/g3fax": { - source: "iana", - extensions: ["g3"] - }, - "image/gif": { - source: "iana", - compressible: false, - extensions: ["gif"] - }, - "image/heic": { - source: "iana", - extensions: ["heic"] - }, - "image/heic-sequence": { - source: "iana", - extensions: ["heics"] - }, - "image/heif": { - source: "iana", - extensions: ["heif"] - }, - "image/heif-sequence": { - source: "iana", - extensions: ["heifs"] - }, - "image/hej2k": { - source: "iana", - extensions: ["hej2"] - }, - "image/ief": { - source: "iana", - extensions: ["ief"] - }, - "image/j2c": { - source: "iana" - }, - "image/jaii": { - source: "iana", - extensions: ["jaii"] - }, - "image/jais": { - source: "iana", - extensions: ["jais"] - }, - "image/jls": { - source: "iana", - extensions: ["jls"] - }, - "image/jp2": { - source: "iana", - compressible: false, - extensions: ["jp2", "jpg2"] - }, - "image/jpeg": { - source: "iana", - compressible: false, - extensions: ["jpg", "jpeg", "jpe"] - }, - "image/jph": { - source: "iana", - extensions: ["jph"] - }, - "image/jphc": { - source: "iana", - extensions: ["jhc"] - }, - "image/jpm": { - source: "iana", - compressible: false, - extensions: ["jpm", "jpgm"] - }, - "image/jpx": { - source: "iana", - compressible: false, - extensions: ["jpx", "jpf"] - }, - "image/jxl": { - source: "iana", - extensions: ["jxl"] - }, - "image/jxr": { - source: "iana", - extensions: ["jxr"] - }, - "image/jxra": { - source: "iana", - extensions: ["jxra"] - }, - "image/jxrs": { - source: "iana", - extensions: ["jxrs"] - }, - "image/jxs": { - source: "iana", - extensions: ["jxs"] - }, - "image/jxsc": { - source: "iana", - extensions: ["jxsc"] - }, - "image/jxsi": { - source: "iana", - extensions: ["jxsi"] - }, - "image/jxss": { - source: "iana", - extensions: ["jxss"] - }, - "image/ktx": { - source: "iana", - extensions: ["ktx"] - }, - "image/ktx2": { - source: "iana", - extensions: ["ktx2"] - }, - "image/naplps": { - source: "iana" - }, - "image/pjpeg": { - compressible: false, - extensions: ["jfif"] - }, - "image/png": { - source: "iana", - compressible: false, - extensions: ["png"] - }, - "image/prs.btif": { - source: "iana", - extensions: ["btif", "btf"] - }, - "image/prs.pti": { - source: "iana", - extensions: ["pti"] - }, - "image/pwg-raster": { - source: "iana" - }, - "image/sgi": { - source: "apache", - extensions: ["sgi"] - }, - "image/svg+xml": { - source: "iana", - compressible: true, - extensions: ["svg", "svgz"] - }, - "image/t38": { - source: "iana", - extensions: ["t38"] - }, - "image/tiff": { - source: "iana", - compressible: false, - extensions: ["tif", "tiff"] - }, - "image/tiff-fx": { - source: "iana", - extensions: ["tfx"] - }, - "image/vnd.adobe.photoshop": { - source: "iana", - compressible: true, - extensions: ["psd"] - }, - "image/vnd.airzip.accelerator.azv": { - source: "iana", - extensions: ["azv"] - }, - "image/vnd.clip": { - source: "iana" - }, - "image/vnd.cns.inf2": { - source: "iana" - }, - "image/vnd.dece.graphic": { - source: "iana", - extensions: ["uvi", "uvvi", "uvg", "uvvg"] - }, - "image/vnd.djvu": { - source: "iana", - extensions: ["djvu", "djv"] - }, - "image/vnd.dvb.subtitle": { - source: "iana", - extensions: ["sub"] - }, - "image/vnd.dwg": { - source: "iana", - extensions: ["dwg"] - }, - "image/vnd.dxf": { - source: "iana", - extensions: ["dxf"] - }, - "image/vnd.fastbidsheet": { - source: "iana", - extensions: ["fbs"] - }, - "image/vnd.fpx": { - source: "iana", - extensions: ["fpx"] - }, - "image/vnd.fst": { - source: "iana", - extensions: ["fst"] - }, - "image/vnd.fujixerox.edmics-mmr": { - source: "iana", - extensions: ["mmr"] - }, - "image/vnd.fujixerox.edmics-rlc": { - source: "iana", - extensions: ["rlc"] - }, - "image/vnd.globalgraphics.pgb": { - source: "iana" - }, - "image/vnd.microsoft.icon": { - source: "iana", - compressible: true, - extensions: ["ico"] - }, - "image/vnd.mix": { - source: "iana" - }, - "image/vnd.mozilla.apng": { - source: "iana" - }, - "image/vnd.ms-dds": { - compressible: true, - extensions: ["dds"] - }, - "image/vnd.ms-modi": { - source: "iana", - extensions: ["mdi"] - }, - "image/vnd.ms-photo": { - source: "apache", - extensions: ["wdp"] - }, - "image/vnd.net-fpx": { - source: "iana", - extensions: ["npx"] - }, - "image/vnd.pco.b16": { - source: "iana", - extensions: ["b16"] - }, - "image/vnd.radiance": { - source: "iana" - }, - "image/vnd.sealed.png": { - source: "iana" - }, - "image/vnd.sealedmedia.softseal.gif": { - source: "iana" - }, - "image/vnd.sealedmedia.softseal.jpg": { - source: "iana" - }, - "image/vnd.svf": { - source: "iana" - }, - "image/vnd.tencent.tap": { - source: "iana", - extensions: ["tap"] - }, - "image/vnd.valve.source.texture": { - source: "iana", - extensions: ["vtf"] - }, - "image/vnd.wap.wbmp": { - source: "iana", - extensions: ["wbmp"] - }, - "image/vnd.xiff": { - source: "iana", - extensions: ["xif"] - }, - "image/vnd.zbrush.pcx": { - source: "iana", - extensions: ["pcx"] - }, - "image/webp": { - source: "iana", - extensions: ["webp"] - }, - "image/wmf": { - source: "iana", - extensions: ["wmf"] - }, - "image/x-3ds": { - source: "apache", - extensions: ["3ds"] - }, - "image/x-adobe-dng": { - extensions: ["dng"] - }, - "image/x-cmu-raster": { - source: "apache", - extensions: ["ras"] - }, - "image/x-cmx": { - source: "apache", - extensions: ["cmx"] - }, - "image/x-emf": { - source: "iana" - }, - "image/x-freehand": { - source: "apache", - extensions: ["fh", "fhc", "fh4", "fh5", "fh7"] - }, - "image/x-icon": { - source: "apache", - compressible: true, - extensions: ["ico"] - }, - "image/x-jng": { - source: "nginx", - extensions: ["jng"] - }, - "image/x-mrsid-image": { - source: "apache", - extensions: ["sid"] - }, - "image/x-ms-bmp": { - source: "nginx", - compressible: true, - extensions: ["bmp"] - }, - "image/x-pcx": { - source: "apache", - extensions: ["pcx"] - }, - "image/x-pict": { - source: "apache", - extensions: ["pic", "pct"] - }, - "image/x-portable-anymap": { - source: "apache", - extensions: ["pnm"] - }, - "image/x-portable-bitmap": { - source: "apache", - extensions: ["pbm"] - }, - "image/x-portable-graymap": { - source: "apache", - extensions: ["pgm"] - }, - "image/x-portable-pixmap": { - source: "apache", - extensions: ["ppm"] - }, - "image/x-rgb": { - source: "apache", - extensions: ["rgb"] - }, - "image/x-tga": { - source: "apache", - extensions: ["tga"] - }, - "image/x-wmf": { - source: "iana" - }, - "image/x-xbitmap": { - source: "apache", - extensions: ["xbm"] - }, - "image/x-xcf": { - compressible: false - }, - "image/x-xpixmap": { - source: "apache", - extensions: ["xpm"] - }, - "image/x-xwindowdump": { - source: "apache", - extensions: ["xwd"] - }, - "message/bhttp": { - source: "iana" - }, - "message/cpim": { - source: "iana" - }, - "message/delivery-status": { - source: "iana" - }, - "message/disposition-notification": { - source: "iana", - extensions: [ - "disposition-notification" - ] - }, - "message/external-body": { - source: "iana" - }, - "message/feedback-report": { - source: "iana" - }, - "message/global": { - source: "iana", - extensions: ["u8msg"] - }, - "message/global-delivery-status": { - source: "iana", - extensions: ["u8dsn"] - }, - "message/global-disposition-notification": { - source: "iana", - extensions: ["u8mdn"] - }, - "message/global-headers": { - source: "iana", - extensions: ["u8hdr"] - }, - "message/http": { - source: "iana", - compressible: false - }, - "message/imdn+xml": { - source: "iana", - compressible: true - }, - "message/mls": { - source: "iana" - }, - "message/news": { - source: "apache" - }, - "message/ohttp-req": { - source: "iana" - }, - "message/ohttp-res": { - source: "iana" - }, - "message/partial": { - source: "iana", - compressible: false - }, - "message/rfc822": { - source: "iana", - compressible: true, - extensions: ["eml", "mime", "mht", "mhtml"] - }, - "message/s-http": { - source: "apache" - }, - "message/sip": { - source: "iana" - }, - "message/sipfrag": { - source: "iana" - }, - "message/tracking-status": { - source: "iana" - }, - "message/vnd.si.simp": { - source: "apache" - }, - "message/vnd.wfa.wsc": { - source: "iana", - extensions: ["wsc"] - }, - "model/3mf": { - source: "iana", - extensions: ["3mf"] - }, - "model/e57": { - source: "iana" - }, - "model/gltf+json": { - source: "iana", - compressible: true, - extensions: ["gltf"] - }, - "model/gltf-binary": { - source: "iana", - compressible: true, - extensions: ["glb"] - }, - "model/iges": { - source: "iana", - compressible: false, - extensions: ["igs", "iges"] - }, - "model/jt": { - source: "iana", - extensions: ["jt"] - }, - "model/mesh": { - source: "iana", - compressible: false, - extensions: ["msh", "mesh", "silo"] - }, - "model/mtl": { - source: "iana", - extensions: ["mtl"] - }, - "model/obj": { - source: "iana", - extensions: ["obj"] - }, - "model/prc": { - source: "iana", - extensions: ["prc"] - }, - "model/step": { - source: "iana", - extensions: ["step", "stp", "stpnc", "p21", "210"] - }, - "model/step+xml": { - source: "iana", - compressible: true, - extensions: ["stpx"] - }, - "model/step+zip": { - source: "iana", - compressible: false, - extensions: ["stpz"] - }, - "model/step-xml+zip": { - source: "iana", - compressible: false, - extensions: ["stpxz"] - }, - "model/stl": { - source: "iana", - extensions: ["stl"] - }, - "model/u3d": { - source: "iana", - extensions: ["u3d"] - }, - "model/vnd.bary": { - source: "iana", - extensions: ["bary"] - }, - "model/vnd.cld": { - source: "iana", - extensions: ["cld"] - }, - "model/vnd.collada+xml": { - source: "iana", - compressible: true, - extensions: ["dae"] - }, - "model/vnd.dwf": { - source: "iana", - extensions: ["dwf"] - }, - "model/vnd.flatland.3dml": { - source: "iana" - }, - "model/vnd.gdl": { - source: "iana", - extensions: ["gdl"] - }, - "model/vnd.gs-gdl": { - source: "apache" - }, - "model/vnd.gs.gdl": { - source: "iana" - }, - "model/vnd.gtw": { - source: "iana", - extensions: ["gtw"] - }, - "model/vnd.moml+xml": { - source: "iana", - compressible: true - }, - "model/vnd.mts": { - source: "iana", - extensions: ["mts"] - }, - "model/vnd.opengex": { - source: "iana", - extensions: ["ogex"] - }, - "model/vnd.parasolid.transmit.binary": { - source: "iana", - extensions: ["x_b"] - }, - "model/vnd.parasolid.transmit.text": { - source: "iana", - extensions: ["x_t"] - }, - "model/vnd.pytha.pyox": { - source: "iana", - extensions: ["pyo", "pyox"] - }, - "model/vnd.rosette.annotated-data-model": { - source: "iana" - }, - "model/vnd.sap.vds": { - source: "iana", - extensions: ["vds"] - }, - "model/vnd.usda": { - source: "iana", - extensions: ["usda"] - }, - "model/vnd.usdz+zip": { - source: "iana", - compressible: false, - extensions: ["usdz"] - }, - "model/vnd.valve.source.compiled-map": { - source: "iana", - extensions: ["bsp"] - }, - "model/vnd.vtu": { - source: "iana", - extensions: ["vtu"] - }, - "model/vrml": { - source: "iana", - compressible: false, - extensions: ["wrl", "vrml"] - }, - "model/x3d+binary": { - source: "apache", - compressible: false, - extensions: ["x3db", "x3dbz"] - }, - "model/x3d+fastinfoset": { - source: "iana", - extensions: ["x3db"] - }, - "model/x3d+vrml": { - source: "apache", - compressible: false, - extensions: ["x3dv", "x3dvz"] - }, - "model/x3d+xml": { - source: "iana", - compressible: true, - extensions: ["x3d", "x3dz"] - }, - "model/x3d-vrml": { - source: "iana", - extensions: ["x3dv"] - }, - "multipart/alternative": { - source: "iana", - compressible: false - }, - "multipart/appledouble": { - source: "iana" - }, - "multipart/byteranges": { - source: "iana" - }, - "multipart/digest": { - source: "iana" - }, - "multipart/encrypted": { - source: "iana", - compressible: false - }, - "multipart/form-data": { - source: "iana", - compressible: false - }, - "multipart/header-set": { - source: "iana" - }, - "multipart/mixed": { - source: "iana" - }, - "multipart/multilingual": { - source: "iana" - }, - "multipart/parallel": { - source: "iana" - }, - "multipart/related": { - source: "iana", - compressible: false - }, - "multipart/report": { - source: "iana" - }, - "multipart/signed": { - source: "iana", - compressible: false - }, - "multipart/vnd.bint.med-plus": { - source: "iana" - }, - "multipart/voice-message": { - source: "iana" - }, - "multipart/x-mixed-replace": { - source: "iana" - }, - "text/1d-interleaved-parityfec": { - source: "iana" - }, - "text/cache-manifest": { - source: "iana", - compressible: true, - extensions: ["appcache", "manifest"] - }, - "text/calendar": { - source: "iana", - extensions: ["ics", "ifb"] - }, - "text/calender": { - compressible: true - }, - "text/cmd": { - compressible: true - }, - "text/coffeescript": { - extensions: ["coffee", "litcoffee"] - }, - "text/cql": { - source: "iana" - }, - "text/cql-expression": { - source: "iana" - }, - "text/cql-identifier": { - source: "iana" - }, - "text/css": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["css"] - }, - "text/csv": { - source: "iana", - compressible: true, - extensions: ["csv"] - }, - "text/csv-schema": { - source: "iana" - }, - "text/directory": { - source: "iana" - }, - "text/dns": { - source: "iana" - }, - "text/ecmascript": { - source: "apache" - }, - "text/encaprtp": { - source: "iana" - }, - "text/enriched": { - source: "iana" - }, - "text/fhirpath": { - source: "iana" - }, - "text/flexfec": { - source: "iana" - }, - "text/fwdred": { - source: "iana" - }, - "text/gff3": { - source: "iana" - }, - "text/grammar-ref-list": { - source: "iana" - }, - "text/hl7v2": { - source: "iana" - }, - "text/html": { - source: "iana", - compressible: true, - extensions: ["html", "htm", "shtml"] - }, - "text/jade": { - extensions: ["jade"] - }, - "text/javascript": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["js", "mjs"] - }, - "text/jcr-cnd": { - source: "iana" - }, - "text/jsx": { - compressible: true, - extensions: ["jsx"] - }, - "text/less": { - compressible: true, - extensions: ["less"] - }, - "text/markdown": { - source: "iana", - compressible: true, - extensions: ["md", "markdown"] - }, - "text/mathml": { - source: "nginx", - extensions: ["mml"] - }, - "text/mdx": { - compressible: true, - extensions: ["mdx"] - }, - "text/mizar": { - source: "iana" - }, - "text/n3": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["n3"] - }, - "text/parameters": { - source: "iana", - charset: "UTF-8" - }, - "text/parityfec": { - source: "iana" - }, - "text/plain": { - source: "iana", - compressible: true, - extensions: ["txt", "text", "conf", "def", "list", "log", "in", "ini"] - }, - "text/provenance-notation": { - source: "iana", - charset: "UTF-8" - }, - "text/prs.fallenstein.rst": { - source: "iana" - }, - "text/prs.lines.tag": { - source: "iana", - extensions: ["dsc"] - }, - "text/prs.prop.logic": { - source: "iana" - }, - "text/prs.texi": { - source: "iana" - }, - "text/raptorfec": { - source: "iana" - }, - "text/red": { - source: "iana" - }, - "text/rfc822-headers": { - source: "iana" - }, - "text/richtext": { - source: "iana", - compressible: true, - extensions: ["rtx"] - }, - "text/rtf": { - source: "iana", - compressible: true, - extensions: ["rtf"] - }, - "text/rtp-enc-aescm128": { - source: "iana" - }, - "text/rtploopback": { - source: "iana" - }, - "text/rtx": { - source: "iana" - }, - "text/sgml": { - source: "iana", - extensions: ["sgml", "sgm"] - }, - "text/shaclc": { - source: "iana" - }, - "text/shex": { - source: "iana", - extensions: ["shex"] - }, - "text/slim": { - extensions: ["slim", "slm"] - }, - "text/spdx": { - source: "iana", - extensions: ["spdx"] - }, - "text/strings": { - source: "iana" - }, - "text/stylus": { - extensions: ["stylus", "styl"] - }, - "text/t140": { - source: "iana" - }, - "text/tab-separated-values": { - source: "iana", - compressible: true, - extensions: ["tsv"] - }, - "text/troff": { - source: "iana", - extensions: ["t", "tr", "roff", "man", "me", "ms"] - }, - "text/turtle": { - source: "iana", - charset: "UTF-8", - extensions: ["ttl"] - }, - "text/ulpfec": { - source: "iana" - }, - "text/uri-list": { - source: "iana", - compressible: true, - extensions: ["uri", "uris", "urls"] - }, - "text/vcard": { - source: "iana", - compressible: true, - extensions: ["vcard"] - }, - "text/vnd.a": { - source: "iana" - }, - "text/vnd.abc": { - source: "iana" - }, - "text/vnd.ascii-art": { - source: "iana" - }, - "text/vnd.curl": { - source: "iana", - extensions: ["curl"] - }, - "text/vnd.curl.dcurl": { - source: "apache", - extensions: ["dcurl"] - }, - "text/vnd.curl.mcurl": { - source: "apache", - extensions: ["mcurl"] - }, - "text/vnd.curl.scurl": { - source: "apache", - extensions: ["scurl"] - }, - "text/vnd.debian.copyright": { - source: "iana", - charset: "UTF-8" - }, - "text/vnd.dmclientscript": { - source: "iana" - }, - "text/vnd.dvb.subtitle": { - source: "iana", - extensions: ["sub"] - }, - "text/vnd.esmertec.theme-descriptor": { - source: "iana", - charset: "UTF-8" - }, - "text/vnd.exchangeable": { - source: "iana" - }, - "text/vnd.familysearch.gedcom": { - source: "iana", - extensions: ["ged"] - }, - "text/vnd.ficlab.flt": { - source: "iana" - }, - "text/vnd.fly": { - source: "iana", - extensions: ["fly"] - }, - "text/vnd.fmi.flexstor": { - source: "iana", - extensions: ["flx"] - }, - "text/vnd.gml": { - source: "iana" - }, - "text/vnd.graphviz": { - source: "iana", - extensions: ["gv"] - }, - "text/vnd.hans": { - source: "iana" - }, - "text/vnd.hgl": { - source: "iana" - }, - "text/vnd.in3d.3dml": { - source: "iana", - extensions: ["3dml"] - }, - "text/vnd.in3d.spot": { - source: "iana", - extensions: ["spot"] - }, - "text/vnd.iptc.newsml": { - source: "iana" - }, - "text/vnd.iptc.nitf": { - source: "iana" - }, - "text/vnd.latex-z": { - source: "iana" - }, - "text/vnd.motorola.reflex": { - source: "iana" - }, - "text/vnd.ms-mediapackage": { - source: "iana" - }, - "text/vnd.net2phone.commcenter.command": { - source: "iana" - }, - "text/vnd.radisys.msml-basic-layout": { - source: "iana" - }, - "text/vnd.senx.warpscript": { - source: "iana" - }, - "text/vnd.si.uricatalogue": { - source: "apache" - }, - "text/vnd.sosi": { - source: "iana" - }, - "text/vnd.sun.j2me.app-descriptor": { - source: "iana", - charset: "UTF-8", - extensions: ["jad"] - }, - "text/vnd.trolltech.linguist": { - source: "iana", - charset: "UTF-8" - }, - "text/vnd.vcf": { - source: "iana" - }, - "text/vnd.wap.si": { - source: "iana" - }, - "text/vnd.wap.sl": { - source: "iana" - }, - "text/vnd.wap.wml": { - source: "iana", - extensions: ["wml"] - }, - "text/vnd.wap.wmlscript": { - source: "iana", - extensions: ["wmls"] - }, - "text/vnd.zoo.kcl": { - source: "iana" - }, - "text/vtt": { - source: "iana", - charset: "UTF-8", - compressible: true, - extensions: ["vtt"] - }, - "text/wgsl": { - source: "iana", - extensions: ["wgsl"] - }, - "text/x-asm": { - source: "apache", - extensions: ["s", "asm"] - }, - "text/x-c": { - source: "apache", - extensions: ["c", "cc", "cxx", "cpp", "h", "hh", "dic"] - }, - "text/x-component": { - source: "nginx", - extensions: ["htc"] - }, - "text/x-fortran": { - source: "apache", - extensions: ["f", "for", "f77", "f90"] - }, - "text/x-gwt-rpc": { - compressible: true - }, - "text/x-handlebars-template": { - extensions: ["hbs"] - }, - "text/x-java-source": { - source: "apache", - extensions: ["java"] - }, - "text/x-jquery-tmpl": { - compressible: true - }, - "text/x-lua": { - extensions: ["lua"] - }, - "text/x-markdown": { - compressible: true, - extensions: ["mkd"] - }, - "text/x-nfo": { - source: "apache", - extensions: ["nfo"] - }, - "text/x-opml": { - source: "apache", - extensions: ["opml"] - }, - "text/x-org": { - compressible: true, - extensions: ["org"] - }, - "text/x-pascal": { - source: "apache", - extensions: ["p", "pas"] - }, - "text/x-processing": { - compressible: true, - extensions: ["pde"] - }, - "text/x-sass": { - extensions: ["sass"] - }, - "text/x-scss": { - extensions: ["scss"] - }, - "text/x-setext": { - source: "apache", - extensions: ["etx"] - }, - "text/x-sfv": { - source: "apache", - extensions: ["sfv"] - }, - "text/x-suse-ymp": { - compressible: true, - extensions: ["ymp"] - }, - "text/x-uuencode": { - source: "apache", - extensions: ["uu"] - }, - "text/x-vcalendar": { - source: "apache", - extensions: ["vcs"] - }, - "text/x-vcard": { - source: "apache", - extensions: ["vcf"] - }, - "text/xml": { - source: "iana", - compressible: true, - extensions: ["xml"] - }, - "text/xml-external-parsed-entity": { - source: "iana" - }, - "text/yaml": { - compressible: true, - extensions: ["yaml", "yml"] - }, - "video/1d-interleaved-parityfec": { - source: "iana" - }, - "video/3gpp": { - source: "iana", - extensions: ["3gp", "3gpp"] - }, - "video/3gpp-tt": { - source: "iana" - }, - "video/3gpp2": { - source: "iana", - extensions: ["3g2"] - }, - "video/av1": { - source: "iana" - }, - "video/bmpeg": { - source: "iana" - }, - "video/bt656": { - source: "iana" - }, - "video/celb": { - source: "iana" - }, - "video/dv": { - source: "iana" - }, - "video/encaprtp": { - source: "iana" - }, - "video/evc": { - source: "iana" - }, - "video/ffv1": { - source: "iana" - }, - "video/flexfec": { - source: "iana" - }, - "video/h261": { - source: "iana", - extensions: ["h261"] - }, - "video/h263": { - source: "iana", - extensions: ["h263"] - }, - "video/h263-1998": { - source: "iana" - }, - "video/h263-2000": { - source: "iana" - }, - "video/h264": { - source: "iana", - extensions: ["h264"] - }, - "video/h264-rcdo": { - source: "iana" - }, - "video/h264-svc": { - source: "iana" - }, - "video/h265": { - source: "iana" - }, - "video/h266": { - source: "iana" - }, - "video/iso.segment": { - source: "iana", - extensions: ["m4s"] - }, - "video/jpeg": { - source: "iana", - extensions: ["jpgv"] - }, - "video/jpeg2000": { - source: "iana" - }, - "video/jpm": { - source: "apache", - extensions: ["jpm", "jpgm"] - }, - "video/jxsv": { - source: "iana" - }, - "video/lottie+json": { - source: "iana", - compressible: true - }, - "video/matroska": { - source: "iana" - }, - "video/matroska-3d": { - source: "iana" - }, - "video/mj2": { - source: "iana", - extensions: ["mj2", "mjp2"] - }, - "video/mp1s": { - source: "iana" - }, - "video/mp2p": { - source: "iana" - }, - "video/mp2t": { - source: "iana", - extensions: ["ts", "m2t", "m2ts", "mts"] - }, - "video/mp4": { - source: "iana", - compressible: false, - extensions: ["mp4", "mp4v", "mpg4"] - }, - "video/mp4v-es": { - source: "iana" - }, - "video/mpeg": { - source: "iana", - compressible: false, - extensions: ["mpeg", "mpg", "mpe", "m1v", "m2v"] - }, - "video/mpeg4-generic": { - source: "iana" - }, - "video/mpv": { - source: "iana" - }, - "video/nv": { - source: "iana" - }, - "video/ogg": { - source: "iana", - compressible: false, - extensions: ["ogv"] - }, - "video/parityfec": { - source: "iana" - }, - "video/pointer": { - source: "iana" - }, - "video/quicktime": { - source: "iana", - compressible: false, - extensions: ["qt", "mov"] - }, - "video/raptorfec": { - source: "iana" - }, - "video/raw": { - source: "iana" - }, - "video/rtp-enc-aescm128": { - source: "iana" - }, - "video/rtploopback": { - source: "iana" - }, - "video/rtx": { - source: "iana" - }, - "video/scip": { - source: "iana" - }, - "video/smpte291": { - source: "iana" - }, - "video/smpte292m": { - source: "iana" - }, - "video/ulpfec": { - source: "iana" - }, - "video/vc1": { - source: "iana" - }, - "video/vc2": { - source: "iana" - }, - "video/vnd.cctv": { - source: "iana" - }, - "video/vnd.dece.hd": { - source: "iana", - extensions: ["uvh", "uvvh"] - }, - "video/vnd.dece.mobile": { - source: "iana", - extensions: ["uvm", "uvvm"] - }, - "video/vnd.dece.mp4": { - source: "iana" - }, - "video/vnd.dece.pd": { - source: "iana", - extensions: ["uvp", "uvvp"] - }, - "video/vnd.dece.sd": { - source: "iana", - extensions: ["uvs", "uvvs"] - }, - "video/vnd.dece.video": { - source: "iana", - extensions: ["uvv", "uvvv"] - }, - "video/vnd.directv.mpeg": { - source: "iana" - }, - "video/vnd.directv.mpeg-tts": { - source: "iana" - }, - "video/vnd.dlna.mpeg-tts": { - source: "iana" - }, - "video/vnd.dvb.file": { - source: "iana", - extensions: ["dvb"] - }, - "video/vnd.fvt": { - source: "iana", - extensions: ["fvt"] - }, - "video/vnd.hns.video": { - source: "iana" - }, - "video/vnd.iptvforum.1dparityfec-1010": { - source: "iana" - }, - "video/vnd.iptvforum.1dparityfec-2005": { - source: "iana" - }, - "video/vnd.iptvforum.2dparityfec-1010": { - source: "iana" - }, - "video/vnd.iptvforum.2dparityfec-2005": { - source: "iana" - }, - "video/vnd.iptvforum.ttsavc": { - source: "iana" - }, - "video/vnd.iptvforum.ttsmpeg2": { - source: "iana" - }, - "video/vnd.motorola.video": { - source: "iana" - }, - "video/vnd.motorola.videop": { - source: "iana" - }, - "video/vnd.mpegurl": { - source: "iana", - extensions: ["mxu", "m4u"] - }, - "video/vnd.ms-playready.media.pyv": { - source: "iana", - extensions: ["pyv"] - }, - "video/vnd.nokia.interleaved-multimedia": { - source: "iana" - }, - "video/vnd.nokia.mp4vr": { - source: "iana" - }, - "video/vnd.nokia.videovoip": { - source: "iana" - }, - "video/vnd.objectvideo": { - source: "iana" - }, - "video/vnd.planar": { - source: "iana" - }, - "video/vnd.radgamettools.bink": { - source: "iana" - }, - "video/vnd.radgamettools.smacker": { - source: "apache" - }, - "video/vnd.sealed.mpeg1": { - source: "iana" - }, - "video/vnd.sealed.mpeg4": { - source: "iana" - }, - "video/vnd.sealed.swf": { - source: "iana" - }, - "video/vnd.sealedmedia.softseal.mov": { - source: "iana" - }, - "video/vnd.uvvu.mp4": { - source: "iana", - extensions: ["uvu", "uvvu"] - }, - "video/vnd.vivo": { - source: "iana", - extensions: ["viv"] - }, - "video/vnd.youtube.yt": { - source: "iana" - }, - "video/vp8": { - source: "iana" - }, - "video/vp9": { - source: "iana" - }, - "video/webm": { - source: "apache", - compressible: false, - extensions: ["webm"] - }, - "video/x-f4v": { - source: "apache", - extensions: ["f4v"] - }, - "video/x-fli": { - source: "apache", - extensions: ["fli"] - }, - "video/x-flv": { - source: "apache", - compressible: false, - extensions: ["flv"] - }, - "video/x-m4v": { - source: "apache", - extensions: ["m4v"] - }, - "video/x-matroska": { - source: "apache", - compressible: false, - extensions: ["mkv", "mk3d", "mks"] - }, - "video/x-mng": { - source: "apache", - extensions: ["mng"] - }, - "video/x-ms-asf": { - source: "apache", - extensions: ["asf", "asx"] - }, - "video/x-ms-vob": { - source: "apache", - extensions: ["vob"] - }, - "video/x-ms-wm": { - source: "apache", - extensions: ["wm"] - }, - "video/x-ms-wmv": { - source: "apache", - compressible: false, - extensions: ["wmv"] - }, - "video/x-ms-wmx": { - source: "apache", - extensions: ["wmx"] - }, - "video/x-ms-wvx": { - source: "apache", - extensions: ["wvx"] - }, - "video/x-msvideo": { - source: "apache", - extensions: ["avi"] - }, - "video/x-sgi-movie": { - source: "apache", - extensions: ["movie"] - }, - "video/x-smv": { - source: "apache", - extensions: ["smv"] - }, - "x-conference/x-cooltalk": { - source: "apache", - extensions: ["ice"] - }, - "x-shader/x-fragment": { - compressible: true - }, - "x-shader/x-vertex": { - compressible: true - } - }; - } -}); -var require_lib19 = __commonJS({ - "node_modules/.deno/@hapi+mimos@7.0.1/node_modules/@hapi/mimos/lib/index.js"(exports2) { - "use strict"; - var Path = __require2("path"); - var Hoek = require_lib(); - var MimeDb = require_db(); - var internals = { - compressibleRx: /^text\/|\+json$|\+text$|\+xml$/ - }; - exports2.MimosEntry = class { - constructor(type, mime) { - this.type = type; - this.source = "mime-db"; - this.extensions = []; - this.compressible = void 0; - Object.assign(this, mime); - if (this.compressible === void 0) { - this.compressible = internals.compressibleRx.test(type); - } - } - }; - internals.insertEntry = function(type, entry, db2) { - db2.byType.set(type, entry); - for (const ext of entry.extensions) { - db2.byExtension.set(ext, entry); - if (ext.length > db2.maxExtLength) { - db2.maxExtLength = ext.length; - } - } - }; - internals.compile = function(mimedb) { - const db2 = { - byType: /* @__PURE__ */ new Map(), - byExtension: /* @__PURE__ */ new Map(), - maxExtLength: 0 - }; - for (const type in mimedb) { - const entry = new exports2.MimosEntry(type, mimedb[type]); - internals.insertEntry(type, entry, db2); - } - return db2; - }; - internals.getTypePart = function(fulltype) { - const splitAt = fulltype.indexOf(";"); - return splitAt === -1 ? fulltype : fulltype.slice(0, splitAt); - }; - internals.applyPredicate = function(mime) { - if (mime.predicate) { - return mime.predicate(Hoek.clone(mime)); - } - return mime; - }; - exports2.Mimos = class Mimos { - #db = internals.base; - constructor(options2 = {}) { - if (options2.override) { - Hoek.assert(typeof options2.override === "object", "overrides option must be an object"); - this.#db = { - ...this.#db, - byType: new Map(this.#db.byType), - byExtension: new Map(this.#db.byExtension) - }; - for (const type in options2.override) { - const override = options2.override[type]; - Hoek.assert(!override.predicate || typeof override.predicate === "function", "predicate option must be a function"); - const from3 = this.#db.byType.get(type); - const baseEntry = from3 ? Hoek.applyToDefaults(from3, override) : override; - const entry = new exports2.MimosEntry(type, baseEntry); - internals.insertEntry(type, entry, this.#db); - } - } - } - path(path8) { - const extension = Path.extname(path8).slice(1).toLowerCase(); - const mime = this.#db.byExtension.get(extension) ?? {}; - return internals.applyPredicate(mime); - } - type(type) { - type = internals.getTypePart(type); - let mime = this.#db.byType.get(type); - if (!mime) { - type = type.trim().toLowerCase(); - mime = this.#db.byType.get(type); - } - if (!mime) { - mime = new exports2.MimosEntry(type, { - source: "mimos" - }); - internals.insertEntry(type, mime, this.#db); - return mime; - } - return internals.applyPredicate(mime); - } - }; - internals.base = internals.compile(MimeDb); - } -}); -var require_lib20 = __commonJS({ - "node_modules/.deno/@hapi+bourne@3.0.0/node_modules/@hapi/bourne/lib/index.js"(exports2) { - "use strict"; - var internals = { - suspectRx: /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*\:/ - }; - exports2.parse = function(text, ...args) { - const firstOptions = typeof args[0] === "object" && args[0]; - const reviver = args.length > 1 || !firstOptions ? args[0] : void 0; - const options2 = args.length > 1 && args[1] || firstOptions || {}; - const obj = JSON.parse(text, reviver); - if (options2.protoAction === "ignore") { - return obj; - } - if (!obj || typeof obj !== "object") { - return obj; - } - if (!text.match(internals.suspectRx)) { - return obj; - } - exports2.scan(obj, options2); - return obj; - }; - exports2.scan = function(obj, options2 = {}) { - let next = [obj]; - while (next.length) { - const nodes = next; - next = []; - for (const node of nodes) { - if (Object.prototype.hasOwnProperty.call(node, "__proto__")) { - if (options2.protoAction !== "remove") { - throw new SyntaxError("Object contains forbidden prototype property"); - } - delete node.__proto__; - } - for (const key in node) { - const value = node[key]; - if (value && typeof value === "object") { - next.push(node[key]); - } - } - } - } - }; - exports2.safeParse = function(text, reviver) { - try { - return exports2.parse(text, reviver); - } catch (ignoreError) { - return null; - } - }; - } -}); -var require_lib21 = __commonJS({ - "node_modules/.deno/@hapi+cryptiles@6.0.1/node_modules/@hapi/cryptiles/lib/index.js"(exports2) { - "use strict"; - var Crypto = __require2("crypto"); - var Boom5 = require_lib2(); - var internals = {}; - exports2.randomString = function(size) { - const buffer = exports2.randomBits((size + 1) * 6); - const string3 = buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, ""); - return string3.slice(0, size); - }; - exports2.randomAlphanumString = function(size) { - let result = ""; - while (result.length < size) { - const buffer = exports2.randomBits((size + 1) * 6); - result += buffer.toString("base64").replace(/[^a-zA-Z0-9]/g, ""); - } - return result.slice(0, size); - }; - exports2.randomDigits = function(size) { - const digits = []; - let buffer = internals.random(size * 2); - let pos = 0; - while (digits.length < size) { - if (pos >= buffer.length) { - buffer = internals.random(size * 2); - pos = 0; - } - if (buffer[pos] < 250) { - digits.push(buffer[pos] % 10); - } - ++pos; - } - return digits.join(""); - }; - exports2.randomBits = function(bits) { - if (!bits || bits < 0) { - throw Boom5.internal("Invalid random bits count"); - } - const bytes = Math.ceil(bits / 8); - return internals.random(bytes); - }; - exports2.fixedTimeComparison = function(a, b) { - try { - return Crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)); - } catch (err) { - return false; - } - }; - internals.random = function(bytes) { - try { - return Crypto.randomBytes(bytes); - } catch (err) { - throw Boom5.internal("Failed generating random bits: " + err.message); - } - }; - } -}); -var require_decoder2 = __commonJS({ - "node_modules/.deno/@hapi+b64@6.0.1/node_modules/@hapi/b64/lib/decoder.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var internals = { - decodeChars: [ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - 62, - -1, - -1, - -1, - 63, - 52, - 53, - 54, - 55, - 56, - 57, - 58, - 59, - 60, - 61, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21, - 22, - 23, - 24, - 25, - -1, - -1, - -1, - -1, - -1, - -1, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - -1, - -1, - -1, - -1, - -1 - ] - }; - exports2.decode = function(buffer) { - const decodeChars = internals.decodeChars; - const len = buffer.length; - const allocated = Math.ceil(len / 4) * 3; - const result = Buffer.alloc(allocated); - let c1; - let c2; - let c3; - let c4; - let j = 0; - for (let i2 = 0; i2 < len; ) { - do { - c1 = decodeChars[buffer[i2++] & 255]; - } while (i2 < len && c1 === -1); - if (c1 === -1) { - break; - } - do { - c2 = decodeChars[buffer[i2++] & 255]; - } while (i2 < len && c2 === -1); - if (c2 === -1) { - break; - } - result[j++] = c1 << 2 | (c2 & 48) >> 4; - do { - c3 = buffer[i2++] & 255; - if (c3 === 61) { - return result.slice(0, j); - } - c3 = decodeChars[c3]; - } while (i2 < len && c3 === -1); - if (c3 === -1) { - break; - } - result[j++] = (c2 & 15) << 4 | (c3 & 60) >> 2; - do { - c4 = buffer[i2++] & 255; - if (c4 === 61) { - return result.slice(0, j); - } - c4 = decodeChars[c4]; - } while (i2 < len && c4 === -1); - if (c4 !== -1) { - result[j++] = (c3 & 3) << 6 | c4; - } - } - return j === allocated ? result : result.slice(0, j); - }; - exports2.Decoder = class Decoder extends Stream.Transform { - constructor() { - super(); - this._reminder = null; - } - _transform(chunk, encoding, callback) { - let part = this._reminder ? Buffer.concat([this._reminder, chunk]) : chunk; - const remaining = part.length % 4; - if (remaining) { - this._reminder = part.slice(part.length - remaining); - part = part.slice(0, part.length - remaining); - } else { - this._reminder = null; - } - this.push(exports2.decode(part)); - return callback(); - } - _flush(callback) { - if (this._reminder) { - this.push(exports2.decode(this._reminder)); - } - return callback(); - } - }; - } -}); -var require_encoder2 = __commonJS({ - "node_modules/.deno/@hapi+b64@6.0.1/node_modules/@hapi/b64/lib/encoder.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - exports2.encode = function(buffer) { - return Buffer.from(buffer.toString("base64")); - }; - exports2.Encoder = class Encoder extends Stream.Transform { - constructor() { - super(); - this._reminder = null; - } - _transform(chunk, encoding, callback) { - let part = this._reminder ? Buffer.concat([this._reminder, chunk]) : chunk; - const remaining = part.length % 3; - if (remaining) { - this._reminder = part.slice(part.length - remaining); - part = part.slice(0, part.length - remaining); - } else { - this._reminder = null; - } - this.push(exports2.encode(part)); - return callback(); - } - _flush(callback) { - if (this._reminder) { - this.push(exports2.encode(this._reminder)); - } - return callback(); - } - }; - } -}); -var require_lib22 = __commonJS({ - "node_modules/.deno/@hapi+b64@6.0.1/node_modules/@hapi/b64/lib/index.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var Decoder2 = require_decoder2(); - var Encoder2 = require_encoder2(); - exports2.decode = Decoder2.decode; - exports2.encode = Encoder2.encode; - exports2.Decoder = Decoder2.Decoder; - exports2.Encoder = Encoder2.Encoder; - exports2.base64urlEncode = function(value, encoding) { - Hoek.assert(typeof value === "string" || Buffer.isBuffer(value), "value must be string or buffer"); - const buf2 = Buffer.isBuffer(value) ? value : Buffer.from(value, encoding || "binary"); - return buf2.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, ""); - }; - exports2.base64urlDecode = function(value, encoding) { - if (typeof value !== "string") { - throw new Error("Value not a string"); - } - if (!/^[\w\-]*$/.test(value)) { - throw new Error("Invalid character"); - } - const buf2 = Buffer.from(value, "base64"); - return encoding === "buffer" ? buf2 : buf2.toString(encoding || "binary"); - }; - } -}); -var require_lib23 = __commonJS({ - "node_modules/.deno/@hapi+iron@7.0.1/node_modules/@hapi/iron/lib/index.js"(exports2) { - "use strict"; - var Crypto = __require2("crypto"); - var B64 = require_lib22(); - var Boom5 = require_lib2(); - var Bourne = require_lib20(); - var Cryptiles = require_lib21(); - var Hoek = require_lib(); - var internals = {}; - exports2.defaults = { - encryption: { - saltBits: 256, - algorithm: "aes-256-cbc", - iterations: 1, - minPasswordlength: 32 - }, - integrity: { - saltBits: 256, - algorithm: "sha256", - iterations: 1, - minPasswordlength: 32 - }, - ttl: 0, - // Milliseconds, 0 means forever - timestampSkewSec: 60, - // Seconds of permitted clock skew for incoming expirations - localtimeOffsetMsec: 0 - // Local clock time offset express in a number of milliseconds (positive or negative) - }; - exports2.algorithms = { - "aes-128-ctr": { keyBits: 128, ivBits: 128 }, - "aes-256-cbc": { keyBits: 256, ivBits: 128 }, - "sha256": { keyBits: 256 } - }; - exports2.macFormatVersion = "2"; - exports2.macPrefix = "Fe26." + exports2.macFormatVersion; - exports2.generateKey = async function(password, options2) { - if (!password) { - throw new Boom5.Boom("Empty password"); - } - if (!options2 || typeof options2 !== "object") { - throw new Boom5.Boom("Bad options"); - } - const algorithm = exports2.algorithms[options2.algorithm]; - if (!algorithm) { - throw new Boom5.Boom("Unknown algorithm: " + options2.algorithm); - } - const result = {}; - if (Buffer.isBuffer(password)) { - if (password.length < algorithm.keyBits / 8) { - throw new Boom5.Boom("Key buffer (password) too small"); - } - result.key = password; - result.salt = ""; - } else { - if (password.length < options2.minPasswordlength) { - throw new Boom5.Boom("Password string too short (min " + options2.minPasswordlength + " characters required)"); - } - let salt = options2.salt; - if (!salt) { - if (!options2.saltBits) { - throw new Boom5.Boom("Missing salt and saltBits options"); - } - const randomSalt = Cryptiles.randomBits(options2.saltBits); - salt = randomSalt.toString("hex"); - } - const derivedKey = await internals.pbkdf2(password, salt, options2.iterations, algorithm.keyBits / 8, "sha1"); - result.key = derivedKey; - result.salt = salt; - } - if (options2.iv) { - result.iv = options2.iv; - } else if (algorithm.ivBits) { - result.iv = Cryptiles.randomBits(algorithm.ivBits); - } - return result; - }; - exports2.encrypt = async function(password, options2, data) { - const key = await exports2.generateKey(password, options2); - const cipher = Crypto.createCipheriv(options2.algorithm, key.key, key.iv); - const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]); - return { encrypted, key }; - }; - exports2.decrypt = async function(password, options2, data) { - const key = await exports2.generateKey(password, options2); - const decipher = Crypto.createDecipheriv(options2.algorithm, key.key, key.iv); - let dec = decipher.update(data, null, "utf8"); - dec = dec + decipher.final("utf8"); - return dec; - }; - exports2.hmacWithPassword = async function(password, options2, data) { - const key = await exports2.generateKey(password, options2); - const hmac = Crypto.createHmac(options2.algorithm, key.key).update(data); - const digest = hmac.digest("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/\=/g, ""); - return { - digest, - salt: key.salt - }; - }; - internals.normalizePassword = function(password) { - if (password && typeof password === "object" && !Buffer.isBuffer(password)) { - return { - id: password.id, - encryption: password.secret ?? password.encryption, - integrity: password.secret ?? password.integrity - }; - } - return { - encryption: password, - integrity: password - }; - }; - exports2.seal = async function(object2, password, options2) { - options2 = Object.assign({}, options2); - const now = Date.now() + (options2.localtimeOffsetMsec ?? 0); - const objectString = internals.stringify(object2); - let passwordId = ""; - password = internals.normalizePassword(password); - if (password.id) { - if (!/^\w+$/.test(password.id)) { - throw new Boom5.Boom("Invalid password id"); - } - passwordId = password.id; - } - const { encrypted, key } = await exports2.encrypt(password.encryption, options2.encryption, objectString); - const encryptedB64 = B64.base64urlEncode(encrypted); - const iv = B64.base64urlEncode(key.iv); - const expiration = options2.ttl ? now + options2.ttl : ""; - const macBaseString = exports2.macPrefix + "*" + passwordId + "*" + key.salt + "*" + iv + "*" + encryptedB64 + "*" + expiration; - const mac = await exports2.hmacWithPassword(password.integrity, options2.integrity, macBaseString); - const sealed = macBaseString + "*" + mac.salt + "*" + mac.digest; - return sealed; - }; - exports2.unseal = async function(sealed, password, options2) { - options2 = Object.assign({}, options2); - const now = Date.now() + (options2.localtimeOffsetMsec ?? 0); - const parts = sealed.split("*"); - if (parts.length !== 8) { - throw new Boom5.Boom("Incorrect number of sealed components"); - } - const macPrefix = parts[0]; - const passwordId = parts[1]; - const encryptionSalt = parts[2]; - const encryptionIv = parts[3]; - const encryptedB64 = parts[4]; - const expiration = parts[5]; - const hmacSalt = parts[6]; - const hmac = parts[7]; - const macBaseString = macPrefix + "*" + passwordId + "*" + encryptionSalt + "*" + encryptionIv + "*" + encryptedB64 + "*" + expiration; - if (macPrefix !== exports2.macPrefix) { - throw new Boom5.Boom("Wrong mac prefix"); - } - if (expiration) { - if (!expiration.match(/^\d+$/)) { - throw new Boom5.Boom("Invalid expiration"); - } - const exp = parseInt(expiration, 10); - if (exp <= now - options2.timestampSkewSec * 1e3) { - throw new Boom5.Boom("Expired seal"); - } - } - if (!password) { - throw new Boom5.Boom("Empty password"); - } - if (typeof password === "object" && !Buffer.isBuffer(password)) { - password = password[passwordId || "default"]; - if (!password) { - throw new Boom5.Boom("Cannot find password: " + passwordId); - } - } - password = internals.normalizePassword(password); - const macOptions = Hoek.clone(options2.integrity); - macOptions.salt = hmacSalt; - const mac = await exports2.hmacWithPassword(password.integrity, macOptions, macBaseString); - if (!Cryptiles.fixedTimeComparison(mac.digest, hmac)) { - throw new Boom5.Boom("Bad hmac value"); - } - try { - var encrypted = B64.base64urlDecode(encryptedB64, "buffer"); - } catch (err) { - throw Boom5.boomify(err); - } - const decryptOptions = Hoek.clone(options2.encryption); - decryptOptions.salt = encryptionSalt; - try { - decryptOptions.iv = B64.base64urlDecode(encryptionIv, "buffer"); - } catch (err) { - throw Boom5.boomify(err); - } - const decrypted = await exports2.decrypt(password.encryption, decryptOptions, encrypted); - try { - return Bourne.parse(decrypted); - } catch (err) { - throw new Boom5.Boom("Failed parsing sealed object JSON: " + err.message); - } - }; - internals.stringify = function(object2) { - try { - return JSON.stringify(object2); - } catch (err) { - throw new Boom5.Boom("Failed to stringify object: " + err.message); - } - }; - internals.pbkdf2 = function(...args) { - return new Promise((resolve82, reject) => { - const next = (err, result) => { - if (err) { - return reject(Boom5.boomify(err)); - } - resolve82(result); - }; - args.push(next); - Crypto.pbkdf2(...args); - }); - }; - } -}); -var require_lib24 = __commonJS({ - "node_modules/.deno/@hapi+statehood@8.2.0/node_modules/@hapi/statehood/lib/index.js"(exports2) { - "use strict"; - var Querystring = __require2("querystring"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Bourne = require_lib20(); - var Cryptiles = require_lib21(); - var Hoek = require_lib(); - var Iron = require_lib23(); - var Validate = require_lib9(); - var internals = { - macPrefix: "hapi.signed.cookie.1" - }; - internals.schema = Validate.object({ - strictHeader: Validate.boolean(), - ignoreErrors: Validate.boolean(), - isSecure: Validate.boolean(), - isHttpOnly: Validate.boolean(), - isPartitioned: Validate.boolean(), - isSameSite: Validate.valid("Strict", "Lax", "None", false), - path: Validate.string().allow(null), - domain: Validate.string().allow(null), - ttl: Validate.number().allow(null), - encoding: Validate.string().valid("base64json", "base64", "form", "iron", "none"), - sign: Validate.object({ - password: [Validate.string(), Validate.binary(), Validate.object()], - integrity: Validate.object() - }), - iron: Validate.object(), - password: [Validate.string(), Validate.binary(), Validate.object()], - contextualize: Validate.function(), - // Used by hapi - clearInvalid: Validate.boolean(), - autoValue: Validate.any(), - passThrough: Validate.boolean() - }); - internals.defaults = { - strictHeader: true, - // Require an RFC 6265 compliant header format - ignoreErrors: false, - isSecure: true, - isHttpOnly: true, - isPartitioned: false, - isSameSite: "Strict", - path: null, - domain: null, - ttl: null, - // MSecs, 0 means remove - encoding: "none" - // options: 'base64json', 'base64', 'form', 'iron', 'none' - }; - internals.validateRx = { - nameRx: { - strict: /^[^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+$/, - loose: /^[^=\s]*$/ - }, - valueRx: { - strict: /^[^\x00-\x20\"\,\;\\\x7F]*$/, - loose: /^(?:"([^\"]*)")|(?:[^\;]*)$/ - }, - domainRx: /^\.?[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d]))(?:\.[a-z\d]+(?:(?:[a-z\d]*)|(?:[a-z\d\-]*[a-z\d])))*$/, - domainLabelLenRx: /^\.?[a-z\d\-]{1,63}(?:\.[a-z\d\-]{1,63})*$/, - pathRx: /^\/[^\x00-\x1F\;]*$/ - }; - internals.pairsRx = /\s*([^=\s]*)\s*=\s*([^\;]*)(?:(?:;\s*)|$)/g; - exports2.Definitions = class { - constructor(options2) { - this.settings = Hoek.applyToDefaults(internals.defaults, options2 ?? {}); - Validate.assert(this.settings, internals.schema, "Invalid state definition defaults"); - this.cookies = {}; - this.names = []; - } - add(name, options2) { - Hoek.assert(name && typeof name === "string", "Invalid name"); - Hoek.assert(!this.cookies[name], "State already defined:", name); - const settings = Hoek.applyToDefaults(this.settings, options2 ?? {}, { nullOverride: true }); - Validate.assert(settings, internals.schema, "Invalid state definition: " + name); - this.cookies[name] = settings; - this.names.push(name); - } - async parse(cookies) { - const state = {}; - const names = []; - const verify = internals.parsePairs(cookies, (name, value) => { - if (name === "__proto__") { - throw Boom5.badRequest("Invalid cookie header"); - } - if (state[name]) { - if (!Array.isArray(state[name])) { - state[name] = [state[name]]; - } - state[name].push(value); - } else { - state[name] = value; - names.push(name); - } - }); - const failed = []; - if (verify !== null) { - if (!this.settings.ignoreErrors) { - throw Boom5.badRequest("Invalid cookie header"); - } - failed.push({ settings: this.settings, reason: `Header contains unexpected syntax: ${verify}` }); - } - const errored = []; - const record2 = (reason, name, value, definition) => { - const details = { - name, - value, - settings: definition, - reason: typeof reason === "string" ? reason : reason.message - }; - failed.push(details); - if (!definition.ignoreErrors) { - errored.push(details); - } - }; - const parsed = {}; - for (const name of names) { - const value = state[name]; - const definition = this.cookies[name] ?? this.settings; - if (definition.strictHeader) { - const reason = internals.validate(name, state); - if (reason) { - record2(reason, name, value, definition); - continue; - } - } - if (definition.encoding === "none") { - parsed[name] = value; - continue; - } - if (!Array.isArray(value)) { - try { - const unsigned = await internals.unsign(name, value, definition); - const result = await internals.decode(unsigned, definition); - parsed[name] = result; - } catch (err) { - Bounce.rethrow(err, "system"); - record2(err, name, value, definition); - } - continue; - } - const arrayResult = []; - for (const arrayValue of value) { - try { - const unsigned = await internals.unsign(name, arrayValue, definition); - const result = await internals.decode(unsigned, definition); - arrayResult.push(result); - } catch (err) { - Bounce.rethrow(err, "system"); - record2(err, name, value, definition); - } - } - parsed[name] = arrayResult; - } - if (errored.length) { - const error2 = Boom5.badRequest("Invalid cookie value", errored); - error2.states = parsed; - error2.failed = failed; - throw error2; - } - return { states: parsed, failed }; - } - async format(cookies, context) { - if (!cookies || Array.isArray(cookies) && !cookies.length) { - return []; - } - if (!Array.isArray(cookies)) { - cookies = [cookies]; - } - const header = []; - for (let i2 = 0; i2 < cookies.length; ++i2) { - const cookie = cookies[i2]; - const base2 = this.cookies[cookie.name] ?? this.settings; - let definition = cookie.options ? Hoek.applyToDefaults(base2, cookie.options, { nullOverride: true }) : base2; - if (definition.contextualize) { - if (definition === base2) { - definition = Hoek.clone(definition); - } - await definition.contextualize(definition, context); - } - const nameRx = definition.strictHeader ? internals.validateRx.nameRx.strict : internals.validateRx.nameRx.loose; - if (!nameRx.test(cookie.name)) { - throw Boom5.badImplementation("Invalid cookie name: " + cookie.name); - } - const value = await exports2.prepareValue(cookie.name, cookie.value, definition); - const valueRx = definition.strictHeader ? internals.validateRx.valueRx.strict : internals.validateRx.valueRx.loose; - if (value && (typeof value !== "string" || !value.match(valueRx))) { - throw Boom5.badImplementation("Invalid cookie value: " + cookie.value); - } - let segment = cookie.name + "=" + (value || ""); - if (definition.ttl !== null && definition.ttl !== void 0) { - const expires = new Date(definition.ttl ? Date.now() + definition.ttl : 0); - segment = segment + "; Max-Age=" + Math.floor(definition.ttl / 1e3) + "; Expires=" + expires.toUTCString(); - } - if (definition.isSecure) { - segment = segment + "; Secure"; - } - if (definition.isHttpOnly) { - segment = segment + "; HttpOnly"; - } - if (definition.isSameSite) { - segment = `${segment}; SameSite=${definition.isSameSite}`; - } - if (definition.isPartitioned) { - if (!definition.isSecure) { - throw Boom5.badImplementation("Partitioned cookies must be secure"); - } - if (definition.isSameSite !== "None") { - throw Boom5.badImplementation("Partitioned cookies must have SameSite=None"); - } - segment = `${segment}; Partitioned`; - } - if (definition.domain) { - const domain = definition.domain.toLowerCase(); - if (!domain.match(internals.validateRx.domainLabelLenRx)) { - throw Boom5.badImplementation("Cookie domain too long: " + definition.domain); - } - if (!domain.match(internals.validateRx.domainRx)) { - throw Boom5.badImplementation("Invalid cookie domain: " + definition.domain); - } - segment = segment + "; Domain=" + domain; - } - if (definition.path) { - if (!definition.path.match(internals.validateRx.pathRx)) { - throw Boom5.badImplementation("Invalid cookie path: " + definition.path); - } - segment = segment + "; Path=" + definition.path; - } - header.push(segment); - } - return header; - } - passThrough(header, fallback) { - if (!this.names.length) { - return header; - } - const exclude = []; - for (let i2 = 0; i2 < this.names.length; ++i2) { - const name = this.names[i2]; - const definition = this.cookies[name]; - const passCookie = definition.passThrough !== void 0 ? definition.passThrough : fallback; - if (!passCookie) { - exclude.push(name); - } - } - return exports2.exclude(header, exclude); - } - }; - internals.parsePairs = function(cookies, eachPairFn) { - let index = 0; - while (index < cookies.length) { - const eqIndex = cookies.indexOf("=", index); - if (eqIndex === -1) { - return cookies.slice(index); - } - const semiIndex = cookies.indexOf(";", eqIndex); - const endOfValueIndex = semiIndex !== -1 ? semiIndex : cookies.length; - const name = cookies.slice(index, eqIndex).trim(); - const value = cookies.slice(eqIndex + 1, endOfValueIndex).trim(); - const unquotedValue = value.startsWith('"') && value.endsWith('"') && value !== '"' ? value.slice(1, -1) : ( - // E.g. '"abc"' -> 'abc' - value - ); - eachPairFn(name, unquotedValue); - index = endOfValueIndex + 1; - } - return null; - }; - internals.validate = function(name, state) { - if (!name.match(internals.validateRx.nameRx.strict)) { - return "Invalid cookie name"; - } - const values = [].concat(state[name]); - for (let i2 = 0; i2 < values.length; ++i2) { - if (!values[i2].match(internals.validateRx.valueRx.strict)) { - return "Invalid cookie value"; - } - } - return null; - }; - internals.unsign = async function(name, value, definition) { - if (!definition.sign) { - return value; - } - const pos = value.lastIndexOf("."); - if (pos === -1) { - throw Boom5.badRequest("Missing signature separator"); - } - const unsigned = value.slice(0, pos); - const sig = value.slice(pos + 1); - if (!sig) { - throw Boom5.badRequest("Missing signature"); - } - const sigParts = sig.split("*"); - if (sigParts.length !== 2) { - throw Boom5.badRequest("Invalid signature format"); - } - const hmacSalt = sigParts[0]; - const hmac = sigParts[1]; - const macOptions = Hoek.clone(definition.sign.integrity ?? Iron.defaults.integrity); - macOptions.salt = hmacSalt; - const mac = await Iron.hmacWithPassword(definition.sign.password, macOptions, [internals.macPrefix, name, unsigned].join("\n")); - if (!Cryptiles.fixedTimeComparison(mac.digest, hmac)) { - throw Boom5.badRequest("Invalid hmac value"); - } - return unsigned; - }; - internals.decode = async function(value, definition) { - if (!value && definition.encoding === "form") { - return {}; - } - Hoek.assert(typeof value === "string", "Invalid string"); - if (definition.encoding === "iron") { - return await Iron.unseal(value, definition.password, definition.iron ?? Iron.defaults); - } - if (definition.encoding === "base64json") { - const decoded = Buffer.from(value, "base64").toString("binary"); - try { - return Bourne.parse(decoded); - } catch (err) { - throw Boom5.badRequest("Invalid JSON payload"); - } - } - if (definition.encoding === "base64") { - return Buffer.from(value, "base64").toString("binary"); - } - return Querystring.parse(value); - }; - exports2.prepareValue = async function(name, value, options2) { - Hoek.assert(options2 && typeof options2 === "object", "Missing or invalid options"); - try { - const encoded = await internals.encode(value, options2); - const signed = await internals.sign(name, encoded, options2.sign); - return signed; - } catch (err) { - throw Boom5.badImplementation("Failed to encode cookie (" + name + ") value: " + err.message); - } - }; - internals.encode = function(value, options2) { - if (value === void 0 || options2.encoding === "none") { - return value; - } - if (options2.encoding === "iron") { - return Iron.seal(value, options2.password, options2.iron ?? Iron.defaults); - } - if (options2.encoding === "base64") { - return Buffer.from(value, "binary").toString("base64"); - } - if (options2.encoding === "base64json") { - const stringified = JSON.stringify(value); - return Buffer.from(stringified, "binary").toString("base64"); - } - return Querystring.stringify(value); - }; - internals.sign = async function(name, value, options2) { - if (value === void 0 || !options2) { - return value; - } - const mac = await Iron.hmacWithPassword(options2.password, options2.integrity ?? Iron.defaults.integrity, [internals.macPrefix, name, value].join("\n")); - const signed = value + "." + mac.salt + "*" + mac.digest; - return signed; - }; - exports2.exclude = function(cookies, excludes) { - let result = ""; - const verify = cookies.replace(internals.pairsRx, ($0, $1, $2) => { - if (excludes.indexOf($1) === -1) { - result = result + (result ? ";" : "") + $1 + "=" + $2; - } - return ""; - }); - return verify === "" ? result : Boom5.badRequest("Invalid cookie header"); - }; - } -}); -var require_lib25 = __commonJS({ - "node_modules/.deno/@hapi+content@6.0.0/node_modules/@hapi/content/lib/index.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var internals = {}; - internals.contentTypeRegex = /^([^\/\s]+\/[^\s;]+)(.*)?$/; - internals.charsetParamRegex = /;\s*charset=(?:"([^"]+)"|([^;"\s]+))/i; - internals.boundaryParamRegex = /;\s*boundary=(?:"([^"]+)"|([^;"\s]+))/i; - exports2.type = function(header) { - if (!header) { - throw Boom5.badRequest("Invalid content-type header"); - } - const match = header.match(internals.contentTypeRegex); - if (!match) { - throw Boom5.badRequest("Invalid content-type header"); - } - const result = { - mime: match[1].toLowerCase() - }; - const params = match[2]; - if (params) { - const param = params.match(internals.charsetParamRegex); - if (param) { - result.charset = (param[1] || param[2]).toLowerCase(); - } - } - if (result.mime.indexOf("multipart/") === 0) { - if (params) { - const param = params.match(internals.boundaryParamRegex); - if (param) { - result.boundary = param[1] || param[2]; - } - } - if (!result.boundary) { - throw Boom5.badRequest("Invalid content-type header: multipart missing boundary"); - } - } - return result; - }; - internals.contentDispositionRegex = /^\s*form-data\s*(?:;\s*(.+))?$/i; - internals.contentDispositionParamRegex = /([^\=\*\s]+)(\*)?\s*\=\s*(?:([^;'"\s]+\'[\w-]*\'[^;\s]+)|(?:\"([^"]*)\")|([^;\s]*))(?:\s*(?:;\s*)|$)/g; - exports2.disposition = function(header) { - if (!header) { - throw Boom5.badRequest("Missing content-disposition header"); - } - const match = header.match(internals.contentDispositionRegex); - if (!match) { - throw Boom5.badRequest("Invalid content-disposition header format"); - } - const parameters = match[1]; - if (!parameters) { - throw Boom5.badRequest("Invalid content-disposition header missing parameters"); - } - const result = {}; - parameters.replace(internals.contentDispositionParamRegex, ($0, $1, $2, $3, $4, $5) => { - if ($1 === "__proto__") { - throw Boom5.badRequest("Invalid content-disposition header format includes invalid parameters"); - } - let value; - if ($2) { - if (!$3) { - throw Boom5.badRequest("Invalid content-disposition header format includes invalid parameters"); - } - try { - value = decodeURIComponent($3.split("'")[2]); - } catch (err) { - throw Boom5.badRequest("Invalid content-disposition header format includes invalid parameters"); - } - } else { - value = $4 || $5 || ""; - } - if ($1 === "name" && value === "__proto__") { - throw Boom5.badRequest("Invalid content-disposition header format includes invalid parameters"); - } - result[$1] = value; - }); - if (!result.name) { - throw Boom5.badRequest("Invalid content-disposition header missing name parameter"); - } - return result; - }; - } -}); -var require_lib26 = __commonJS({ - "node_modules/.deno/@hapi+file@3.0.0/node_modules/@hapi/file/lib/index.js"(exports2) { - "use strict"; - var Crypto = __require2("crypto"); - var Path = __require2("path"); - exports2.uniqueFilename = function(path8, extension) { - if (extension) { - extension = extension[0] !== "." ? "." + extension : extension; - } else { - extension = ""; - } - path8 = Path.resolve(path8); - const name = [Date.now(), process.pid, Crypto.randomBytes(8).toString("hex")].join("-") + extension; - return Path.join(path8, name); - }; - } -}); -var require_lib27 = __commonJS({ - "node_modules/.deno/@hapi+vise@5.0.1/node_modules/@hapi/vise/lib/index.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - exports2.Vise = class Vise { - constructor(chunks) { - this.length = 0; - this._chunks = []; - this._offset = 0; - if (chunks) { - chunks = [].concat(chunks); - for (let i2 = 0; i2 < chunks.length; ++i2) { - this.push(chunks[i2]); - } - } - } - push(chunk) { - Hoek.assert(Buffer.isBuffer(chunk), "Chunk must be a buffer"); - const item = { - data: chunk, - length: chunk.length, - offset: this.length + this._offset, - index: this._chunks.length - }; - this._chunks.push(item); - this.length += chunk.length; - } - shift(length2) { - if (!length2) { - return []; - } - const prevOffset = this._offset; - const item = this.#chunkAt(length2); - let dropTo = this._chunks.length; - this._offset = 0; - if (item) { - dropTo = item.chunk.index; - this._offset = item.offset; - } - const chunks = []; - for (let i2 = 0; i2 < dropTo; ++i2) { - const chunk = this._chunks.shift(); - if (i2 === 0 && prevOffset) { - chunks.push(chunk.data.slice(prevOffset)); - } else { - chunks.push(chunk.data); - } - } - if (this._offset) { - chunks.push(item.chunk.data.slice(dropTo ? 0 : prevOffset, this._offset)); - } - this.length = 0; - for (let i2 = 0; i2 < this._chunks.length; ++i2) { - const chunk = this._chunks[i2]; - chunk.offset = this.length, chunk.index = i2; - this.length += chunk.length; - } - this.length -= this._offset; - return chunks; - } - readUInt8(pos) { - const item = this.#chunkAt(pos); - return item ? item.chunk.data[item.offset] : void 0; - } - at(pos) { - return this.readUInt8(pos); - } - #chunkAt(pos) { - if (pos < 0) { - return null; - } - pos = pos + this._offset; - for (let i2 = 0; i2 < this._chunks.length; ++i2) { - const chunk = this._chunks[i2]; - const offset = pos - chunk.offset; - if (offset < chunk.length) { - return { chunk, offset }; - } - } - return null; - } - chunks() { - const chunks = []; - for (let i2 = 0; i2 < this._chunks.length; ++i2) { - const chunk = this._chunks[i2]; - if (i2 === 0 && this._offset) { - chunks.push(chunk.data.slice(this._offset)); - } else { - chunks.push(chunk.data); - } - } - return chunks; - } - startsWith(value, pos, length2) { - pos = pos ?? 0; - length2 = length2 ? Math.min(value.length, length2) : value.length; - if (pos + length2 > this.length) { - return false; - } - const start = this.#chunkAt(pos); - if (!start) { - return false; - } - let j = start.chunk.index; - for (let i2 = 0; j < this._chunks.length && i2 < length2; ++j) { - const chunk = this._chunks[j]; - let k = j === start.chunk.index ? start.offset : 0; - for (; k < chunk.length && i2 < length2; ++k, ++i2) { - if (chunk.data[k] !== value[i2]) { - return false; - } - } - } - return true; - } - }; - } -}); -var require_lib28 = __commonJS({ - "node_modules/.deno/@hapi+nigel@5.0.1/node_modules/@hapi/nigel/lib/index.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var Hoek = require_lib(); - var { Vise } = require_lib27(); - var internals = {}; - exports2.compile = function(needle) { - Hoek.assert(needle?.length, "Missing needle"); - Hoek.assert(Buffer.isBuffer(needle), "Needle must be a buffer"); - const profile = { - value: needle, - lastPos: needle.length - 1, - last: needle[needle.length - 1], - length: needle.length, - badCharShift: Buffer.alloc(256) - // Lookup table of how many characters can be skipped for each match - }; - for (let i2 = 0; i2 < 256; ++i2) { - profile.badCharShift[i2] = profile.length; - } - const last = profile.length - 1; - for (let i2 = 0; i2 < last; ++i2) { - profile.badCharShift[profile.value[i2]] = last - i2; - } - return profile; - }; - exports2.horspool = function(haystack, needle, start) { - Hoek.assert(haystack, "Missing haystack"); - needle = needle.badCharShift ? needle : exports2.compile(needle); - start = start ?? 0; - for (let i2 = start; i2 <= haystack.length - needle.length; ) { - const lastChar = haystack.readUInt8(i2 + needle.lastPos); - if (lastChar === needle.last && internals.startsWith(haystack, needle, i2)) { - return i2; - } - i2 += needle.badCharShift[lastChar]; - } - return -1; - }; - internals.startsWith = function(haystack, needle, pos) { - if (haystack.startsWith) { - return haystack.startsWith(needle.value, pos, needle.lastPos); - } - for (let i2 = 0; i2 < needle.lastPos; ++i2) { - if (needle.value[i2] !== haystack.readUInt8(pos + i2)) { - return false; - } - } - return true; - }; - exports2.all = function(haystack, needle, start) { - needle = exports2.compile(needle); - start = start ?? 0; - const matches = []; - for (let i2 = start; i2 !== -1 && i2 < haystack.length; ) { - i2 = exports2.horspool(haystack, needle, i2); - if (i2 !== -1) { - matches.push(i2); - i2 += needle.length; - } - } - return matches; - }; - internals._indexOf = function(haystack, needle) { - Hoek.assert(haystack, "Missing haystack"); - for (let i2 = 0; i2 <= haystack.length - needle.length; ++i2) { - if (haystack.startsWith(needle.value, i2)) { - return i2; - } - } - return -1; - }; - exports2.Stream = class extends Stream.Writable { - constructor(needle) { - super(); - this.needle(needle); - this._haystack = new Vise(); - this._indexOf = this._needle.length > 2 ? exports2.horspool : internals._indexOf; - this.on("finish", () => { - const chunks = this._haystack.chunks(); - for (let i2 = 0; i2 < chunks.length; ++i2) { - this.emit("haystack", chunks[i2]); - } - }); - } - needle(needle) { - this._needle = exports2.compile(needle); - } - _write(chunk, encoding, next) { - this._haystack.push(chunk); - let match = this._indexOf(this._haystack, this._needle); - if (match === -1 && chunk.length >= this._needle.length) { - this._flush(this._haystack.length - chunk.length); - } - while (match !== -1) { - this._flush(match); - this._haystack.shift(this._needle.length); - this.emit("needle"); - match = this._indexOf(this._haystack, this._needle); - } - if (this._haystack.length) { - const notChecked = this._haystack.length - this._needle.length + 1; - let i2 = notChecked; - for (; i2 < this._haystack.length; ++i2) { - if (this._haystack.startsWith(this._needle.value, i2, this._haystack.length - i2)) { - break; - } - } - this._flush(i2); - } - return next(); - } - _flush(pos) { - const chunks = this._haystack.shift(pos); - for (let i2 = 0; i2 < chunks.length; ++i2) { - this.emit("haystack", chunks[i2]); - } - } - flush() { - const chunks = this._haystack.shift(this._haystack.length); - for (let i2 = 0; i2 < chunks.length; ++i2) { - this.emit("haystack", chunks[i2]); - } - } - }; - } -}); -var require_lib29 = __commonJS({ - "node_modules/.deno/@hapi+pez@6.1.0/node_modules/@hapi/pez/lib/index.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var B64 = require_lib22(); - var Boom5 = require_lib2(); - var Content = require_lib25(); - var Hoek = require_lib(); - var Nigel = require_lib28(); - var internals = {}; - internals.state = { - preamble: 0, - // Until the first boundary is received - boundary: 1, - // After a boundary, waiting for first line with optional linear-whitespace - header: 2, - // Receiving part headers - payload: 3, - // Receiving part payload - epilogue: 4 - }; - internals.defaults = { - maxBytes: Infinity, - maxParts: Infinity - }; - exports2.Dispenser = class extends Stream.Writable { - constructor(options2) { - super({ autoDestroy: false }); - Hoek.assert(options2 !== null && typeof options2 === "object", "options must be an object"); - const settings = Hoek.applyToDefaults(internals.defaults, options2); - this._boundary = settings.boundary; - this._state = internals.state.preamble; - this._held = ""; - this._stream = null; - this._headers = {}; - this._name = ""; - this._pendingHeader = ""; - this._error = null; - this._bytesCount = 0; - this._partsCount = 0; - this._maxBytes = settings.maxBytes; - this._maxParts = settings.maxParts; - this._parts = new Nigel.Stream(Buffer.from("--" + settings.boundary)); - this._lines = new Nigel.Stream(Buffer.from("\r\n")); - this._parts.on("needle", () => this.#onPartEnd()); - this._parts.on("haystack", (chunk) => this.#onPart(chunk)); - this._lines.on("needle", () => this.#onLineEnd()); - this._lines.on("haystack", (chunk) => this.#onLine(chunk)); - this.once("finish", () => this._parts.end()); - this._parts.once("close", () => this._lines.end()); - let piper = null; - let finish = (err) => { - if (piper) { - piper.removeListener("data", onReqData); - piper.removeListener("error", finish); - piper.removeListener("aborted", onReqAborted); - } - if (err) { - return this.#abort(err); - } - this.#emit("close"); - }; - finish = Hoek.once(finish); - this._lines.once("close", () => { - if (this._state === internals.state.epilogue) { - if (this._held) { - this.#emit("epilogue", this._held); - this._held = ""; - } - } else if (this._state === internals.state.boundary) { - if (!this._held) { - this.#abort(Boom5.badRequest("Missing end boundary")); - } else if (this._held !== "--") { - this.#abort(Boom5.badRequest("Only white space allowed after boundary at end")); - } - } else { - this.#abort(Boom5.badRequest("Incomplete multipart payload")); - } - setImmediate(finish); - }); - const onReqAborted = () => { - finish(Boom5.badRequest("Client request aborted")); - }; - const onReqData = (data) => { - this._bytesCount += Buffer.byteLength(data); - if (this._bytesCount > this._maxBytes) { - finish(Boom5.entityTooLarge("Maximum size exceeded")); - } - }; - this.once("pipe", (req) => { - piper = req; - req.on("data", onReqData); - req.once("error", finish); - req.once("aborted", onReqAborted); - }); - } - _write(buffer, encoding, next) { - if (this._error) { - return next(); - } - this._parts.write(buffer); - return next(); - } - #emit(...args) { - if (this._error) { - return; - } - this.emit(...args); - } - #abort(err) { - this.#emit("error", err); - this._error = err; - } - #onPartEnd() { - this._lines.flush(); - if (this._state === internals.state.preamble) { - if (this._held) { - const last = this._held.length - 1; - if (this._held[last] !== "\n" || this._held[last - 1] !== "\r") { - return this.#abort(Boom5.badRequest("Preamble missing CRLF terminator")); - } - this.#emit("preamble", this._held.slice(0, -2)); - this._held = ""; - } - this._parts.needle(Buffer.from("\r\n--" + this._boundary)); - } else { - this._partsCount++; - if (this._partsCount > this._maxParts) { - return this.#abort(Boom5.badRequest("Maximum parts exceeded")); - } - } - this._state = internals.state.boundary; - if (this._stream) { - this._stream.end(); - this._stream = null; - } else if (this._name) { - this.#emit("field", this._name, this._held); - this._name = ""; - this._held = ""; - } - } - #onPart(chunk) { - if (this._state === internals.state.preamble) { - this._held = this._held + chunk.toString(); - } else if (this._state === internals.state.payload) { - if (this._stream) { - this._stream.write(chunk); - } else { - this._held = this._held + chunk.toString(); - } - } else { - this._lines.write(chunk); - } - } - #onLineEnd() { - if (this._state === internals.state.boundary) { - if (this._held) { - this._held = this._held.replace(/[\t ]/g, ""); - if (this._held) { - if (this._held === "--") { - this._state = internals.state.epilogue; - this._held = ""; - return; - } - return this.#abort(Boom5.badRequest("Only white space allowed after boundary")); - } - } - this._state = internals.state.header; - return; - } - if (this._state === internals.state.header) { - if (this._held) { - if (this._held[0] === " " || this._held[0] === " ") { - if (!this._pendingHeader) { - return this.#abort(Boom5.badRequest("Invalid header continuation without valid declaration on previous line")); - } - this._pendingHeader = this._pendingHeader + " " + this._held.slice(1); - this._held = ""; - return; - } - this.#flushHeader(); - this._pendingHeader = this._held; - this._held = ""; - return; - } - this.#flushHeader(); - this._state = internals.state.payload; - let disposition; - try { - disposition = Content.disposition(this._headers["content-disposition"]); - } catch (err) { - return this.#abort(err); - } - if (disposition.filename !== void 0) { - const stream = new Stream.PassThrough(); - const transferEncoding = this._headers["content-transfer-encoding"]; - if (transferEncoding && transferEncoding.toLowerCase() === "base64") { - this._stream = new B64.Decoder(); - this._stream.pipe(stream); - } else { - this._stream = stream; - } - stream.name = disposition.name; - stream.filename = disposition.filename; - stream.headers = this._headers; - this._headers = {}; - this.#emit("part", stream); - } else { - this._name = disposition.name; - } - this._lines.flush(); - return; - } - this._held = this._held + "\r\n"; - } - #onLine(chunk) { - if (this._stream) { - this._stream.write(chunk); - } else { - this._held = this._held + chunk.toString(); - } - } - #flushHeader() { - if (!this._pendingHeader) { - return; - } - const sep = this._pendingHeader.indexOf(":"); - if (sep === -1) { - return this.#abort(Boom5.badRequest("Invalid header missing colon separator")); - } - if (!sep) { - return this.#abort(Boom5.badRequest("Invalid header missing field name")); - } - const name = this._pendingHeader.slice(0, sep).toLowerCase(); - if (name === "__proto__") { - return this.#abort(Boom5.badRequest("Invalid header")); - } - this._headers[name] = this._pendingHeader.slice(sep + 1).trim(); - this._pendingHeader = ""; - } - }; - } -}); -var require_payload = __commonJS({ - "node_modules/.deno/@hapi+wreck@18.1.0/node_modules/@hapi/wreck/lib/payload.js"(exports2, module14) { - "use strict"; - var Stream = __require2("stream"); - var internals = {}; - module14.exports = internals.Payload = class extends Stream.Readable { - constructor(payload, encoding) { - super(); - const data = [].concat(payload || ""); - let size = 0; - for (let i2 = 0; i2 < data.length; ++i2) { - const chunk = data[i2]; - size = size + chunk.length; - data[i2] = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); - } - this._data = Buffer.concat(data, size); - this._position = 0; - this._encoding = encoding || "utf8"; - } - _read(size) { - const chunk = this._data.slice(this._position, this._position + size); - this.push(chunk, this._encoding); - this._position = this._position + chunk.length; - if (this._position >= this._data.length) { - this.push(null); - } - } - }; - } -}); -var require_recorder = __commonJS({ - "node_modules/.deno/@hapi+wreck@18.1.0/node_modules/@hapi/wreck/lib/recorder.js"(exports2, module14) { - "use strict"; - var Stream = __require2("stream"); - var Boom5 = require_lib2(); - var internals = {}; - module14.exports = internals.Recorder = class extends Stream.Writable { - constructor(options2) { - super(); - this.settings = options2; - this.buffers = []; - this.length = 0; - } - _write(chunk, encoding, next) { - if (this.settings.maxBytes && this.length + chunk.length > this.settings.maxBytes) { - return this.emit("error", Boom5.entityTooLarge("Payload content length greater than maximum allowed: " + this.settings.maxBytes)); - } - this.length = this.length + chunk.length; - this.buffers.push(chunk); - next(); - } - collect() { - const buffer = this.buffers.length === 0 ? Buffer.alloc(0) : this.buffers.length === 1 ? this.buffers[0] : Buffer.concat(this.buffers, this.length); - return buffer; - } - }; - } -}); -var require_tap = __commonJS({ - "node_modules/.deno/@hapi+wreck@18.1.0/node_modules/@hapi/wreck/lib/tap.js"(exports2, module14) { - "use strict"; - var Stream = __require2("stream"); - var Payload = require_payload(); - var internals = {}; - module14.exports = internals.Tap = class extends Stream.Transform { - constructor() { - super(); - this.buffers = []; - } - _transform(chunk, encoding, next) { - this.buffers.push(chunk); - next(null, chunk); - } - collect() { - return new Payload(this.buffers); - } - }; - } -}); -var require_lib30 = __commonJS({ - "node_modules/.deno/@hapi+wreck@18.1.0/node_modules/@hapi/wreck/lib/index.js"(exports2, module14) { - "use strict"; - var Events2 = __require2("events"); - var Http = __require2("http"); - var Https = __require2("https"); - var Stream = __require2("stream"); - var Url = __require2("url"); - var Zlib = __require2("zlib"); - var Boom5 = require_lib2(); - var Bourne = require_lib20(); - var Hoek = require_lib(); - var Payload = require_payload(); - var Recorder = require_recorder(); - var Tap = require_tap(); - var internals = { - jsonRegex: /^application\/([a-z0-9.]*[+-]json|json)$/, - shallowOptions: ["agent", "agents", "beforeRedirect", "payload", "redirected"], - httpOptions: ["secureProtocol", "ciphers", "lookup", "family", "hints"] - }; - internals.Client = class { - constructor(options2 = {}) { - Hoek.assert(!options2.agents || options2.agents.https && options2.agents.http && options2.agents.httpsAllowUnauthorized, 'Option agents must include "http", "https", and "httpsAllowUnauthorized"'); - this._defaults = Hoek.clone(options2, { shallow: internals.shallowOptions }); - this.agents = this._defaults.agents || { - https: new Https.Agent({ maxSockets: Infinity }), - http: new Http.Agent({ maxSockets: Infinity }), - httpsAllowUnauthorized: new Https.Agent({ maxSockets: Infinity, rejectUnauthorized: false }) - }; - if (this._defaults.events) { - this.events = new Events2.EventEmitter(); - } - } - defaults(options2) { - Hoek.assert(options2 && typeof options2 === "object", "options must be provided to defaults"); - options2 = Hoek.applyToDefaults(this._defaults, options2, { shallow: internals.shallowOptions }); - return new internals.Client(options2); - } - request(method, url2, options2 = {}) { - try { - options2 = Hoek.applyToDefaults(this._defaults, options2, { shallow: internals.shallowOptions }); - Hoek.assert(options2.payload === void 0 || typeof options2.payload === "string" || typeof options2.payload === "object", "options.payload must be a string, a Buffer, a Stream, or an Object"); - Hoek.assert(internals.isNullOrUndefined(options2.agent) || typeof options2.rejectUnauthorized !== "boolean", "options.agent cannot be set to an Agent at the same time as options.rejectUnauthorized is set"); - Hoek.assert(internals.isNullOrUndefined(options2.beforeRedirect) || typeof options2.beforeRedirect === "function", "options.beforeRedirect must be a function"); - Hoek.assert(internals.isNullOrUndefined(options2.redirected) || typeof options2.redirected === "function", "options.redirected must be a function"); - Hoek.assert(options2.gunzip === void 0 || typeof options2.gunzip === "boolean" || options2.gunzip === "force", 'options.gunzip must be a boolean or "force"'); - } catch (err) { - return Promise.reject(err); - } - if (options2.baseUrl) { - url2 = internals.resolveUrl(options2.baseUrl, url2); - delete options2.baseUrl; - } - const relay = {}; - const req = this._request(method, url2, options2, relay); - const promise = new Promise((resolve82, reject) => { - relay.callback = (err, res) => { - if (err) { - reject(err); - return; - } - resolve82(res); - return; - }; - }); - promise.req = req; - return promise; - } - _request(method, url2, options2, relay, _trace) { - const uri = {}; - if (options2.socketPath) { - uri.socketPath = options2.socketPath; - const parsedUri = new Url.URL(url2, `unix://${options2.socketPath}`); - internals.applyUrlToOptions(uri, { - host: "", - // host must be empty according to https://tools.ietf.org/html/rfc2616#section-14.23 - protocol: "http:", - hash: parsedUri.hash, - search: parsedUri.search, - searchParams: parsedUri.searchParams, - pathname: parsedUri.pathname, - href: parsedUri.href - }); - } else { - uri.setHost = false; - const parsedUri = new Url.URL(url2); - internals.applyUrlToOptions(uri, parsedUri); - } - uri.method = method.toUpperCase(); - uri.headers = /* @__PURE__ */ Object.create(null); - const usedHeaders = /* @__PURE__ */ new Set(); - if (options2.headers) { - for (const [key, value] of Object.entries(options2.headers)) { - if (value !== void 0) { - uri.headers[key] = value; - usedHeaders.add(key.toLowerCase()); - } - } - } - if (!usedHeaders.has("host")) { - uri.headers.host = uri.host; - } - if (options2.payload && typeof options2.payload === "object" && !(options2.payload instanceof Stream) && !Buffer.isBuffer(options2.payload)) { - options2.payload = JSON.stringify(options2.payload); - if (!usedHeaders.has("content-type")) { - uri.headers["content-type"] = "application/json"; - } - } - if (options2.gunzip && !usedHeaders.has("accept-encoding")) { - uri.headers["accept-encoding"] = "gzip"; - } - const payloadSupported = uri.method !== "GET" && uri.method !== "HEAD" && !internals.isNullOrUndefined(options2.payload); - if (payloadSupported && (typeof options2.payload === "string" || Buffer.isBuffer(options2.payload)) && !usedHeaders.has("content-length")) { - uri.headers["content-length"] = Buffer.isBuffer(options2.payload) ? options2.payload.length : Buffer.byteLength(options2.payload); - } - let redirects = options2.hasOwnProperty("redirects") ? options2.redirects : false; - _trace = _trace ?? []; - _trace.push({ method: uri.method, url: url2 }); - const client = uri.protocol === "https:" ? Https : Http; - for (const option of internals.httpOptions) { - if (options2[option] !== void 0) { - uri[option] = options2[option]; - } - } - if (options2.rejectUnauthorized !== void 0 && uri.protocol === "https:") { - uri.agent = options2.rejectUnauthorized ? this.agents.https : this.agents.httpsAllowUnauthorized; - } else if (options2.agent || options2.agent === false) { - uri.agent = options2.agent; - } else { - uri.agent = uri.protocol === "https:" ? this.agents.https : this.agents.http; - } - this._emit("preRequest", uri, options2); - const start = Date.now(); - const req = client.request(uri); - this._emit("request", req); - let shadow = null; - let timeoutId; - const onError = (err) => { - err.trace = _trace; - return finishOnce(Boom5.badGateway("Client request error", err)); - }; - const onAbort = () => { - if (!req.socket) { - const error2 = new Error("socket hang up"); - error2.code = "ECONNRESET"; - finishOnce(error2); - } - }; - req.once("error", onError); - const onResponse = (res) => { - const statusCode = res.statusCode; - const redirectMethod = internals.redirectMethod(statusCode, uri.method, options2); - if (redirects === false || !redirectMethod) { - return finishOnce(null, res); - } - res.destroy(); - if (redirects === 0) { - return finishOnce(Boom5.badGateway("Maximum redirections reached", _trace)); - } - let location = res.headers.location; - if (!location) { - return finishOnce(Boom5.badGateway("Received redirection without location", _trace)); - } - if (!/^https?:/i.test(location)) { - location = Url.resolve(uri.href, location); - } - const redirectOptions = Hoek.clone(options2, { shallow: internals.shallowOptions }); - redirectOptions.payload = shadow ?? options2.payload; - redirectOptions.redirects = --redirects; - if (timeoutId) { - clearTimeout(timeoutId); - const elapsed = Date.now() - start; - redirectOptions.timeout = (redirectOptions.timeout - elapsed).toString(); - } - if (redirectOptions.headers) { - const parsedLocation = new URL(location); - if (uri.hostname !== parsedLocation.hostname) { - for (const header of Object.keys(redirectOptions.headers)) { - const lowerHeader = header.toLowerCase(); - if (lowerHeader === "authorization" || lowerHeader === "cookie") { - delete redirectOptions.headers[header]; - } - } - } - } - const followRedirect = (err) => { - if (err) { - err.trace = _trace; - return finishOnce(Boom5.badGateway("Invalid redirect", err)); - } - const redirectReq = this._request(redirectMethod, location, redirectOptions, { callback: finishOnce }, _trace); - if (options2.redirected) { - options2.redirected(statusCode, location, redirectReq); - } - }; - if (!options2.beforeRedirect) { - return followRedirect(); - } - return options2.beforeRedirect(redirectMethod, statusCode, location, res.headers, redirectOptions, followRedirect); - }; - const finish = (err, res) => { - if (err) { - req.abort(); - } - req.removeListener("response", onResponse); - req.removeListener("error", onError); - req.removeListener("abort", onAbort); - req.on("error", Hoek.ignore); - clearTimeout(timeoutId); - this._emit("response", err, { req, res, start, uri }); - return relay.callback(err, res); - }; - const finishOnce = Hoek.once(finish); - req.once("response", onResponse); - if (options2.timeout) { - timeoutId = setTimeout(() => finishOnce(Boom5.gatewayTimeout("Client request timeout")), options2.timeout); - } - req.on("abort", onAbort); - if (payloadSupported) { - if (options2.payload instanceof Stream) { - let stream = options2.payload; - if (redirects) { - const collector = new Tap(); - collector.once("finish", () => { - shadow = collector.collect(); - }); - stream = options2.payload.pipe(collector); - } - internals.deferPipeUntilSocketConnects(req, stream); - return req; - } - req.write(options2.payload); - } - req.end(); - return req; - } - _emit(...args) { - if (this.events) { - this.events.emit(...args); - } - } - read(res, options2 = {}) { - return new Promise((resolve82, reject) => { - this._read(res, options2, (err, payload) => { - if (err) { - reject(err); - return; - } - resolve82(payload); - return; - }); - }); - } - _read(res, options2, callback) { - options2 = Hoek.applyToDefaults(this._defaults, options2, { shallow: internals.shallowOptions }); - let clientTimeoutId = null; - const finish = (err, buffer) => { - clearTimeout(clientTimeoutId); - reader.removeListener("error", onReaderError); - reader.removeListener("finish", onReaderFinish); - res.removeListener("error", onResError); - res.removeListener("close", onResAborted); - res.removeListener("aborted", onResAborted); - res.on("error", Hoek.ignore); - if (err) { - return callback(err); - } - if (!options2.json) { - return callback(null, buffer); - } - if (options2.json === "force") { - return internals.tryParseBuffer(buffer, callback); - } - const contentType = res.headers?.["content-type"] ?? ""; - const mime = contentType.split(";")[0].trim().toLowerCase(); - if (!internals.jsonRegex.test(mime)) { - if (options2.json === "strict") { - return callback(Boom5.notAcceptable("The content-type is not JSON compatible")); - } - return callback(null, buffer); - } - return internals.tryParseBuffer(buffer, callback); - }; - const finishOnce = Hoek.once(finish); - const clientTimeout = options2.timeout; - if (clientTimeout && clientTimeout > 0) { - clientTimeoutId = setTimeout(() => finishOnce(Boom5.clientTimeout()), clientTimeout); - } - const onResError = (err) => { - return finishOnce(err.isBoom ? err : Boom5.internal("Payload stream error", err)); - }; - const onResAborted = () => { - if (!res.complete) { - finishOnce(Boom5.internal("Payload stream closed prematurely")); - } - }; - res.once("error", onResError); - res.once("close", onResAborted); - res.once("aborted", onResAborted); - const reader = new Recorder({ maxBytes: options2.maxBytes }); - const onReaderError = (err) => { - if (res.destroy) { - res.destroy(); - } - return finishOnce(err); - }; - reader.once("error", onReaderError); - const onReaderFinish = () => { - return finishOnce(null, reader.collect()); - }; - reader.once("finish", onReaderFinish); - if (options2.gunzip) { - const contentEncoding = options2.gunzip === "force" ? "gzip" : res.headers?.["content-encoding"] ?? ""; - if (/^(x-)?gzip(\s*,\s*identity)?$/.test(contentEncoding)) { - const gunzip = Zlib.createGunzip(); - gunzip.once("error", onReaderError); - res.pipe(gunzip).pipe(reader); - return; - } - } - res.pipe(reader); - } - toReadableStream(payload, encoding) { - return new Payload(payload, encoding); - } - parseCacheControl(field) { - const regex = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g; - const header = {}; - const error2 = field.replace(regex, ($0, $1, $2, $3) => { - const value = $2 || $3; - header[$1] = value ? value.toLowerCase() : true; - return ""; - }); - if (header["max-age"]) { - try { - const maxAge2 = parseInt(header["max-age"], 10); - if (isNaN(maxAge2)) { - return null; - } - header["max-age"] = maxAge2; - } catch (err) { - } - } - return error2 ? null : header; - } - // Shortcuts - get(uri, options2) { - return this._shortcut("GET", uri, options2); - } - post(uri, options2) { - return this._shortcut("POST", uri, options2); - } - patch(uri, options2) { - return this._shortcut("PATCH", uri, options2); - } - put(uri, options2) { - return this._shortcut("PUT", uri, options2); - } - delete(uri, options2) { - return this._shortcut("DELETE", uri, options2); - } - async _shortcut(method, uri, options2 = {}) { - const res = await this.request(method, uri, options2); - let payload; - try { - payload = await this.read(res, options2); - } catch (err) { - err.data = err.data ?? {}; - err.data.res = res; - throw err; - } - if (res.statusCode < 400) { - return { res, payload }; - } - const data = { - isResponseError: true, - headers: res.headers, - res, - payload - }; - throw new Boom5.Boom(`Response Error: ${res.statusCode} ${res.statusMessage}`, { statusCode: res.statusCode, data }); - } - }; - internals.resolveUrl = function(baseUrl, path8) { - if (!path8) { - return baseUrl; - } - const url2 = new Url.URL(path8, baseUrl); - return Url.format(url2); - }; - internals.deferPipeUntilSocketConnects = function(req, stream) { - const onSocket = (socket) => { - if (!socket.connecting) { - return onSocketConnect(); - } - socket.once("connect", onSocketConnect); - }; - const onSocketConnect = () => { - stream.pipe(req); - stream.removeListener("error", onStreamError); - }; - const onStreamError = (err) => { - req.emit("error", err); - }; - req.once("socket", onSocket); - stream.on("error", onStreamError); - }; - internals.redirectMethod = function(code2, method, options2) { - switch (code2) { - case 301: - case 302: - return options2.redirectMethod || method; - case 303: - if (options2.redirect303) { - return "GET"; - } - break; - case 307: - case 308: - return method; - } - return null; - }; - internals.tryParseBuffer = function(buffer, next) { - if (buffer.length === 0) { - return next(null, null); - } - let payload; - try { - payload = Bourne.parse(buffer.toString()); - } catch (err) { - return next(Boom5.badGateway(err.message, { payload: buffer })); - } - return next(null, payload); - }; - internals.applyUrlToOptions = (options2, url2) => { - options2.host = url2.host; - options2.origin = url2.origin; - options2.searchParams = url2.searchParams; - options2.protocol = url2.protocol; - options2.hostname = typeof url2.hostname === "string" && url2.hostname.startsWith("[") ? url2.hostname.slice(1, -1) : url2.hostname; - options2.hash = url2.hash; - options2.search = url2.search; - options2.pathname = url2.pathname; - options2.path = `${url2.pathname}${url2.search}`; - options2.href = url2.href; - if (url2.port !== "") { - options2.port = Number(url2.port); - } - if (url2.username || url2.password) { - options2.auth = `${url2.username}:${url2.password}`; - options2.username = url2.username; - options2.password = url2.password; - } - return options2; - }; - internals.isNullOrUndefined = (val) => [null, void 0].includes(val); - module14.exports = new internals.Client(); - } -}); -var require_lib31 = __commonJS({ - "node_modules/.deno/@hapi+subtext@8.1.1/node_modules/@hapi/subtext/lib/index.js"(exports2) { - "use strict"; - var Fs = __require2("fs"); - var Fsp = __require2("fs/promises"); - var Os = __require2("os"); - var Querystring = __require2("querystring"); - var Stream = __require2("stream"); - var Zlib = __require2("zlib"); - var Boom5 = require_lib2(); - var Bourne = require_lib20(); - var Content = require_lib25(); - var File2 = require_lib26(); - var Hoek = require_lib(); - var Pez = require_lib29(); - var Wreck = require_lib30(); - var internals = { - kSubtext: Symbol("subtext"), - decoders: { - gzip: (options2) => Zlib.createGunzip(options2), - deflate: (options2) => Zlib.createInflate(options2) - } - }; - exports2.parse = async function(req, tap, options2) { - Hoek.assert(options2, "Missing options"); - Hoek.assert(options2.parse !== void 0, "Missing parse option setting"); - Hoek.assert(options2.output !== void 0, "Missing output option setting"); - const contentLength = req.headers["content-length"]; - if (options2.maxBytes !== void 0 && contentLength && parseInt(contentLength, 10) > options2.maxBytes) { - throw Boom5.entityTooLarge("Payload content length greater than maximum allowed: " + options2.maxBytes); - } - const contentType = Content.type(options2.override || req.headers["content-type"] || options2.defaultContentType || "application/octet-stream"); - try { - if (options2.allow && options2.allow.indexOf(contentType.mime) === -1) { - throw Boom5.unsupportedMediaType(); - } - const parsed = { mime: contentType.mime }; - if (options2.parse === true) { - parsed.payload = await internals.parse(req, tap, options2, contentType); - return parsed; - } - parsed.payload = await internals.raw(req, tap, options2); - return parsed; - } catch (err) { - err.mime = contentType.mime; - throw err; - } - }; - internals.parse = async function(req, tap, options2, contentType) { - const output = options2.output; - let source = internals.decoder(req, options2); - if (tap) { - [source] = internals.pipe(source, tap); - } - if (contentType.mime === "multipart/form-data") { - if (options2.multipart === false) { - throw Boom5.unsupportedMediaType(); - } - return await internals.multipart(req, options2, source, contentType); - } - if (output === "stream") { - return source; - } - if (output === "file") { - const file = await internals.writeFile(req, options2, source); - return file.item; - } - const payload = await Wreck.read(source, { timeout: options2.timeout, maxBytes: options2.maxBytes }); - return internals.object(options2, payload, contentType.mime); - }; - internals.decoder = function(source, options2) { - const contentEncoding = source.headers["content-encoding"]; - const decoders = options2.decoders ?? internals.decoders; - if (!decoders.hasOwnProperty(contentEncoding)) { - return source; - } - const decoderOptions = options2.compression?.[contentEncoding] ?? null; - const stream = decoders[contentEncoding](decoderOptions); - const orig = stream.emit; - stream.emit = (event, ...args) => { - if (event === "error") { - args = [Boom5.badRequest("Invalid compressed payload", args[0])]; - } - return orig.call(stream, event, ...args); - }; - [source] = internals.pipe(source, stream); - return source; - }; - internals.raw = async function(req, tap, options2) { - const output = options2.output; - let source = req; - if (options2.parse === "gunzip") { - source = internals.decoder(source, options2); - } - if (tap) { - [source] = internals.pipe(source, tap); - } - if (output === "stream") { - return source; - } - if (output === "file") { - const file = await internals.writeFile(req, options2, source); - return file.item; - } - return await Wreck.read(source, { timeout: options2.timeout, maxBytes: options2.maxBytes }); - }; - internals.object = function(options2, payload, mime) { - if (mime === "application/octet-stream") { - return payload.length ? payload : null; - } - if (mime.match(/^text\/.+$/)) { - return payload.toString("utf8"); - } - if (/^application\/(?:.+\+)?json$/.test(mime)) { - if (!payload.length) { - return null; - } - try { - return Bourne.parse(payload.toString("utf8"), { protoAction: options2.protoAction }); - } catch (err) { - const error3 = Boom5.badRequest("Invalid request payload JSON format", err); - error3.raw = payload; - throw error3; - } - } - if (mime === "application/x-www-form-urlencoded") { - const parse52 = options2.querystring ?? Querystring.parse; - return payload.length ? parse52(payload.toString("utf8")) : {}; - } - const error2 = Boom5.unsupportedMediaType(); - error2.raw = payload; - throw error2; - }; - internals.multipart = function(req, options2, source, contentType) { - return new Promise((resolve82, reject) => { - const clientTimeout = options2.timeout; - const clientTimeoutId = clientTimeout ? setTimeout(() => reject(Boom5.clientTimeout()), clientTimeout) : null; - const dispenserOptions = Hoek.applyToDefaults(contentType, { - maxBytes: options2.maxBytes, - maxParts: options2.maxParts - }); - const dispenser = new Pez.Dispenser(dispenserOptions); - const data = {}; - const pendingFiles = []; - const onError = (err) => { - const cleanup = internals.cleanupFiles(pendingFiles); - cleanup.catch(Hoek.ignore); - reject(Boom5.badRequest("Invalid multipart payload format", err)); - }; - dispenser.once("error", onError); - const set = (name, value) => { - if (!data.hasOwnProperty(name)) { - data[name] = value; - } else if (Array.isArray(data[name])) { - data[name].push(value); - } else { - data[name] = [data[name], value]; - } - }; - const finalize = async () => { - clearTimeout(clientTimeoutId); - dispenser.removeListener("error", onError); - dispenser.removeListener("part", onPart); - dispenser.removeListener("field", onField); - dispenser.removeListener("close", onClose); - try { - const files = await Promise.all(pendingFiles); - for (const { item, name } of files) { - set(name, item); - } - } catch (err) { - reject(err); - return; - } - resolve82(data); - }; - const output = typeof options2.multipart === "object" ? options2.multipart.output : options2.output; - const onPart = (part) => { - if (output === "file") { - pendingFiles.push(internals.writeFile(req, options2, part)); - } else { - internals.part(part, output, set, options2); - } - }; - dispenser.on("part", onPart); - const onField = (name, value) => set(name, value); - dispenser.on("field", onField); - const onClose = () => finalize(); - dispenser.once("close", onClose); - source.pipe(dispenser); - }); - }; - internals.writeFile = function(req, options2, stream) { - const promise = new Promise((resolve82, reject) => { - const path8 = File2.uniqueFilename(options2.uploads ?? Os.tmpdir()); - const file = Fs.createWriteStream(path8, { flags: "wx" }); - const counter = new internals.Counter(options2); - const finalize = (err) => { - req.removeListener("aborted", onAbort); - file.removeListener("close", finalize); - file.removeListener("error", finalize); - if (err) { - unpipeStreamToCounter(); - unpipeCounterToFile(); - file.close(); - Fs.unlink(path8, () => reject(err)); - return; - } - const result = { - item: { - path: path8, - bytes: counter.bytes - } - }; - if (stream.name) { - result.name = stream.name; - result.item.filename = stream.filename; - result.item.headers = stream.headers; - } - resolve82(result); - }; - file.once("close", finalize); - file.once("error", finalize); - const onAbort = () => finalize(Boom5.badRequest("Client connection aborted")); - req.once("aborted", onAbort); - const [, unpipeStreamToCounter] = internals.pipe(stream, counter); - const [, unpipeCounterToFile] = internals.pipe(counter, file); - }); - promise.catch(Hoek.ignore); - return promise; - }; - internals.cleanupFiles = async (pendingFiles) => { - const results = await Promise.allSettled(pendingFiles); - await Promise.all(results.map(async (result) => { - if (result.value) { - await Fsp.unlink(result.value.item.path); - } - })); - }; - internals.part = async function(part, output, set, options2) { - const payload = await Wreck.read(part); - if (output === "stream") { - const item = Wreck.toReadableStream(payload); - item.hapi = { - filename: part.filename, - headers: part.headers - }; - return set(part.name, item); - } - const ct = part.headers["content-type"] || ""; - const mime = ct.split(";")[0].trim().toLowerCase(); - const annotate = (value) => set(part.name, output === "annotated" ? { filename: part.filename, headers: part.headers, payload: value } : value); - if (!mime) { - return annotate(payload); - } - if (!payload.length) { - return annotate({}); - } - try { - const object2 = internals.object(options2, payload, mime); - annotate(object2); - } catch (err) { - annotate(payload); - } - }; - internals.pipe = function(from3, to) { - const forwardError = (err) => { - unpipe(); - to.emit("error", err); - }; - const unpipe = () => { - from3.removeListener("error", forwardError); - return from3.unpipe(to); - }; - from3.once("error", forwardError); - return [from3.pipe(to), unpipe]; - }; - internals.Counter = class extends Stream.Transform { - constructor(options2) { - super(); - this.bytes = 0; - this._maxBytes = options2.maxBytes; - } - _transform(chunk, encoding, next) { - this.bytes = this.bytes + chunk.length; - if (this._maxBytes !== void 0 && this.bytes > this._maxBytes) { - return next(Boom5.entityTooLarge("Payload content length greater than maximum allowed: " + this._maxBytes)); - } - return next(null, chunk); - } - }; - } -}); -var require_ext = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/ext.js"(exports2, module14) { - "use strict"; - var Hoek = require_lib(); - var Topo = require_lib8(); - var internals = {}; - exports2 = module14.exports = internals.Ext = class { - type = null; - nodes = null; - #core = null; - #routes = []; - #topo = new Topo.Sorter(); - constructor(type, core) { - this.#core = core; - this.type = type; - } - add(event) { - const methods = [].concat(event.method); - for (const method of methods) { - const settings = { - before: event.options.before, - after: event.options.after, - group: event.realm.plugin, - sort: this.#core.extensionsSeq++ - }; - const node = { - func: method, - // Request: function (request, h), Server: function (server) - bind: event.options.bind, - server: event.server, - // Server event - realm: event.realm, - timeout: event.options.timeout - }; - this.#topo.add(node, settings); - } - this.nodes = this.#topo.nodes; - for (const route2 of this.#routes) { - route2.rebuild(event); - } - } - merge(others) { - const merge3 = []; - for (const other of others) { - merge3.push(other.#topo); - } - this.#topo.merge(merge3); - this.nodes = this.#topo.nodes.length ? this.#topo.nodes : null; - } - subscribe(route2) { - this.#routes.push(route2); - } - static combine(route2, type) { - const ext = new internals.Ext(type, route2._core); - const events = route2.settings.ext[type]; - if (events) { - for (let event of events) { - event = Object.assign({}, event); - Hoek.assert(!event.options.sandbox, "Cannot specify sandbox option for route extension"); - event.realm = route2.realm; - ext.add(event); - } - } - const server = route2._core.extensions.route[type]; - const realm = route2.realm._extensions[type]; - ext.merge([server, realm]); - server.subscribe(route2); - realm.subscribe(route2); - return ext; - } - }; - } -}); -var require_handler = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/handler.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var internals = {}; - exports2.execute = async function(request) { - if (request._route._prerequisites) { - for (const set of request._route._prerequisites) { - const pres = []; - for (const item of set) { - pres.push(internals.handler(request, item.method, item)); - } - const responses = await Promise.all(pres); - for (const response of responses) { - if (response !== void 0) { - return response; - } - } - } - } - const result = await internals.handler(request, request.route.settings.handler); - if (result._takeover || typeof result === "symbol") { - return result; - } - request._setResponse(result); - }; - internals.handler = async function(request, method, pre) { - const bind = request.route.settings.bind; - const realm = request.route.realm; - let response = await request._core.toolkit.execute(method, request, { bind, realm, continue: "null" }); - if (!pre) { - if (response.isBoom) { - request._log(["handler", "error"], response); - throw response; - } - return response; - } - if (response.isBoom) { - response.assign = pre.assign; - response = await request._core.toolkit.failAction(request, pre.failAction, response, { tags: ["pre", "error"], retain: true }); - } - if (typeof response === "symbol") { - return response; - } - if (pre.assign) { - request.pre[pre.assign] = response.isBoom ? response : response.source; - request.preResponses[pre.assign] = response; - } - if (response._takeover) { - return response; - } - }; - exports2.defaults = function(method, handler, core) { - let defaults = null; - if (typeof handler === "object") { - const type = Object.keys(handler)[0]; - const serverHandler = core.decorations.handler.get(type); - Hoek.assert(serverHandler, "Unknown handler:", type); - if (serverHandler.defaults) { - defaults = typeof serverHandler.defaults === "function" ? serverHandler.defaults(method) : serverHandler.defaults; - } - } - return defaults ?? {}; - }; - exports2.configure = function(handler, route2) { - if (typeof handler === "object") { - const type = Object.keys(handler)[0]; - const serverHandler = route2._core.decorations.handler.get(type); - Hoek.assert(serverHandler, "Unknown handler:", type); - return serverHandler(route2.public, handler[type]); - } - return handler; - }; - exports2.prerequisitesConfig = function(config2) { - if (!config2) { - return null; - } - const prerequisites = []; - for (let pres of config2) { - pres = [].concat(pres); - const set = []; - for (let pre of pres) { - if (typeof pre !== "object") { - pre = { method: pre }; - } - const item = { - method: pre.method, - assign: pre.assign, - failAction: pre.failAction ?? "error" - }; - set.push(item); - } - prerequisites.push(set); - } - return prerequisites.length ? prerequisites : null; - }; - } -}); -var require_headers = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/headers.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var Boom5 = require_lib2(); - var internals = {}; - exports2.cache = function(response) { - const request = response.request; - if (response.headers["cache-control"]) { - return; - } - const settings = request.route.settings.cache; - const policy = settings && request._route._cache && (settings._statuses.has(response.statusCode) || response.statusCode === 304 && settings._statuses.has(200)); - if (policy || response.settings.ttl) { - const ttl = response.settings.ttl !== null ? response.settings.ttl : request._route._cache.ttl(); - const privacy = request.auth.isAuthenticated || response.headers["set-cookie"] ? "private" : settings.privacy ?? "default"; - response._header("cache-control", "max-age=" + Math.floor(ttl / 1e3) + ", must-revalidate" + (privacy !== "default" ? ", " + privacy : "")); - } else if (settings) { - response._header("cache-control", settings.otherwise); - } - }; - exports2.content = async function(response) { - const request = response.request; - if (response._isPayloadSupported() || request.method === "head") { - await response._marshal(); - if (typeof response._payload.size === "function") { - response._header("content-length", response._payload.size(), { override: false }); - } - if (!response._isPayloadSupported()) { - response._close(); - response._payload = new internals.Empty(); - } - exports2.type(response); - } else { - response._close(); - response._payload = new internals.Empty(); - delete response.headers["content-length"]; - } - }; - exports2.state = async function(response) { - const request = response.request; - const states = []; - for (const stateName in request._states) { - states.push(request._states[stateName]); - } - try { - for (const name in request._core.states.cookies) { - const autoValue = request._core.states.cookies[name].autoValue; - if (!autoValue || name in request._states || name in request.state) { - continue; - } - if (typeof autoValue !== "function") { - states.push({ name, value: autoValue }); - continue; - } - const value = await autoValue(request); - states.push({ name, value }); - } - if (!states.length) { - return; - } - let header = await request._core.states.format(states, request); - const existing = response.headers["set-cookie"]; - if (existing) { - header = (Array.isArray(existing) ? existing : [existing]).concat(header); - } - response._header("set-cookie", header); - } catch (err) { - const error2 = Boom5.boomify(err); - request._log(["state", "response", "error"], error2); - request._states = {}; - throw error2; - } - }; - exports2.type = function(response) { - const type = response.contentType; - if (type !== null && type !== response.headers["content-type"]) { - response.type(type); - } - }; - exports2.entity = function(response) { - const request = response.request; - if (!request._entity) { - return; - } - if (request._entity.etag && !response.headers.etag) { - response.etag(request._entity.etag, { vary: request._entity.vary }); - } - if (request._entity.modified && !response.headers["last-modified"]) { - response.header("last-modified", request._entity.modified); - } - }; - exports2.unmodified = function(response) { - const request = response.request; - if (response.statusCode === 304) { - return; - } - const entity = { - etag: response.headers.etag, - vary: response.settings.varyEtag, - modified: response.headers["last-modified"] - }; - const etag = request._core.Response.unmodified(request, entity); - if (etag) { - response.code(304); - if (etag !== true) { - response.headers.etag = etag; - } - } - }; - internals.Empty = class extends Stream.Readable { - _read() { - this.push(null); - } - writeToStream(stream) { - stream.end(); - } - }; - } -}); -var require_security = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/security.js"(exports2) { - "use strict"; - exports2.route = function(settings) { - if (!settings) { - return null; - } - const security = settings; - if (security.hsts) { - if (security.hsts === true) { - security._hsts = "max-age=15768000"; - } else if (typeof security.hsts === "number") { - security._hsts = "max-age=" + security.hsts; - } else { - security._hsts = "max-age=" + (security.hsts.maxAge ?? 15768e3); - if (security.hsts.includeSubdomains || security.hsts.includeSubDomains) { - security._hsts = security._hsts + "; includeSubDomains"; - } - if (security.hsts.preload) { - security._hsts = security._hsts + "; preload"; - } - } - } - if (security.xframe) { - if (security.xframe === true) { - security._xframe = "DENY"; - } else if (typeof security.xframe === "string") { - security._xframe = security.xframe.toUpperCase(); - } else if (security.xframe.rule === "allow-from") { - if (!security.xframe.source) { - security._xframe = "SAMEORIGIN"; - } else { - security._xframe = "ALLOW-FROM " + security.xframe.source; - } - } else { - security._xframe = security.xframe.rule.toUpperCase(); - } - } - return security; - }; - exports2.headers = function(response) { - const security = response.request.route.settings.security; - if (security._hsts) { - response._header("strict-transport-security", security._hsts, { override: false }); - } - if (security._xframe) { - response._header("x-frame-options", security._xframe, { override: false }); - } - if (security.xss === "enabled") { - response._header("x-xss-protection", "1; mode=block", { override: false }); - } else if (security.xss === "disabled") { - response._header("x-xss-protection", "0", { override: false }); - } - if (security.noOpen) { - response._header("x-download-options", "noopen", { override: false }); - } - if (security.noSniff) { - response._header("x-content-type-options", "nosniff", { override: false }); - } - if (security.referrer !== false) { - response._header("referrer-policy", security.referrer, { override: false }); - } - }; - } -}); -var require_streams = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/streams.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var Boom5 = require_lib2(); - var Teamwork = require_lib11(); - var internals = { - team: Symbol("team") - }; - exports2.isStream = function(stream) { - const isReadableStream = stream instanceof Stream.Readable; - if (!isReadableStream && typeof stream?.pipe === "function") { - throw Boom5.badImplementation("Cannot reply with a stream-like object that is not an instance of Stream.Readable"); - } - if (!isReadableStream) { - return false; - } - if (stream.readableObjectMode) { - throw Boom5.badImplementation("Cannot reply with stream in object mode"); - } - return true; - }; - exports2.drain = function(stream) { - const team = new Teamwork.Team(); - stream[internals.team] = team; - stream.on("readable", internals.read); - stream.on("error", internals.end); - stream.on("end", internals.end); - stream.on("close", internals.end); - return team.work; - }; - internals.read = function() { - while (this.read()) { - } - }; - internals.end = function() { - this.removeListener("readable", internals.read); - this.removeListener("error", internals.end); - this.removeListener("end", internals.end); - this.removeListener("close", internals.end); - this[internals.team].attend(); - }; - } -}); -var require_validation = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/validation.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Validate = require_lib9(); - var internals = {}; - exports2.validator = function(validator) { - Hoek.assert(validator, "Missing validator"); - Hoek.assert(typeof validator.compile === "function", "Invalid validator compile method"); - return validator; - }; - exports2.compile = function(rule, validator, realm, core) { - validator = validator ?? internals.validator(realm, core); - if (rule === false) { - return Validate.object({}).allow(null); - } - if (typeof rule === "function") { - return rule; - } - if (!rule || // false tested above - rule === true) { - return null; - } - if (typeof rule.validate === "function") { - return rule; - } - Hoek.assert(validator, "Cannot set uncompiled validation rules without configuring a validator"); - return validator.compile(rule); - }; - internals.validator = function(realm, core) { - while (realm) { - if (realm.validator) { - return realm.validator; - } - realm = realm.parent; - } - return core.validator; - }; - exports2.headers = function(request) { - return internals.input("headers", request); - }; - exports2.params = function(request) { - return internals.input("params", request); - }; - exports2.payload = function(request) { - if (request.method === "get" || request.method === "head") { - return; - } - return internals.input("payload", request); - }; - exports2.query = function(request) { - return internals.input("query", request); - }; - exports2.state = function(request) { - return internals.input("state", request); - }; - internals.input = async function(source, request) { - const localOptions = { - context: { - headers: request.headers, - params: request.params, - query: request.query, - payload: request.payload, - state: request.state, - auth: request.auth, - app: { - route: request.route.settings.app, - request: request.app - } - } - }; - delete localOptions.context[source]; - Hoek.merge(localOptions, request.route.settings.validate.options); - try { - const schema = request.route.settings.validate[source]; - const bind = request.route.settings.bind; - var value = await (typeof schema !== "function" ? internals.validate(request[source], schema, localOptions) : schema.call(bind, request[source], localOptions)); - return; - } catch (err) { - var validationError = err; - } finally { - request.orig[source] = request[source]; - if (value !== void 0) { - request[source] = value; - } - } - if (request.route.settings.validate.failAction === "ignore") { - return; - } - const defaultError = validationError.isBoom ? validationError : Boom5.badRequest(`Invalid request ${source} input`); - const detailedError = Boom5.boomify(validationError, { statusCode: 400, override: false, data: { defaultError } }); - detailedError.output.payload.validation = { source, keys: [] }; - if (validationError.details) { - for (const details of validationError.details) { - const path8 = details.path; - detailedError.output.payload.validation.keys.push(Hoek.escapeHtml(path8.join("."))); - } - } - if (request.route.settings.validate.errorFields) { - for (const field in request.route.settings.validate.errorFields) { - detailedError.output.payload[field] = request.route.settings.validate.errorFields[field]; - } - } - return request._core.toolkit.failAction(request, request.route.settings.validate.failAction, defaultError, { details: detailedError, tags: ["validation", "error", source] }); - }; - exports2.response = async function(request) { - if (request.route.settings.response.sample) { - const currentSample = Math.ceil(Math.random() * 100); - if (currentSample > request.route.settings.response.sample) { - return; - } - } - const response = request.response; - const statusCode = response.isBoom ? response.output.statusCode : response.statusCode; - const statusSchema = request.route.settings.response.status[statusCode]; - if (statusCode >= 400 && !statusSchema) { - return; - } - const schema = statusSchema !== void 0 ? statusSchema : request.route.settings.response.schema; - if (schema === null) { - return; - } - if (!response.isBoom && request.response.variety !== "plain") { - throw Boom5.badImplementation("Cannot validate non-object response"); - } - const localOptions = { - context: { - headers: request.headers, - params: request.params, - query: request.query, - payload: request.payload, - state: request.state, - auth: request.auth, - app: { - route: request.route.settings.app, - request: request.app - } - } - }; - const source = response.isBoom ? response.output.payload : response.source; - Hoek.merge(localOptions, request.route.settings.response.options); - try { - let value; - if (typeof schema !== "function") { - value = await internals.validate(source, schema, localOptions); - } else { - value = await schema(source, localOptions); - } - if (value !== void 0 && request.route.settings.response.modify) { - if (response.isBoom) { - response.output.payload = value; - } else { - response.source = value; - } - } - } catch (err) { - return request._core.toolkit.failAction(request, request.route.settings.response.failAction, err, { tags: ["validation", "response", "error"] }); - } - }; - internals.validate = function(value, schema, options2) { - if (typeof schema.validateAsync === "function") { - return schema.validateAsync(value, options2); - } - return schema.validate(value, options2); - }; - } -}); -var require_route2 = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/route.js"(exports2, module14) { - "use strict"; - var Assert = __require2("assert"); - var Bounce = require_lib12(); - var Catbox = require_lib16(); - var Hoek = require_lib(); - var Subtext = require_lib31(); - var Validate = require_lib9(); - var Auth = require_auth(); - var Config = require_config(); - var Cors = require_cors(); - var Ext = require_ext(); - var Handler = require_handler(); - var Headers2 = require_headers(); - var Security = require_security(); - var Streams = require_streams(); - var Validation = require_validation(); - var internals = {}; - exports2 = module14.exports = internals.Route = class { - constructor(route2, server, options2 = {}) { - const core = server._core; - const realm = server.realm; - Config.apply("route", route2, route2.method, route2.path); - const method = route2.method.toLowerCase(); - Hoek.assert(method !== "head", "Cannot set HEAD route:", route2.path); - const path8 = realm.modifiers.route.prefix ? realm.modifiers.route.prefix + (route2.path !== "/" ? route2.path : "") : route2.path; - Hoek.assert(path8 === "/" || path8[path8.length - 1] !== "/" || !core.settings.router.stripTrailingSlash, "Path cannot end with a trailing slash when configured to strip:", route2.method, route2.path); - const vhost = realm.modifiers.route.vhost ?? route2.vhost; - this.method = method; - this.path = path8; - let config2 = route2.options ?? route2.config ?? {}; - if (typeof config2 === "function") { - config2 = config2.call(realm.settings.bind, server); - } - config2 = Config.enable(config2); - this._assert(method !== "get" || !config2.payload, "Cannot set payload settings on HEAD or GET request"); - this._assert(method !== "get" || !config2.validate?.payload, "Cannot validate HEAD or GET request payload"); - this._assert(!route2.rules || !config2.rules, "Route rules can only appear once"); - const rules = route2.rules ?? config2.rules; - const rulesConfig = internals.rules(rules, { method, path: path8, vhost }, server); - delete config2.rules; - this._assert(route2.handler || config2.handler, "Missing or undefined handler"); - this._assert(!!route2.handler ^ !!config2.handler, "Handler must only appear once"); - const handler = Config.apply("handler", route2.handler ?? config2.handler); - delete config2.handler; - const handlerDefaults = Handler.defaults(method, handler, core); - const settings = internals.config([core.settings.routes, handlerDefaults, realm.settings, rulesConfig, config2]); - this.settings = Config.apply("routeConfig", settings, method, path8); - this._core = core; - this.realm = realm; - this.settings.vhost = vhost; - this.settings.plugins = this.settings.plugins ?? {}; - this.settings.app = this.settings.app ?? {}; - this._special = !!options2.special; - this._analysis = this._core.router.analyze(this.path); - this.params = this._analysis.params; - this.fingerprint = this._analysis.fingerprint; - this.public = { - method: this.method, - path: this.path, - vhost, - realm, - settings: this.settings, - fingerprint: this.fingerprint, - auth: { - access: (request) => Auth.testAccess(request, this.public) - } - }; - this._setupValidation(); - if (this.method === "get") { - this.settings.payload = null; - } else { - this.settings.payload.decoders = this._core.compression.decoders; - } - this._assert(!this.settings.validate.payload || this.settings.payload.parse, "Route payload must be set to 'parse' when payload validation enabled"); - this._assert(!this.settings.validate.state || this.settings.state.parse, "Route state must be set to 'parse' when state validation enabled"); - this.settings.auth = this._special ? false : this._core.auth._setupRoute(this.settings.auth, path8); - if (this.method === "get" && typeof this.settings.cache === "object" && (this.settings.cache.expiresIn || this.settings.cache.expiresAt)) { - this.settings.cache._statuses = new Set(this.settings.cache.statuses); - this._cache = new Catbox.Policy({ expiresIn: this.settings.cache.expiresIn, expiresAt: this.settings.cache.expiresAt }); - } - this.settings.cors = Cors.route(this.settings.cors); - this.settings.security = Security.route(this.settings.security); - this.settings.handler = Handler.configure(handler, this); - this._prerequisites = Handler.prerequisitesConfig(this.settings.pre); - this._extensions = { - onPreResponse: Ext.combine(this, "onPreResponse"), - onPostResponse: Ext.combine(this, "onPostResponse") - }; - if (this._special) { - this._cycle = [internals.drain, Handler.execute]; - this.rebuild(); - return; - } - this._extensions.onPreAuth = Ext.combine(this, "onPreAuth"); - this._extensions.onCredentials = Ext.combine(this, "onCredentials"); - this._extensions.onPostAuth = Ext.combine(this, "onPostAuth"); - this._extensions.onPreHandler = Ext.combine(this, "onPreHandler"); - this._extensions.onPostHandler = Ext.combine(this, "onPostHandler"); - this.rebuild(); - } - _setupValidation() { - const validation2 = this.settings.validate; - if (this.method === "get") { - validation2.payload = null; - } - this._assert(!validation2.params || this.params.length, "Cannot set path parameters validations without path parameters"); - for (const type of ["headers", "params", "query", "payload", "state"]) { - validation2[type] = Validation.compile(validation2[type], this.settings.validate.validator, this.realm, this._core); - } - if (this.settings.response.schema !== void 0 || this.settings.response.status) { - this.settings.response._validate = true; - const rule = this.settings.response.schema; - this.settings.response.status = this.settings.response.status ?? {}; - const statuses = Object.keys(this.settings.response.status); - if (rule === true && !statuses.length) { - this.settings.response._validate = false; - } else { - this.settings.response.schema = Validation.compile(rule, this.settings.validate.validator, this.realm, this._core); - for (const code2 of statuses) { - this.settings.response.status[code2] = Validation.compile(this.settings.response.status[code2], this.settings.validate.validator, this.realm, this._core); - } - } - } - } - rebuild(event) { - if (event) { - this._extensions[event.type].add(event); - } - if (this._special) { - this._postCycle = this._extensions.onPreResponse.nodes ? [this._extensions.onPreResponse] : []; - this._buildMarshalCycle(); - return; - } - this._cycle = []; - if (this.settings.state.parse) { - this._cycle.push(internals.state); - } - if (this._extensions.onPreAuth.nodes) { - this._cycle.push(this._extensions.onPreAuth); - } - if (this._core.auth._enabled(this, "authenticate")) { - this._cycle.push(Auth.authenticate); - } - if (this.method !== "get") { - this._cycle.push(internals.payload); - if (this._core.auth._enabled(this, "payload")) { - this._cycle.push(Auth.payload); - } - } - if (this._core.auth._enabled(this, "authenticate") && this._extensions.onCredentials.nodes) { - this._cycle.push(this._extensions.onCredentials); - } - if (this._core.auth._enabled(this, "access")) { - this._cycle.push(Auth.access); - } - if (this._extensions.onPostAuth.nodes) { - this._cycle.push(this._extensions.onPostAuth); - } - if (this.settings.validate.headers) { - this._cycle.push(Validation.headers); - } - if (this.settings.validate.params) { - this._cycle.push(Validation.params); - } - if (this.settings.validate.query) { - this._cycle.push(Validation.query); - } - if (this.settings.validate.payload) { - this._cycle.push(Validation.payload); - } - if (this.settings.validate.state) { - this._cycle.push(Validation.state); - } - if (this._extensions.onPreHandler.nodes) { - this._cycle.push(this._extensions.onPreHandler); - } - this._cycle.push(Handler.execute); - if (this._extensions.onPostHandler.nodes) { - this._cycle.push(this._extensions.onPostHandler); - } - this._postCycle = []; - if (this.settings.response._validate && this.settings.response.sample !== 0) { - this._postCycle.push(Validation.response); - } - if (this._extensions.onPreResponse.nodes) { - this._postCycle.push(this._extensions.onPreResponse); - } - this._buildMarshalCycle(); - } - _buildMarshalCycle() { - this._marshalCycle = [Headers2.type]; - if (this.settings.cors) { - this._marshalCycle.push(Cors.headers); - } - if (this.settings.security) { - this._marshalCycle.push(Security.headers); - } - this._marshalCycle.push(Headers2.entity); - if (this.method === "get" || this.method === "*") { - this._marshalCycle.push(Headers2.unmodified); - } - this._marshalCycle.push(Headers2.cache); - this._marshalCycle.push(Headers2.state); - this._marshalCycle.push(Headers2.content); - if (this._core.auth._enabled(this, "response")) { - this._marshalCycle.push(Auth.response); - } - } - _assert(condition, message) { - if (condition) { - return; - } - if (this.method[0] !== "_") { - message = `${message}: ${this.method.toUpperCase()} ${this.path}`; - } - throw new Assert.AssertionError({ - message, - actual: false, - expected: true, - operator: "==", - stackStartFunction: this._assert - }); - } - }; - internals.state = async function(request) { - request.state = {}; - const req = request.raw.req; - const cookies = req.headers.cookie; - if (!cookies) { - return; - } - try { - var result = await request._core.states.parse(cookies); - } catch (err) { - Bounce.rethrow(err, "system"); - var parseError = err; - } - const { states, failed = [] } = result ?? parseError; - request.state = states ?? {}; - for (const item of failed) { - if (item.settings.clearInvalid) { - request._clearState(item.name); - } - } - if (!parseError) { - return; - } - parseError.header = cookies; - return request._core.toolkit.failAction(request, request.route.settings.state.failAction, parseError, { tags: ["state", "error"] }); - }; - internals.payload = async function(request) { - if (request.method === "get" || request.method === "head") { - return; - } - if (request.payload !== void 0) { - return internals.drain(request); - } - if (request._expectContinue) { - request._expectContinue = false; - request.raw.res.writeContinue(); - } - try { - const { payload, mime } = await Subtext.parse(request.raw.req, request._tap(), request.route.settings.payload); - request._isPayloadPending = !!payload?._readableState; - request.mime = mime; - request.payload = payload; - } catch (err) { - Bounce.rethrow(err, "system"); - await internals.drain(request); - request.mime = err.mime; - request.payload = null; - return request._core.toolkit.failAction(request, request.route.settings.payload.failAction, err, { tags: ["payload", "error"] }); - } - }; - internals.drain = async function(request) { - if (request._expectContinue) { - request._isPayloadPending = false; - request._expectContinue = false; - } - if (request._isPayloadPending) { - await Streams.drain(request.raw.req); - request._isPayloadPending = false; - } - }; - internals.config = function(chain) { - if (!chain.length) { - return {}; - } - let config2 = chain[0]; - for (const item of chain) { - config2 = Hoek.applyToDefaults(config2, item, { shallow: ["bind", "validate.headers", "validate.payload", "validate.params", "validate.query", "validate.state"] }); - } - return config2; - }; - internals.rules = function(rules, info, server) { - const configs = []; - let realm = server.realm; - while (realm) { - if (realm._rules) { - const source = !realm._rules.settings.validate ? rules : Validate.attempt(rules, realm._rules.settings.validate.schema, realm._rules.settings.validate.options); - const config2 = realm._rules.processor(source, info); - if (config2) { - configs.unshift(config2); - } - } - realm = realm.parent; - } - return internals.config(configs); - }; - } -}); -var require_cors = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/cors.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Route = null; - var internals = {}; - exports2.route = function(options2) { - if (!options2) { - return false; - } - const settings = Hoek.clone(options2); - settings._headers = settings.headers.concat(settings.additionalHeaders); - settings._headersString = settings._headers.join(","); - for (let i2 = 0; i2 < settings._headers.length; ++i2) { - settings._headers[i2] = settings._headers[i2].toLowerCase(); - } - if (settings._headers.indexOf("origin") === -1) { - settings._headers.push("origin"); - } - settings._exposedHeaders = settings.exposedHeaders.concat(settings.additionalExposedHeaders).join(","); - if (settings.origin === "ignore") { - settings._origin = false; - } else if (settings.origin.indexOf("*") !== -1) { - Hoek.assert(settings.origin.length === 1, "Cannot specify cors.origin * together with other values"); - settings._origin = true; - } else { - settings._origin = { - qualified: [], - wildcards: [] - }; - for (const origin of settings.origin) { - if (origin.indexOf("*") !== -1) { - settings._origin.wildcards.push(new RegExp("^" + Hoek.escapeRegex(origin).replace(/\\\*/g, ".*").replace(/\\\?/g, ".") + "$")); - } else { - settings._origin.qualified.push(origin); - } - } - } - return settings; - }; - exports2.options = function(route2, server) { - if (route2.method === "options" || !route2.settings.cors) { - return; - } - exports2.handler(server); - }; - exports2.handler = function(server) { - Route = Route || require_route2(); - if (server._core.router.specials.options) { - return; - } - const definition = { - method: "_special", - path: "/{p*}", - handler: internals.handler, - options: { - cors: false - } - }; - const route2 = new Route(definition, server, { special: true }); - server._core.router.special("options", route2); - }; - internals.handler = function(request, h2) { - const method = request.headers["access-control-request-method"]; - if (!method) { - throw Boom5.notFound("CORS error: Missing Access-Control-Request-Method header"); - } - const route2 = request.server.match(method, request.path, request.info.hostname); - if (!route2) { - throw Boom5.notFound(); - } - const settings = route2.settings.cors; - if (!settings) { - return { message: "CORS is disabled for this route" }; - } - const origin = request.headers.origin; - if (!origin && settings._origin !== false) { - throw Boom5.notFound("CORS error: Missing Origin header"); - } - if (!exports2.matchOrigin(origin, settings)) { - return { message: "CORS error: Origin not allowed" }; - } - let headers = request.headers["access-control-request-headers"]; - if (headers) { - headers = headers.toLowerCase().split(/\s*,\s*/); - if (Hoek.intersect(headers, settings._headers).length !== headers.length) { - return { message: "CORS error: Some headers are not allowed" }; - } - } - const response = h2.response(); - response.code(settings.preflightStatusCode); - response._header("access-control-allow-origin", settings._origin ? origin : "*"); - response._header("access-control-allow-methods", method); - response._header("access-control-allow-headers", settings._headersString); - response._header("access-control-max-age", settings.maxAge); - if (settings.credentials) { - response._header("access-control-allow-credentials", "true"); - } - if (settings._exposedHeaders) { - response._header("access-control-expose-headers", settings._exposedHeaders); - } - return response; - }; - exports2.headers = function(response) { - const request = response.request; - const settings = request.route.settings.cors; - if (settings._origin !== false) { - response.vary("origin"); - } - if (request.info.cors && !request.info.cors.isOriginMatch || // After route lookup - !exports2.matchOrigin(request.headers.origin, request.route.settings.cors)) { - return; - } - response._header("access-control-allow-origin", settings._origin ? request.headers.origin : "*"); - if (settings.credentials) { - response._header("access-control-allow-credentials", "true"); - } - if (settings._exposedHeaders) { - response._header("access-control-expose-headers", settings._exposedHeaders, { append: true }); - } - }; - exports2.matchOrigin = function(origin, settings) { - if (settings._origin === true || settings._origin === false) { - return true; - } - if (!origin) { - return false; - } - if (settings._origin.qualified.indexOf(origin) !== -1) { - return true; - } - for (const wildcard of settings._origin.wildcards) { - if (origin.match(wildcard)) { - return true; - } - } - return false; - }; - } -}); -var require_toolkit = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/toolkit.js"(exports2) { - "use strict"; - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var internals = {}; - exports2.reserved = [ - "abandon", - "authenticated", - "close", - "context", - "continue", - "entity", - "redirect", - "realm", - "request", - "response", - "state", - "unauthenticated", - "unstate" - ]; - exports2.symbols = { - abandon: Symbol("abandon"), - close: Symbol("close"), - continue: Symbol("continue") - }; - exports2.Manager = class { - constructor() { - this._toolkit = internals.toolkit(); - } - async execute(method, request, options2) { - const h2 = new this._toolkit(request, options2); - const bind = options2.bind ?? null; - try { - let operation; - if (bind) { - operation = method.call(bind, request, h2); - } else if (options2.args) { - operation = method(request, h2, ...options2.args); - } else { - operation = method(request, h2); - } - var response = await exports2.timed(operation, options2); - } catch (err) { - if (Bounce.isSystem(err)) { - response = Boom5.badImplementation(err); - } else if (!Bounce.isError(err)) { - response = Boom5.badImplementation("Cannot throw non-error object", err); - } else { - response = Boom5.boomify(err); - } - } - if (options2.ignoreResponse) { - return response; - } - if (response === void 0) { - response = Boom5.badImplementation(`${method.name} method did not return a value, a promise, or throw an error`); - } - if (options2.continue && response === exports2.symbols.continue) { - if (options2.continue === "undefined") { - return; - } - response = null; - } - if (options2.auth && response instanceof internals.Auth) { - return response; - } - if (typeof response !== "symbol") { - response = request._core.Response.wrap(response, request); - if (!response.isBoom && response._state === "init") { - await response._prepare(); - } - } - return response; - } - decorate(name, method) { - this._toolkit.prototype[name] = method; - } - async failAction(request, failAction, err, options2) { - const retain = options2.retain ? err : void 0; - if (failAction === "ignore") { - return retain; - } - if (failAction === "log") { - request._log(options2.tags, err); - return retain; - } - if (failAction === "error") { - throw err; - } - return await this.execute(failAction, request, { realm: request.route.realm, args: [options2.details ?? err] }); - } - }; - exports2.timed = async function(method, options2) { - if (!options2.timeout) { - return method; - } - const timer2 = new Promise((resolve82, reject) => { - const handler = () => { - reject(Boom5.internal(`${options2.name} timed out`)); - }; - setTimeout(handler, options2.timeout); - }); - return await Promise.race([timer2, method]); - }; - internals.toolkit = function() { - const Toolkit = class { - constructor(request, options2) { - this.context = options2.bind; - this.realm = options2.realm; - this.request = request; - this._auth = options2.auth; - } - response(result) { - Hoek.assert(!result || typeof result !== "object" || typeof result.then !== "function", "Cannot wrap a promise"); - Hoek.assert(result instanceof Error === false, "Cannot wrap an error"); - Hoek.assert(typeof result !== "symbol", "Cannot wrap a symbol"); - return this.request._core.Response.wrap(result, this.request); - } - redirect(location) { - return this.response("").redirect(location); - } - entity(options2) { - Hoek.assert(options2, "Entity method missing required options"); - Hoek.assert(options2.etag || options2.modified, "Entity methods missing required options key"); - this.request._entity = options2; - const entity = this.request._core.Response.entity(options2.etag, options2); - if (this.request._core.Response.unmodified(this.request, entity)) { - return this.response().code(304).takeover(); - } - } - state(name, value, options2) { - this.request._setState(name, value, options2); - } - unstate(name, options2) { - this.request._clearState(name, options2); - } - authenticated(data) { - Hoek.assert(this._auth, "Method not supported outside of authentication"); - Hoek.assert(data?.credentials, "Authentication data missing credentials information"); - return new internals.Auth(null, data); - } - unauthenticated(error2, data) { - Hoek.assert(this._auth, "Method not supported outside of authentication"); - Hoek.assert(!data || data.credentials, "Authentication data missing credentials information"); - return new internals.Auth(error2, data); - } - }; - Toolkit.prototype.abandon = exports2.symbols.abandon; - Toolkit.prototype.close = exports2.symbols.close; - Toolkit.prototype.continue = exports2.symbols.continue; - return Toolkit; - }; - internals.Auth = class { - constructor(error2, data) { - this.isAuth = true; - this.error = error2; - this.data = data; - } - }; - } -}); -var require_lib32 = __commonJS({ - "node_modules/.deno/@hapi+ammo@6.0.1/node_modules/@hapi/ammo/lib/index.js"(exports2) { - "use strict"; - var Stream = __require2("stream"); - var Hoek = require_lib(); - var internals = {}; - internals.headerRx = /^bytes=[\s,]*((?:(?:\d+\-\d*)|(?:\-\d+))(?:\s*,\s*(?:(?:\d+\-\d*)|(?:\-\d+)))*)$/i; - exports2.header = function(header, length2) { - const parts = internals.headerRx.exec(header); - if (!parts) { - return null; - } - const lastPos = length2 - 1; - const result = []; - const ranges = parts[1].match(/\d*\-\d*/g); - for (let range of ranges) { - let from3; - let to; - range = range.split("-"); - if (range[0]) { - from3 = parseInt(range[0], 10); - } - if (range[1]) { - to = parseInt(range[1], 10); - if (from3 !== void 0) { - if (to > lastPos) { - to = lastPos; - } - } else { - from3 = length2 - to; - to = lastPos; - } - } else { - to = lastPos; - } - if (from3 > to) { - return null; - } - result.push(new internals.Range(from3, to)); - } - if (result.length === 1) { - return result; - } - result.sort((a, b) => a.from - b.from); - const consolidated = []; - for (let i2 = result.length - 1; i2 > 0; --i2) { - const current = result[i2]; - const before = result[i2 - 1]; - if (current.from <= before.to + 1) { - before.to = current.to; - } else { - consolidated.unshift(current); - } - } - consolidated.unshift(result[0]); - return consolidated; - }; - internals.Range = class { - constructor(from3, to) { - this.from = from3; - this.to = to; - } - }; - exports2.Clip = class extends Stream.Transform { - constructor(range) { - if (!(range instanceof internals.Range)) { - Hoek.assert(typeof range === "object", 'Expected "range" object'); - const from3 = range.from ?? 0; - Hoek.assert(typeof from3 === "number", '"range.from" must be a number'); - Hoek.assert(from3 === parseInt(from3, 10) && from3 >= 0, '"range.from" must be a positive integer'); - const to = range.to ?? 0; - Hoek.assert(typeof to === "number", '"range.to" must be a number'); - Hoek.assert(to === parseInt(to, 10) && to >= 0, '"range.to" must be a positive integer'); - Hoek.assert(to >= from3, '"range.to" must be greater than or equal to "range.from"'); - range = new internals.Range(from3, to); - } - super(); - this._range = range; - this._next = 0; - this._pipes = /* @__PURE__ */ new Set(); - this.on("pipe", (pipe2) => this._pipes.add(pipe2)); - this.on("unpipe", (pipe2) => this._pipes.delete(pipe2)); - } - _transform(chunk, encoding, done) { - try { - internals.processChunk(this, chunk); - } catch (err) { - return done(err); - } - return done(); - } - _flush(done) { - this._pipes.clear(); - done(); - } - }; - internals.processChunk = function(stream, chunk) { - const pos = stream._next; - stream._next = stream._next + chunk.length; - if (stream._next <= stream._range.from) { - return; - } - if (pos > stream._range.to) { - for (const pipe2 of stream._pipes) { - pipe2.unpipe(stream); - } - stream._pipes.clear(); - stream.end(); - return; - } - const from3 = Math.max(0, stream._range.from - pos); - const to = Math.min(chunk.length, stream._range.to - pos + 1); - stream.push(chunk.slice(from3, to)); - }; - } -}); -var require_transmit = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/transmit.js"(exports2) { - "use strict"; - var Http = __require2("http"); - var Ammo = require_lib32(); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Teamwork = require_lib11(); - var Config = require_config(); - var internals = {}; - exports2.send = async function(request) { - const response = request.response; - try { - if (response.isBoom) { - await internals.fail(request, response); - return; - } - await internals.marshal(response); - await internals.transmit(response); - } catch (err) { - Bounce.rethrow(err, "system"); - request._setResponse(err); - return internals.fail(request, err); - } - }; - internals.marshal = async function(response) { - for (const func of response.request._route._marshalCycle) { - await func(response); - } - }; - internals.fail = async function(request, boom) { - const response = internals.error(request, boom); - request.response = response; - try { - await internals.marshal(response); - } catch (err) { - Bounce.rethrow(err, "system"); - const minimal = { - statusCode: response.statusCode, - error: Http.STATUS_CODES[response.statusCode], - message: boom.message - }; - response._payload = new request._core.Response.Payload(JSON.stringify(minimal), {}); - } - return internals.transmit(response); - }; - internals.error = function(request, boom) { - const error2 = boom.output; - const response = new request._core.Response(error2.payload, request, { error: boom }); - response.code(error2.statusCode); - response.headers = Hoek.clone(error2.headers); - return response; - }; - internals.transmit = function(response) { - const request = response.request; - const length2 = internals.length(response); - const encoding = request._core.compression.encoding(response, length2); - const ranger = encoding ? null : internals.range(response, length2); - const compressor = internals.encoding(response, encoding); - const isInjection = request.isInjected; - if (!(isInjection || request._core.started) || request._isPayloadPending && !request.raw.req._readableState.ended) { - response._header("connection", "close"); - } - internals.writeHead(response); - if (isInjection) { - request.raw.res[Config.symbol] = { request }; - if (response.variety === "plain") { - request.raw.res[Config.symbol].result = response._isPayloadSupported() ? response.source : null; - } - } - const stream = internals.chain([response._payload, response._tap(), compressor, ranger]); - return internals.pipe(request, stream); - }; - internals.length = function(response) { - const request = response.request; - const header = response.headers["content-length"]; - if (header === void 0) { - return null; - } - let length2 = header; - if (typeof length2 === "string") { - length2 = parseInt(header, 10); - if (!isFinite(length2)) { - delete response.headers["content-length"]; - return null; - } - } - if (length2 === 0 && !response._statusCode && response.statusCode === 200 && request.route.settings.response.emptyStatusCode !== 200) { - response.code(204); - delete response.headers["content-length"]; - } - return length2; - }; - internals.range = function(response, length2) { - const request = response.request; - if (!length2 || !request.route.settings.response.ranges || request.method !== "get" || response.statusCode !== 200) { - return null; - } - response._header("accept-ranges", "bytes"); - if (!request.headers.range) { - return null; - } - if (request.headers["if-range"] && request.headers["if-range"] !== response.headers.etag) { - return null; - } - const ranges = Ammo.header(request.headers.range, length2); - if (!ranges) { - const error2 = Boom5.rangeNotSatisfiable(); - error2.output.headers["content-range"] = "bytes */" + length2; - throw error2; - } - if (ranges.length !== 1) { - return null; - } - const range = ranges[0]; - response.code(206); - response.bytes(range.to - range.from + 1); - response._header("content-range", "bytes " + range.from + "-" + range.to + "/" + length2); - return new Ammo.Clip(range); - }; - internals.encoding = function(response, encoding) { - const request = response.request; - const header = response.headers["content-encoding"] || encoding; - if (header && response.headers.etag && response.settings.varyEtag) { - response.headers.etag = response.headers.etag.slice(0, -1) + "-" + header + '"'; - } - if (!encoding || response.statusCode === 206 || !response._isPayloadSupported()) { - return null; - } - delete response.headers["content-length"]; - response._header("content-encoding", encoding); - const compressor = request._core.compression.encoder(request, encoding); - if (response.variety === "stream" && typeof response._payload.setCompressor === "function") { - response._payload.setCompressor(compressor); - } - return compressor; - }; - internals.pipe = function(request, stream) { - const team = new Teamwork.Team(); - const env2 = { stream, request, team }; - if (request._closed) { - internals.end(env2, "aborted"); - return team.work; - } - const aborted2 = internals.end.bind(null, env2, "aborted"); - const close = internals.end.bind(null, env2, "close"); - const end = internals.end.bind(null, env2, null); - request.raw.req.on("aborted", aborted2); - request.raw.res.on("close", close); - request.raw.res.on("error", end); - request.raw.res.on("finish", end); - if (stream.writeToStream) { - stream.writeToStream(request.raw.res); - } else { - stream.on("error", end); - stream.on("close", aborted2); - stream.pipe(request.raw.res); - } - return team.work; - }; - internals.end = function(env2, event, err) { - const { request, stream, team } = env2; - if (!team) { - return; - } - env2.team = null; - if (request.raw.res.writableEnded) { - request.info.responded = Date.now(); - team.attend(); - return; - } - if (err) { - request.raw.res.destroy(); - request._core.Response.drain(stream); - } - const origResponse = request.response; - const error2 = err ? Boom5.boomify(err) : new Boom5.Boom(`Request ${event}`, { statusCode: request.route.settings.response.disconnectStatusCode, data: origResponse }); - request._setResponse(error2); - if (request.raw.res[Config.symbol]) { - request.raw.res[Config.symbol].error = event ? error2 : new Boom5.Boom(`Response error`, { statusCode: request.route.settings.response.disconnectStatusCode, data: origResponse }); - } - if (event) { - request._log(["response", "error", event]); - } else { - request._log(["response", "error"], err); - } - request.raw.res.end(); - team.attend(); - }; - internals.writeHead = function(response) { - const res = response.request.raw.res; - const headers = Object.keys(response.headers); - let i2 = 0; - try { - for (; i2 < headers.length; ++i2) { - const header = headers[i2]; - const value = response.headers[header]; - if (value !== void 0) { - res.setHeader(header, value); - } - } - } catch (err) { - for (--i2; i2 >= 0; --i2) { - res.removeHeader(headers[i2]); - } - throw Boom5.boomify(err); - } - if (response.settings.message) { - res.statusMessage = response.settings.message; - } - try { - res.writeHead(response.statusCode); - } catch (err) { - throw Boom5.boomify(err); - } - }; - internals.chain = function(sources) { - let from3 = sources[0]; - for (let i2 = 1; i2 < sources.length; ++i2) { - const to = sources[i2]; - if (to) { - from3.on("close", internals.destroyPipe.bind(from3, to)); - from3.on("error", internals.errorPipe.bind(from3, to)); - from3 = from3.pipe(to); - } - } - return from3; - }; - internals.destroyPipe = function(to) { - if (!this.readableEnded && !this.errored) { - to.destroy(); - } - }; - internals.errorPipe = function(to, err) { - to.emit("error", err); - }; - } -}); -var require_request2 = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/request.js"(exports2, module14) { - "use strict"; - var Querystring = __require2("querystring"); - var Url = __require2("url"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Podium = require_lib15(); - var Cors = require_cors(); - var Toolkit = require_toolkit(); - var Transmit = require_transmit(); - var internals = { - events: Podium.validate(["finish", { name: "peek", spread: true }, "disconnect"]), - reserved: ["server", "url", "query", "path", "method", "mime", "setUrl", "setMethod", "headers", "id", "app", "plugins", "route", "auth", "pre", "preResponses", "info", "isInjected", "orig", "params", "paramsArray", "payload", "state", "response", "raw", "domain", "log", "logs", "generateResponse"] - }; - exports2 = module14.exports = internals.Request = class { - constructor(server, req, res, options2) { - this._allowInternals = !!options2.allowInternals; - this._closed = false; - this._core = server._core; - this._entity = null; - this._eventContext = { request: this }; - this._events = null; - this._expectContinue = !!options2.expectContinue; - this._isInjected = !!options2.isInjected; - this._isPayloadPending = !!(req.headers["content-length"] || req.headers["transfer-encoding"]); - this._isReplied = false; - this._route = this._core.router.specials.notFound.route; - this._serverTimeoutId = null; - this._states = {}; - this._url = null; - this._urlError = null; - this.app = options2.app ? Object.assign({}, options2.app) : {}; - this.headers = req.headers; - this.logs = []; - this.method = req.method.toLowerCase(); - this.mime = null; - this.orig = {}; - this.params = null; - this.paramsArray = null; - this.path = null; - this.payload = void 0; - this.plugins = options2.plugins ? Object.assign({}, options2.plugins) : {}; - this.pre = {}; - this.preResponses = {}; - this.raw = { req, res }; - this.response = null; - this.route = this._route.public; - this.query = null; - this.server = server; - this.state = null; - this.info = new internals.Info(this); - this.auth = { - isAuthenticated: false, - isAuthorized: false, - isInjected: options2.auth ? true : false, - [internals.Request.symbols.authPayload]: options2.auth?.payload ?? true, - credentials: options2.auth?.credentials ?? null, - // Special keys: 'app', 'user', 'scope' - artifacts: options2.auth?.artifacts ?? null, - // Scheme-specific artifacts - strategy: options2.auth?.strategy ?? null, - mode: null, - error: null - }; - this._initializeUrl(); - } - static generate(server, req, res, options2) { - const request = new server._core.Request(server, req, res, options2); - if (server._core.decorations.requestApply) { - for (const [property, assignment] of server._core.decorations.requestApply.entries()) { - request[property] = assignment(request); - } - } - request._listen(); - return request; - } - get events() { - if (!this._events) { - this._events = new Podium.Podium(internals.events); - } - return this._events; - } - get isInjected() { - return this._isInjected; - } - get url() { - if (this._urlError) { - return null; - } - if (this._url) { - return this._url; - } - return this._parseUrl(this.raw.req.url, this._core.settings.router); - } - _initializeUrl() { - try { - this._setUrl(this.raw.req.url, this._core.settings.router.stripTrailingSlash, { fast: true }); - } catch (err) { - this.path = this.raw.req.url; - this.query = {}; - this._urlError = Boom5.boomify(err, { statusCode: 400, override: false }); - } - } - setUrl(url2, stripTrailingSlash) { - Hoek.assert(this.params === null, "Cannot change request URL after routing"); - if (url2 instanceof Url.URL) { - url2 = url2.href; - } - Hoek.assert(typeof url2 === "string", "Url must be a string or URL object"); - this._setUrl(url2, stripTrailingSlash, { fast: false }); - } - _setUrl(source, stripTrailingSlash, { fast }) { - const url2 = this._parseUrl(source, { stripTrailingSlash, _fast: fast }); - this.query = this._parseQuery(url2.searchParams); - this.path = url2.pathname; - } - _parseUrl(source, options2) { - if (source[0] === "/") { - if (options2._fast) { - const url2 = { - pathname: source, - searchParams: "" - }; - const q = source.indexOf("?"); - const h2 = source.indexOf("#"); - if (q !== -1 && (h2 === -1 || q < h2)) { - url2.pathname = source.slice(0, q); - const query = h2 === -1 ? source.slice(q + 1) : source.slice(q + 1, h2); - url2.searchParams = Querystring.parse(query); - } else { - url2.pathname = h2 === -1 ? source : source.slice(0, h2); - } - this._normalizePath(url2, options2); - return url2; - } - this._url = new Url.URL(`${this._core.info.protocol}://${this.info.host || `${this._core.info.host}:${this._core.info.port}`}${source}`); - } else { - this._url = new Url.URL(source); - this.info.hostname = this._url.hostname; - this.info.host = this._url.host; - } - this._normalizePath(this._url, options2); - this._urlError = null; - return this._url; - } - _normalizePath(url2, options2) { - let path8 = this._core.router.normalize(url2.pathname); - if (options2.stripTrailingSlash && path8.length > 1 && path8[path8.length - 1] === "/") { - path8 = path8.slice(0, -1); - } - url2.pathname = path8; - } - _parseQuery(searchParams) { - let query = /* @__PURE__ */ Object.create(null); - if (searchParams instanceof Url.URLSearchParams) { - for (let [key, value] of searchParams) { - const entry = query[key]; - if (entry !== void 0) { - value = [].concat(entry, value); - } - query[key] = value; - } - } else { - query = Object.assign(query, searchParams); - } - const parser3 = this._core.settings.query.parser; - if (parser3) { - query = parser3(query); - if (!query || typeof query !== "object") { - throw Boom5.badImplementation("Parsed query must be an object"); - } - } - return query; - } - setMethod(method) { - Hoek.assert(this.params === null, "Cannot change request method after routing"); - Hoek.assert(method && typeof method === "string", "Missing method"); - this.method = method.toLowerCase(); - } - active() { - return !!this._eventContext.request; - } - async _execute() { - this.info.acceptEncoding = this._core.compression.accept(this); - try { - await this._onRequest(); - } catch (err) { - Bounce.rethrow(err, "system"); - return this._reply(err); - } - this._lookup(); - this._setTimeouts(); - await this._lifecycle(); - this._reply(); - } - async _onRequest() { - if (this._core.extensions.route.onRequest.nodes) { - const response = await this._invoke(this._core.extensions.route.onRequest); - if (response) { - if (!internals.skip(response)) { - throw Boom5.badImplementation("onRequest extension methods must return an error, a takeover response, or a continue signal"); - } - throw response; - } - } - if (this._urlError) { - throw this._urlError; - } - } - _listen() { - if (this._isPayloadPending) { - this.raw.req.on("end", internals.event.bind(this.raw.req, this._eventContext, "end")); - } - this.raw.res.on("close", internals.event.bind(this.raw.res, this._eventContext, "close")); - this.raw.req.on("error", internals.event.bind(this.raw.req, this._eventContext, "error")); - this.raw.req.on("aborted", internals.event.bind(this.raw.req, this._eventContext, "abort")); - this.raw.res.once("close", internals.closed.bind(this.raw.res, this)); - } - _lookup() { - const match = this._core.router.route(this.method, this.path, this.info.hostname); - if (!match.route.settings.isInternal || this._allowInternals) { - this._route = match.route; - this.route = this._route.public; - } - this.params = match.params ?? {}; - this.paramsArray = match.paramsArray ?? []; - if (this.route.settings.cors) { - this.info.cors = { - isOriginMatch: Cors.matchOrigin(this.headers.origin, this.route.settings.cors) - }; - } - } - _setTimeouts() { - if (this.raw.req.socket && this.route.settings.timeout.socket !== void 0) { - this.raw.req.socket.setTimeout(this.route.settings.timeout.socket || 0); - } - let serverTimeout = this.route.settings.timeout.server; - if (!serverTimeout) { - return; - } - const elapsed = Date.now() - this.info.received; - serverTimeout = Math.floor(serverTimeout - elapsed); - if (serverTimeout <= 0) { - internals.timeoutReply(this, serverTimeout); - return; - } - this._serverTimeoutId = setTimeout(internals.timeoutReply, serverTimeout, this, serverTimeout); - } - async _lifecycle() { - for (const func of this._route._cycle) { - if (this._isReplied) { - return; - } - try { - var response = await (typeof func === "function" ? func(this) : this._invoke(func)); - } catch (err) { - Bounce.rethrow(err, "system"); - response = this._core.Response.wrap(err, this); - } - if (!response || response === Toolkit.symbols.continue) { - continue; - } - if (!internals.skip(response)) { - response = Boom5.badImplementation("Lifecycle methods called before the handler can only return an error, a takeover response, or a continue signal"); - } - this._setResponse(response); - return; - } - } - async _invoke(event, options2 = {}) { - for (const ext of event.nodes) { - const realm = ext.realm; - const bind = ext.bind ?? realm.settings.bind; - const response = await this._core.toolkit.execute(ext.func, this, { bind, realm, timeout: ext.timeout, name: event.type, ignoreResponse: options2.ignoreResponse }); - if (options2.ignoreResponse) { - if (Boom5.isBoom(response)) { - this._log(["ext", "error"], response); - } - continue; - } - if (response === Toolkit.symbols.continue) { - continue; - } - if (internals.skip(response) || this.response === null) { - return response; - } - this._setResponse(response); - } - } - async _reply(exit3) { - if (this._isReplied) { - return; - } - this._isReplied = true; - if (this._serverTimeoutId) { - clearTimeout(this._serverTimeoutId); - } - if (exit3) { - this._setResponse(this._core.Response.wrap(exit3, this)); - } - if (!this._eventContext.request) { - this._finalize(); - return; - } - if (typeof this.response === "symbol") { - this._abort(); - return; - } - await this._postCycle(); - if (!this._eventContext.request || typeof this.response === "symbol") { - this._abort(); - return; - } - await Transmit.send(this); - this._finalize(); - } - async _postCycle() { - for (const func of this._route._postCycle) { - if (!this._eventContext.request) { - return; - } - try { - var response = await (typeof func === "function" ? func(this) : this._invoke(func)); - } catch (err) { - Bounce.rethrow(err, "system"); - response = this._core.Response.wrap(err, this); - } - if (response && response !== Toolkit.symbols.continue) { - this._setResponse(response); - } - } - } - _abort() { - if (this.response === Toolkit.symbols.close) { - this.raw.res.end(); - } - this._finalize(); - } - _finalize() { - this._eventContext.request = null; - if (this.response._close) { - if (this.response.statusCode === 500 && this.response._error) { - const tags = this.response._error.isDeveloperError ? ["internal", "implementation", "error"] : ["internal", "error"]; - this._log(tags, this.response._error, "error"); - } - this.response._close(); - } - this.info.completed = Date.now(); - this._core.events.emit("response", this); - if (this._route._extensions.onPostResponse.nodes) { - this._invoke(this._route._extensions.onPostResponse, { ignoreResponse: true }); - } - } - _setResponse(response) { - if (this.response && !this.response.isBoom && this.response !== response && this.response.source !== response.source) { - this.response._close?.(); - } - if (this.info.completed) { - response._close?.(); - return; - } - this.response = response; - } - _setState(name, value, options2) { - const state = { name, value }; - if (options2) { - Hoek.assert(!options2.autoValue, "Cannot set autoValue directly in a response"); - state.options = Hoek.clone(options2); - } - this._states[name] = state; - } - _clearState(name, options2 = {}) { - const state = { name }; - state.options = Hoek.clone(options2); - state.options.ttl = 0; - this._states[name] = state; - } - _tap() { - if (!this._events) { - return null; - } - if (this._events.hasListeners("peek") || this._events.hasListeners("finish")) { - return new this._core.Response.Peek(this._events); - } - return null; - } - log(tags, data) { - return this._log(tags, data, "app"); - } - _log(tags, data, channel = "internal") { - if (!this._core.events.hasListeners("request") && !this.route.settings.log.collect) { - return; - } - if (!Array.isArray(tags)) { - tags = [tags]; - } - const timestamp = Date.now(); - const field = data instanceof Error ? "error" : "data"; - let event = [this, { request: this.info.id, timestamp, tags, [field]: data, channel }]; - if (typeof data === "function") { - event = () => [this, { request: this.info.id, timestamp, tags, data: data(), channel }]; - } - if (this.route.settings.log.collect) { - if (typeof data === "function") { - event = event(); - } - this.logs.push(event[1]); - } - this._core.events.emit({ name: "request", channel, tags }, event); - } - generateResponse(source, options2) { - return new this._core.Response(source, this, options2); - } - }; - internals.Request.reserved = internals.reserved; - internals.Request.symbols = { - authPayload: Symbol("auth.payload") - }; - internals.Info = class { - constructor(request) { - this._request = request; - const req = request.raw.req; - const host = req.headers.host ? req.headers.host.trim() : ""; - const received = Date.now(); - this.received = received; - this.referrer = req.headers.referrer || req.headers.referer || ""; - this.host = host; - this.hostname = host.split(":")[0]; - this.id = `${received}:${request._core.info.id}:${request._core._counter()}`; - this._remoteAddress = null; - this._remotePort = null; - this.acceptEncoding = null; - this.cors = null; - this.responded = 0; - this.completed = 0; - if (request._core.settings.info.remote) { - this.remoteAddress; - this.remotePort; - } - } - get remoteAddress() { - if (!this._remoteAddress) { - const ipv6Prefix = "::ffff:"; - const socketAddress = this._request.raw.req.socket.remoteAddress; - if (socketAddress && socketAddress.startsWith(ipv6Prefix) && socketAddress.includes(".", ipv6Prefix.length)) { - this._remoteAddress = socketAddress.slice(ipv6Prefix.length); - } else { - this._remoteAddress = socketAddress; - } - } - return this._remoteAddress; - } - get remotePort() { - if (this._remotePort === null) { - this._remotePort = this._request.raw.req.socket.remotePort || ""; - } - return this._remotePort; - } - toJSON() { - return { - acceptEncoding: this.acceptEncoding, - completed: this.completed, - cors: this.cors, - host: this.host, - hostname: this.hostname, - id: this.id, - received: this.received, - referrer: this.referrer, - remoteAddress: this.remoteAddress, - remotePort: this.remotePort, - responded: this.responded - }; - } - }; - internals.closed = function(request) { - request._closed = true; - }; - internals.event = function({ request }, event, err) { - if (!request) { - return; - } - request._isPayloadPending = false; - if (event === "close" && request.raw.res.writableEnded) { - return; - } - if (event === "end") { - return; - } - request._log(err ? ["request", "error"] : ["request", "error", event], err); - if (event === "error") { - return; - } - request._eventContext.request = null; - if (event === "abort") { - request._reply(new Boom5.Boom("Request aborted", { statusCode: request.route.settings.response.disconnectStatusCode, data: request.response })); - if (request._events) { - request._events.emit("disconnect"); - } - } - }; - internals.timeoutReply = function(request, timeout) { - const elapsed = Date.now() - request.info.received; - request._log(["request", "server", "timeout", "error"], { timeout, elapsed }); - request._reply(Boom5.serverUnavailable()); - }; - internals.skip = function(response) { - return response.isBoom || response._takeover || typeof response === "symbol"; - }; - } -}); -var require_auth = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/auth.js"(exports2, module14) { - "use strict"; - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Config = require_config(); - var Request2 = require_request2(); - var internals = { - missing: Symbol("missing") - }; - exports2 = module14.exports = internals.Auth = class { - #core = null; - #schemes = {}; - #strategies = {}; - api = {}; - // Do not reassign api or settings, as they are referenced in public() - settings = { - default: null - // Strategy used as default if route has no auth settings - }; - constructor(core) { - this.#core = core; - } - public(server) { - return { - api: this.api, - settings: this.settings, - scheme: this.scheme.bind(this), - strategy: this._strategy.bind(this, server), - default: this.default.bind(this), - test: this.test.bind(this), - verify: this.verify.bind(this), - lookup: this.lookup.bind(this) - }; - } - scheme(name, scheme) { - Hoek.assert(name, "Authentication scheme must have a name"); - Hoek.assert(!this.#schemes[name], "Authentication scheme name already exists:", name); - Hoek.assert(typeof scheme === "function", "scheme must be a function:", name); - this.#schemes[name] = scheme; - } - _strategy(server, name, scheme, options2 = {}) { - Hoek.assert(name, "Authentication strategy must have a name"); - Hoek.assert(typeof options2 === "object", "options must be an object"); - Hoek.assert(!this.#strategies[name], "Authentication strategy name already exists"); - Hoek.assert(scheme, "Authentication strategy", name, "missing scheme"); - Hoek.assert(this.#schemes[scheme], "Authentication strategy", name, "uses unknown scheme:", scheme); - server = server._clone(); - const strategy = this.#schemes[scheme](server, options2); - Hoek.assert(strategy.authenticate, "Invalid scheme:", name, "missing authenticate() method"); - Hoek.assert(typeof strategy.authenticate === "function", "Invalid scheme:", name, "invalid authenticate() method"); - Hoek.assert(!strategy.payload || typeof strategy.payload === "function", "Invalid scheme:", name, "invalid payload() method"); - Hoek.assert(!strategy.response || typeof strategy.response === "function", "Invalid scheme:", name, "invalid response() method"); - strategy.options = strategy.options ?? {}; - Hoek.assert(strategy.payload || !strategy.options.payload, "Cannot require payload validation without a payload method"); - this.#strategies[name] = { - methods: strategy, - realm: server.realm - }; - if (strategy.api) { - this.api[name] = strategy.api; - } - } - default(options2) { - Hoek.assert(!this.settings.default, "Cannot set default strategy more than once"); - options2 = Config.apply("auth", options2, "default strategy"); - this.settings.default = this._setupRoute(Hoek.clone(options2)); - const routes = this.#core.router.table(); - for (const route2 of routes) { - route2.rebuild(); - } - } - async test(name, request) { - Hoek.assert(name, "Missing authentication strategy name"); - const strategy = this.#strategies[name]; - Hoek.assert(strategy, "Unknown authentication strategy:", name); - const bind = strategy.methods; - const realm = strategy.realm; - const response = await request._core.toolkit.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); - if (!response.isAuth) { - throw response; - } - if (response.error) { - throw response.error; - } - return response.data; - } - async verify(request) { - const auth = request.auth; - if (auth.error) { - throw auth.error; - } - if (!auth.isAuthenticated) { - return; - } - const strategy = this.#strategies[auth.strategy]; - Hoek.assert(strategy, "Unknown authentication strategy:", auth.strategy); - if (!strategy.methods.verify) { - return; - } - const bind = strategy.methods; - await strategy.methods.verify.call(bind, auth); - } - static testAccess(request, route2) { - const auth = request._core.auth; - try { - return auth._access(request, route2); - } catch (err) { - Bounce.rethrow(err, "system"); - return false; - } - } - _setupRoute(options2, path8) { - if (!options2) { - return options2; - } - if (typeof options2 === "string") { - options2 = { strategies: [options2] }; - } else if (options2.strategy) { - options2.strategies = [options2.strategy]; - delete options2.strategy; - } - if (path8 && !options2.strategies) { - Hoek.assert(this.settings.default, "Route missing authentication strategy and no default defined:", path8); - options2 = Hoek.applyToDefaults(this.settings.default, options2); - } - path8 = path8 ?? "default strategy"; - Hoek.assert(options2.strategies?.length, "Missing authentication strategy:", path8); - options2.mode = options2.mode ?? "required"; - if (options2.entity !== void 0 || // Backwards compatibility with <= 11.x.x - options2.scope !== void 0) { - options2.access = [{ entity: options2.entity, scope: options2.scope }]; - delete options2.entity; - delete options2.scope; - } - if (options2.access) { - for (const access of options2.access) { - access.scope = internals.setupScope(access); - } - } - if (options2.payload === true) { - options2.payload = "required"; - } - let hasAuthenticatePayload = false; - for (const name of options2.strategies) { - const strategy = this.#strategies[name]; - Hoek.assert(strategy, "Unknown authentication strategy", name, "in", path8); - Hoek.assert(strategy.methods.payload || options2.payload !== "required", "Payload validation can only be required when all strategies support it in", path8); - hasAuthenticatePayload = hasAuthenticatePayload || strategy.methods.payload; - Hoek.assert(!strategy.methods.options.payload || options2.payload === void 0 || options2.payload === "required", "Cannot set authentication payload to", options2.payload, "when a strategy requires payload validation in", path8); - } - Hoek.assert(!options2.payload || hasAuthenticatePayload, "Payload authentication requires at least one strategy with payload support in", path8); - return options2; - } - lookup(route2) { - if (route2.settings.auth === false) { - return false; - } - return route2.settings.auth || this.settings.default; - } - _enabled(route2, type) { - const config2 = this.lookup(route2); - if (!config2) { - return false; - } - if (type === "authenticate") { - return true; - } - if (type === "access") { - return !!config2.access; - } - for (const name of config2.strategies) { - const strategy = this.#strategies[name]; - if (strategy.methods[type]) { - return true; - } - } - return false; - } - static authenticate(request) { - const auth = request._core.auth; - return auth._authenticate(request); - } - async _authenticate(request) { - const config2 = this.lookup(request.route); - const errors = []; - request.auth.mode = config2.mode; - if (request.auth.credentials) { - internals.validate(null, { credentials: request.auth.credentials, artifacts: request.auth.artifacts }, request.auth.strategy, config2, request, errors); - return; - } - for (const name of config2.strategies) { - const strategy = this.#strategies[name]; - const bind = strategy.methods; - const realm = strategy.realm; - const response = await request._core.toolkit.execute(strategy.methods.authenticate, request, { bind, realm, auth: true }); - const message = response.isAuth ? internals.validate(response.error, response.data, name, config2, request, errors) : internals.validate(response, null, name, config2, request, errors); - if (!message) { - return; - } - if (message !== internals.missing) { - return message; - } - } - const err = Boom5.unauthorized("Missing authentication", errors); - if (config2.mode === "required") { - throw err; - } - request.auth.isAuthenticated = false; - request.auth.credentials = null; - request.auth.error = err; - request._log(["auth", "unauthenticated"]); - } - static access(request) { - const auth = request._core.auth; - request.auth.isAuthorized = auth._access(request); - } - _access(request, route2) { - const config2 = this.lookup(route2 || request.route); - if (!config2?.access) { - return true; - } - const credentials = request.auth.credentials; - if (!credentials) { - if (config2.mode !== "required") { - return false; - } - throw Boom5.forbidden("Request is unauthenticated"); - } - const requestEntity = credentials.user ? "user" : "app"; - const scopeErrors = []; - for (const access of config2.access) { - const entity = access.entity; - if (entity && entity !== "any" && entity !== requestEntity) { - continue; - } - let scope = access.scope; - if (scope) { - if (!credentials.scope) { - scopeErrors.push(scope); - continue; - } - scope = internals.expandScope(request, scope); - if (!internals.validateScope(credentials, scope, "required") || !internals.validateScope(credentials, scope, "selection") || !internals.validateScope(credentials, scope, "forbidden")) { - scopeErrors.push(scope); - continue; - } - } - return true; - } - if (scopeErrors.length) { - request._log(["auth", "scope", "error"]); - throw Boom5.forbidden("Insufficient scope", { got: credentials.scope, need: scopeErrors }); - } - if (requestEntity === "app") { - request._log(["auth", "entity", "user", "error"]); - throw Boom5.forbidden("Application credentials cannot be used on a user endpoint"); - } - request._log(["auth", "entity", "app", "error"]); - throw Boom5.forbidden("User credentials cannot be used on an application endpoint"); - } - static async payload(request) { - if (!request.auth.isAuthenticated || !request.auth[Request2.symbols.authPayload]) { - return; - } - const auth = request._core.auth; - const strategy = auth.#strategies[request.auth.strategy]; - Hoek.assert(strategy, "Unknown authentication strategy:", request.auth.strategy); - if (!strategy.methods.payload) { - return; - } - const config2 = auth.lookup(request.route); - const setting = config2.payload ?? (strategy.methods.options.payload ? "required" : false); - if (!setting) { - return; - } - const bind = strategy.methods; - const realm = strategy.realm; - const response = await request._core.toolkit.execute(strategy.methods.payload, request, { bind, realm }); - if (response.isBoom && response.isMissing) { - return setting === "optional" ? void 0 : Boom5.unauthorized("Missing payload authentication"); - } - return response; - } - static async response(response) { - const request = response.request; - const auth = request._core.auth; - if (!request.auth.isAuthenticated) { - return; - } - const strategy = auth.#strategies[request.auth.strategy]; - Hoek.assert(strategy, "Unknown authentication strategy:", request.auth.strategy); - if (!strategy.methods.response) { - return; - } - const bind = strategy.methods; - const realm = strategy.realm; - const error2 = await request._core.toolkit.execute(strategy.methods.response, request, { bind, realm, continue: "undefined" }); - if (error2) { - throw error2; - } - } - }; - internals.setupScope = function(access) { - if (!access.scope) { - return false; - } - if (!Array.isArray(access.scope)) { - return access.scope; - } - const scope = {}; - for (const value of access.scope) { - const prefix = value[0]; - const type = prefix === "+" ? "required" : prefix === "!" ? "forbidden" : "selection"; - const clean = type === "selection" ? value : value.slice(1); - scope[type] = scope[type] ?? []; - scope[type].push(clean); - if (!scope._hasParameters?.[type] && /{([^}]+)}/.test(clean)) { - scope._hasParameters = scope._hasParameters ?? {}; - scope._hasParameters[type] = true; - } - } - return scope; - }; - internals.validate = function(err, result, name, config2, request, errors) { - result = result ?? {}; - request.auth.isAuthenticated = !err; - if (err) { - if (err instanceof Error === false) { - request._log(["auth", "unauthenticated", "response", name], { statusCode: err.statusCode }); - return err; - } - if (err.isMissing) { - request._log(["auth", "unauthenticated", "missing", name], err); - errors.push(err.output.headers["WWW-Authenticate"]); - return internals.missing; - } - } - request.auth.strategy = name; - request.auth.credentials = result.credentials; - request.auth.artifacts = result.artifacts; - if (!err) { - return; - } - request.auth.error = err; - if (config2.mode === "try") { - request._log(["auth", "unauthenticated", "try", name], err); - return; - } - request._log(["auth", "unauthenticated", "error", name], err); - throw err; - }; - internals.expandScope = function(request, scope) { - if (!scope._hasParameters) { - return scope; - } - const expanded = { - required: internals.expandScopeType(request, scope, "required"), - selection: internals.expandScopeType(request, scope, "selection"), - forbidden: internals.expandScopeType(request, scope, "forbidden") - }; - return expanded; - }; - internals.expandScopeType = function(request, scope, type) { - if (!scope._hasParameters[type]) { - return scope[type]; - } - const expanded = []; - const context = { - params: request.params, - query: request.query, - payload: request.payload, - credentials: request.auth.credentials - }; - for (const template of scope[type]) { - expanded.push(Hoek.reachTemplate(context, template)); - } - return expanded; - }; - internals.validateScope = function(credentials, scope, type) { - if (!scope[type]) { - return true; - } - const count = typeof credentials.scope === "string" ? scope[type].indexOf(credentials.scope) !== -1 ? 1 : 0 : Hoek.intersect(scope[type], credentials.scope).length; - if (type === "forbidden") { - return count === 0; - } - if (type === "required") { - return count === scope.required.length; - } - return !!count; - }; - } -}); -var require_header = __commonJS({ - "node_modules/.deno/@hapi+accept@6.0.3/node_modules/@hapi/accept/lib/header.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var Boom5 = require_lib2(); - var internals = {}; - exports2.selection = function(header, preferences, options2) { - const selections = exports2.selections(header, preferences, options2); - return selections.length ? selections[0] : ""; - }; - exports2.selections = function(header, preferences, options2) { - Hoek.assert(!preferences || Array.isArray(preferences), "Preferences must be an array"); - return internals.parse(header || "", preferences, options2); - }; - internals.parse = function(raw, preferences, options2) { - const header = raw.replace(/[ \t]/g, ""); - const lowers = /* @__PURE__ */ new Map(); - if (preferences) { - let pos = 0; - for (const preference of preferences) { - const lower = preference.toLowerCase(); - lowers.set(lower, { orig: preference, pos: pos++ }); - if (options2.prefixMatch) { - const parts2 = lower.split("-"); - while (parts2.pop(), parts2.length > 0) { - const joined = parts2.join("-"); - if (!lowers.has(joined)) { - lowers.set(joined, { orig: preference, pos: pos++ }); - } - } - } - } - } - const parts = header.split(","); - const selections = []; - const map = /* @__PURE__ */ new Set(); - for (let i2 = 0; i2 < parts.length; ++i2) { - const part = parts[i2]; - if (!part) { - continue; - } - const params = part.split(";"); - if (params.length > 2) { - throw Boom5.badRequest(`Invalid ${options2.type} header`); - } - let token = params[0].toLowerCase(); - if (!token) { - throw Boom5.badRequest(`Invalid ${options2.type} header`); - } - if (options2.equivalents?.has(token)) { - token = options2.equivalents.get(token); - } - const selection = { - token, - pos: i2, - q: 1 - }; - if (preferences && lowers.has(token)) { - selection.pref = lowers.get(token).pos; - } - map.add(selection.token); - if (params.length === 2) { - const q = params[1]; - const [key, value] = q.split("="); - if (!value || key !== "q" && key !== "Q") { - throw Boom5.badRequest(`Invalid ${options2.type} header`); - } - const score = parseFloat(value); - if (score === 0) { - continue; - } - if (Number.isFinite(score) && score <= 1 && score >= 1e-3) { - selection.q = score; - } - } - selections.push(selection); - } - selections.sort(internals.sort); - const values = selections.map((selection) => selection.token); - if (options2.default && !map.has(options2.default)) { - values.push(options2.default); - } - if (!preferences?.length) { - return values; - } - const preferred = []; - for (const selection of values) { - if (selection === "*") { - for (const [preference, value] of lowers) { - if (!map.has(preference)) { - preferred.push(value.orig); - } - } - } else { - const lower = selection.toLowerCase(); - if (lowers.has(lower)) { - preferred.push(lowers.get(lower).orig); - } - } - } - return preferred; - }; - internals.sort = function(a, b) { - const aFirst = -1; - const bFirst = 1; - if (b.q !== a.q) { - return b.q - a.q; - } - if (b.pref !== a.pref) { - if (a.pref === void 0) { - return bFirst; - } - if (b.pref === void 0) { - return aFirst; - } - return a.pref - b.pref; - } - return a.pos - b.pos; - }; - } -}); -var require_media = __commonJS({ - "node_modules/.deno/@hapi+accept@6.0.3/node_modules/@hapi/accept/lib/media.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var Boom5 = require_lib2(); - var internals = {}; - exports2.selection = function(header, preferences) { - const selections = exports2.selections(header, preferences); - return selections.length ? selections[0] : ""; - }; - exports2.selections = function(header, preferences) { - Hoek.assert(!preferences || Array.isArray(preferences), "Preferences must be an array"); - return internals.parse(header, preferences); - }; - internals.validMediaRx = /^(?:\*\/\*)|(?:[\w\!#\$%&'\*\+\-\.\^`\|~]+\/\*)|(?:[\w\!#\$%&'\*\+\-\.\^`\|~]+\/[\w\!#\$%&'\*\+\-\.\^`\|~]+)$/; - internals.parse = function(raw, preferences) { - const { header, quoted } = internals.normalize(raw); - const parts = header.split(","); - const selections = []; - const map = {}; - for (let i2 = 0; i2 < parts.length; ++i2) { - const part = parts[i2]; - if (!part) { - continue; - } - const pairs = part.split(";"); - const token = pairs.shift().toLowerCase(); - if (!internals.validMediaRx.test(token)) { - continue; - } - const selection = { - token, - params: {}, - exts: {}, - pos: i2 - }; - let target = "params"; - for (const pair of pairs) { - const kv = pair.split("="); - if (kv.length !== 2 || !kv[1]) { - throw Boom5.badRequest(`Invalid accept header`); - } - const key = kv[0]; - let value = kv[1]; - if (key === "q" || key === "Q") { - target = "exts"; - value = parseFloat(value); - if (!Number.isFinite(value) || value > 1 || value < 1e-3 && value !== 0) { - value = 1; - } - selection.q = value; - } else { - if (value[0] === '"') { - value = `"${quoted[value]}"`; - } - selection[target][kv[0]] = value; - } - } - const params = Object.keys(selection.params); - selection.original = [""].concat(params.map((key) => `${key}=${selection.params[key]}`)).join(";"); - selection.specificity = params.length; - if (selection.q === void 0) { - selection.q = 1; - } - const tparts = selection.token.split("/"); - selection.type = tparts[0]; - selection.subtype = tparts[1]; - map[selection.token] = selection; - if (selection.q) { - selections.push(selection); - } - } - selections.sort(internals.sort); - return internals.preferences(map, selections, preferences); - }; - internals.normalize = function(raw) { - raw = raw || "*/*"; - const normalized = { - header: raw, - quoted: {} - }; - if (raw.includes('"')) { - let i2 = 0; - normalized.header = raw.replace(/="([^"]*)"/g, ($0, $1) => { - const key = '"' + ++i2; - normalized.quoted[key] = $1; - return "=" + key; - }); - } - normalized.header = normalized.header.replace(/[ \t]/g, ""); - return normalized; - }; - internals.sort = function(a, b) { - if (b.q !== a.q) { - return b.q - a.q; - } - if (a.type !== b.type) { - return internals.innerSort(a, b, "type"); - } - if (a.subtype !== b.subtype) { - return internals.innerSort(a, b, "subtype"); - } - if (a.specificity !== b.specificity) { - return b.specificity - a.specificity; - } - return a.pos - b.pos; - }; - internals.innerSort = function(a, b, key) { - const aFirst = -1; - const bFirst = 1; - if (a[key] === "*") { - return bFirst; - } - if (b[key] === "*") { - return aFirst; - } - return a[key] < b[key] ? aFirst : bFirst; - }; - internals.preferences = function(map, selections, preferences) { - if (!preferences?.length) { - return selections.map((selection) => selection.token + selection.original); - } - const lowers = /* @__PURE__ */ Object.create(null); - const flat = /* @__PURE__ */ Object.create(null); - let any = false; - for (const preference of preferences) { - const lower = preference.toLowerCase(); - flat[lower] = preference; - const parts = lower.split("/"); - const type = parts[0]; - const subtype = parts[1]; - if (type === "*") { - Hoek.assert(subtype === "*", "Invalid media type preference contains wildcard type with a subtype"); - any = true; - continue; - } - lowers[type] = lowers[type] ?? /* @__PURE__ */ Object.create(null); - lowers[type][subtype] = preference; - } - const preferred = []; - for (const selection of selections) { - const token = selection.token; - const { type, subtype } = map[token]; - const subtypes = lowers[type]; - if (type === "*") { - for (const preference of Object.keys(flat)) { - if (!map[preference]) { - preferred.push(flat[preference]); - } - } - if (any) { - preferred.push("*/*"); - } - continue; - } - if (any) { - preferred.push((flat[token] || token) + selection.original); - continue; - } - if (subtype !== "*") { - const pref = flat[token]; - if (pref || subtypes && subtypes["*"]) { - preferred.push((pref || token) + selection.original); - } - continue; - } - if (subtypes) { - for (const psub of Object.keys(subtypes)) { - if (!map[`${type}/${psub}`]) { - preferred.push(subtypes[psub]); - } - } - } - } - return preferred; - }; - } -}); -var require_lib33 = __commonJS({ - "node_modules/.deno/@hapi+accept@6.0.3/node_modules/@hapi/accept/lib/index.js"(exports2) { - "use strict"; - var Header = require_header(); - var Media = require_media(); - var internals = { - options: { - charset: { - type: "accept-charset" - }, - encoding: { - type: "accept-encoding", - default: "identity", - equivalents: /* @__PURE__ */ new Map([ - ["x-compress", "compress"], - ["x-gzip", "gzip"] - ]) - }, - language: { - type: "accept-language", - prefixMatch: true - } - } - }; - for (const type in internals.options) { - exports2[type] = (header, preferences) => Header.selection(header, preferences, internals.options[type]); - exports2[`${type}s`] = (header, preferences) => Header.selections(header, preferences, internals.options[type]); - } - exports2.mediaType = (header, preferences) => Media.selection(header, preferences); - exports2.mediaTypes = (header, preferences) => Media.selections(header, preferences); - exports2.parseAll = function(requestHeaders) { - return { - charsets: exports2.charsets(requestHeaders["accept-charset"]), - encodings: exports2.encodings(requestHeaders["accept-encoding"]), - languages: exports2.languages(requestHeaders["accept-language"]), - mediaTypes: exports2.mediaTypes(requestHeaders.accept) - }; - }; - } -}); -var require_compression = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/compression.js"(exports2, module14) { - "use strict"; - var Zlib = __require2("zlib"); - var Accept = require_lib33(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var internals = { - common: ["gzip, deflate", "deflate, gzip", "gzip", "deflate", "gzip, deflate, br"] - }; - exports2 = module14.exports = internals.Compression = class { - decoders = { - gzip: (options2) => Zlib.createGunzip(options2), - deflate: (options2) => Zlib.createInflate(options2) - }; - encodings = ["identity", "gzip", "deflate"]; - encoders = { - identity: null, - gzip: (options2) => Zlib.createGzip(options2), - deflate: (options2) => Zlib.createDeflate(options2) - }; - #common = null; - constructor() { - this._updateCommons(); - } - _updateCommons() { - this.#common = /* @__PURE__ */ new Map(); - for (const header of internals.common) { - this.#common.set(header, Accept.encoding(header, this.encodings)); - } - } - addEncoder(encoding, encoder3) { - Hoek.assert(this.encoders[encoding] === void 0, `Cannot override existing encoder for ${encoding}`); - Hoek.assert(typeof encoder3 === "function", `Invalid encoder function for ${encoding}`); - this.encoders[encoding] = encoder3; - this.encodings.unshift(encoding); - this._updateCommons(); - } - addDecoder(encoding, decoder) { - Hoek.assert(this.decoders[encoding] === void 0, `Cannot override existing decoder for ${encoding}`); - Hoek.assert(typeof decoder === "function", `Invalid decoder function for ${encoding}`); - this.decoders[encoding] = decoder; - } - accept(request) { - const header = request.headers["accept-encoding"]; - if (!header) { - return "identity"; - } - const common4 = this.#common.get(header); - if (common4) { - return common4; - } - try { - return Accept.encoding(header, this.encodings); - } catch (err) { - Bounce.rethrow(err, "system"); - err.header = header; - request._log(["accept-encoding", "error"], err); - return "identity"; - } - } - encoding(response, length2) { - if (response.settings.compressed) { - response.headers["content-encoding"] = response.settings.compressed; - return null; - } - const request = response.request; - if (!request._core.settings.compression || length2 !== null && length2 < request._core.settings.compression.minBytes) { - return null; - } - const mime = request._core.mime.type(response.headers["content-type"] || "application/octet-stream"); - if (!mime.compressible) { - return null; - } - response.vary("accept-encoding"); - if (response.headers["content-encoding"]) { - return null; - } - return request.info.acceptEncoding === "identity" ? null : request.info.acceptEncoding; - } - encoder(request, encoding) { - const encoder3 = this.encoders[encoding]; - Hoek.assert(encoder3 !== void 0, `Unknown encoding ${encoding}`); - return encoder3(request.route.settings.compression[encoding]); - } - }; - } -}); -var require_methods = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/methods.js"(exports2, module14) { - "use strict"; - var Boom5 = require_lib2(); - var Hoek = require_lib(); - var Config = require_config(); - var internals = { - methodNameRx: /^[_$a-zA-Z][$\w]*(?:\.[_$a-zA-Z][$\w]*)*$/ - }; - exports2 = module14.exports = internals.Methods = class { - methods = {}; - #core = null; - constructor(core) { - this.#core = core; - } - add(name, method, options2, realm) { - if (typeof name !== "object") { - return this._add(name, method, options2, realm); - } - const items = [].concat(name); - for (let item of items) { - item = Config.apply("methodObject", item); - this._add(item.name, item.method, item.options ?? {}, realm); - } - } - _add(name, method, options2, realm) { - Hoek.assert(typeof method === "function", "method must be a function"); - Hoek.assert(typeof name === "string", "name must be a string"); - Hoek.assert(name.match(internals.methodNameRx), "Invalid name:", name); - Hoek.assert(!Hoek.reach(this.methods, name, { functions: false }), "Server method function name already exists:", name); - options2 = Config.apply("method", options2, name); - const settings = Hoek.clone(options2, { shallow: ["bind"] }); - settings.generateKey = settings.generateKey ?? internals.generateKey; - const bind = settings.bind ?? realm.settings.bind ?? null; - const bound = !bind ? method : (...args) => method.apply(bind, args); - if (!settings.cache) { - return this._assign(name, bound); - } - Hoek.assert(!settings.cache.generateFunc, "Cannot set generateFunc with method caching:", name); - Hoek.assert(settings.cache.generateTimeout !== void 0, "Method caching requires a timeout value in generateTimeout:", name); - settings.cache.generateFunc = (id, flags) => bound(...id.args, flags); - const cache2 = this.#core._cachePolicy(settings.cache, "#" + name); - const func = function(...args) { - const key = settings.generateKey.apply(bind, args); - if (typeof key !== "string") { - return Promise.reject(Boom5.badImplementation("Invalid method key when invoking: " + name, { name, args })); - } - return cache2.get({ id: key, args }); - }; - func.cache = { - drop: function(...args) { - const key = settings.generateKey.apply(bind, args); - if (typeof key !== "string") { - return Promise.reject(Boom5.badImplementation("Invalid method key when invoking: " + name, { name, args })); - } - return cache2.drop(key); - }, - stats: cache2.stats - }; - this._assign(name, func, func); - } - _assign(name, method) { - const path8 = name.split("."); - let ref = this.methods; - for (let i2 = 0; i2 < path8.length; ++i2) { - if (!ref[path8[i2]]) { - ref[path8[i2]] = i2 + 1 === path8.length ? method : {}; - } - ref = ref[path8[i2]]; - } - } - }; - internals.supportedArgs = ["string", "number", "boolean"]; - internals.generateKey = function(...args) { - let key = ""; - for (let i2 = 0; i2 < args.length; ++i2) { - const arg = args[i2]; - if (!internals.supportedArgs.includes(typeof arg)) { - return null; - } - key = key + (i2 ? ":" : "") + encodeURIComponent(arg.toString()); - } - return key; - }; - } -}); -var require_response2 = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/response.js"(exports2, module14) { - "use strict"; - var Stream = __require2("stream"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Podium = require_lib15(); - var Streams = require_streams(); - var internals = { - events: Podium.validate(["finish", { name: "peek", spread: true }]), - hopByHop: { - connection: true, - "keep-alive": true, - "proxy-authenticate": true, - "proxy-authorization": true, - "te": true, - "trailer": true, - "transfer-encoding": true, - "upgrade": true - }, - reserved: [ - "app", - "headers", - "plugins", - "request", - "source", - "statusCode", - "variety", - "settings", - "events", - "code", - "message", - "header", - "vary", - "etag", - "type", - "contentType", - "bytes", - "location", - "created", - "compressed", - "replacer", - "space", - "suffix", - "escape", - "passThrough", - "redirect", - "temporary", - "permanent", - "rewritable", - "encoding", - "charset", - "ttl", - "state", - "unstate", - "takeover" - ] - }; - exports2 = module14.exports = internals.Response = class { - constructor(source, request, options2 = {}) { - this.app = {}; - this.headers = {}; - this.plugins = {}; - this.request = request; - this.source = null; - this.statusCode = null; - this.variety = null; - this.settings = { - charset: "utf-8", - // '-' required by IANA - compressed: null, - encoding: "utf8", - message: null, - passThrough: true, - stringify: null, - // JSON.stringify options - ttl: null, - varyEtag: false - }; - this._events = null; - this._payload = null; - this._error = options2.error ?? null; - this._contentType = null; - this._takeover = false; - this._statusCode = false; - this._state = this._error ? "prepare" : "init"; - this._processors = { - marshal: options2.marshal, - prepare: options2.prepare, - close: options2.close - }; - this._setSource(source, options2.variety); - } - static wrap(result, request) { - if (result instanceof request._core.Response || typeof result === "symbol") { - return result; - } - if (result instanceof Error) { - return Boom5.boomify(result); - } - return new request._core.Response(result, request); - } - _setSource(source, variety) { - this.variety = variety ?? "plain"; - if (source === null || source === void 0) { - source = null; - } else if (Buffer.isBuffer(source)) { - this.variety = "buffer"; - this._contentType = "application/octet-stream"; - } else if (Streams.isStream(source)) { - this.variety = "stream"; - this._contentType = "application/octet-stream"; - } - this.source = source; - if (this.variety === "plain" && this.source !== null) { - this._contentType = typeof this.source === "string" ? "text/html" : "application/json"; - } - } - get events() { - if (!this._events) { - this._events = new Podium.Podium(internals.events); - } - return this._events; - } - code(statusCode) { - Hoek.assert(Number.isSafeInteger(statusCode), "Status code must be an integer"); - this.statusCode = statusCode; - this._statusCode = true; - return this; - } - message(httpMessage) { - this.settings.message = httpMessage; - return this; - } - header(key, value, options2) { - key = key.toLowerCase(); - if (key === "vary") { - return this.vary(value); - } - return this._header(key, value, options2); - } - _header(key, value, options2 = {}) { - const append = options2.append ?? false; - const separator = options2.separator || ","; - const override = options2.override !== false; - const duplicate = options2.duplicate !== false; - if (!append && override || !this.headers[key]) { - this.headers[key] = value; - } else if (override) { - if (key === "set-cookie") { - this.headers[key] = [].concat(this.headers[key], value); - } else { - const existing = this.headers[key]; - if (!duplicate) { - const values = existing.split(separator); - for (const v2 of values) { - if (v2 === value) { - return this; - } - } - } - this.headers[key] = existing + separator + value; - } - } - return this; - } - vary(value) { - if (value === "*") { - this.headers.vary = "*"; - } else if (!this.headers.vary) { - this.headers.vary = value; - } else if (this.headers.vary !== "*") { - this._header("vary", value, { append: true, duplicate: false }); - } - return this; - } - etag(tag3, options2) { - const entity = this.request._core.Response.entity(tag3, options2); - this._header("etag", entity.etag); - this.settings.varyEtag = entity.vary; - return this; - } - static entity(tag3, options2 = {}) { - Hoek.assert(tag3 !== "*", "ETag cannot be *"); - return { - etag: (options2.weak ? "W/" : "") + '"' + tag3 + '"', - vary: options2.vary !== false && !options2.weak, - // vary defaults to true - modified: options2.modified - }; - } - static unmodified(request, entity) { - if (request.method !== "get" && request.method !== "head") { - return false; - } - if (entity.etag && request.headers["if-none-match"]) { - const ifNoneMatch = request.headers["if-none-match"].split(/\s*,\s*/); - for (const etag of ifNoneMatch) { - if (etag === entity.etag) { - return true; - } - if (!entity.vary) { - continue; - } - if (etag === `W/${entity.etag}`) { - return etag; - } - const etagBase = entity.etag.slice(0, -1); - const encoders = request._core.compression.encodings; - for (const encoder3 of encoders) { - if (etag === etagBase + `-${encoder3}"`) { - return true; - } - } - } - return false; - } - if (!entity.modified) { - return false; - } - const ifModifiedSinceHeader = request.headers["if-modified-since"]; - if (!ifModifiedSinceHeader) { - return false; - } - const ifModifiedSince = internals.parseDate(ifModifiedSinceHeader); - if (!ifModifiedSince) { - return false; - } - const lastModified = internals.parseDate(entity.modified); - if (!lastModified) { - return false; - } - return ifModifiedSince >= lastModified; - } - type(type) { - this._header("content-type", type); - return this; - } - get contentType() { - let type = this.headers["content-type"]; - if (type) { - type = type.trim(); - if (this.settings.charset && type.match(/^(?:text\/)|(?:application\/(?:json)|(?:javascript))/) && !type.match(/; *charset=/)) { - const semi = type[type.length - 1] === ";"; - return type + (semi ? " " : "; ") + "charset=" + this.settings.charset; - } - return type; - } - if (this._contentType) { - const charset = this.settings.charset && this._contentType !== "application/octet-stream" ? "; charset=" + this.settings.charset : ""; - return this._contentType + charset; - } - return null; - } - bytes(bytes) { - this._header("content-length", bytes); - return this; - } - location(uri) { - this._header("location", uri); - return this; - } - created(location) { - Hoek.assert(this.request.method === "post" || this.request.method === "put" || this.request.method === "patch", "Cannot return 201 status codes for " + this.request.method.toUpperCase()); - this.statusCode = 201; - this.location(location); - return this; - } - compressed(encoding) { - Hoek.assert(encoding && typeof encoding === "string", "Invalid content-encoding"); - this.settings.compressed = encoding; - return this; - } - replacer(method) { - this.settings.stringify = this.settings.stringify ?? {}; - this.settings.stringify.replacer = method; - return this; - } - spaces(count) { - this.settings.stringify = this.settings.stringify ?? {}; - this.settings.stringify.space = count; - return this; - } - suffix(suffix) { - this.settings.stringify = this.settings.stringify ?? {}; - this.settings.stringify.suffix = suffix; - return this; - } - escape(escape) { - this.settings.stringify = this.settings.stringify ?? {}; - this.settings.stringify.escape = escape; - return this; - } - passThrough(enabled2) { - this.settings.passThrough = enabled2 !== false; - return this; - } - redirect(location) { - this.statusCode = 302; - this.location(location); - return this; - } - temporary(isTemporary) { - Hoek.assert(this.headers.location, "Cannot set redirection mode without first setting a location"); - this._setTemporary(isTemporary !== false); - return this; - } - permanent(isPermanent) { - Hoek.assert(this.headers.location, "Cannot set redirection mode without first setting a location"); - this._setTemporary(isPermanent === false); - return this; - } - rewritable(isRewritable) { - Hoek.assert(this.headers.location, "Cannot set redirection mode without first setting a location"); - this._setRewritable(isRewritable !== false); - return this; - } - _isTemporary() { - return this.statusCode === 302 || this.statusCode === 307; - } - _isRewritable() { - return this.statusCode === 301 || this.statusCode === 302; - } - _setTemporary(isTemporary) { - if (isTemporary) { - if (this._isRewritable()) { - this.statusCode = 302; - } else { - this.statusCode = 307; - } - } else { - if (this._isRewritable()) { - this.statusCode = 301; - } else { - this.statusCode = 308; - } - } - } - _setRewritable(isRewritable) { - if (isRewritable) { - if (this._isTemporary()) { - this.statusCode = 302; - } else { - this.statusCode = 301; - } - } else { - if (this._isTemporary()) { - this.statusCode = 307; - } else { - this.statusCode = 308; - } - } - } - encoding(encoding) { - this.settings.encoding = encoding; - return this; - } - charset(charset) { - this.settings.charset = charset ?? null; - return this; - } - ttl(ttl) { - this.settings.ttl = ttl; - return this; - } - state(name, value, options2) { - this.request._setState(name, value, options2); - return this; - } - unstate(name, options2) { - this.request._clearState(name, options2); - return this; - } - takeover() { - this._takeover = true; - return this; - } - _prepare() { - Hoek.assert(this._state === "init"); - this._state = "prepare"; - this._passThrough(); - if (!this._processors.prepare) { - return this; - } - try { - return this._processors.prepare(this); - } catch (err) { - throw Boom5.boomify(err); - } - } - _passThrough() { - if (this.variety === "stream" && this.settings.passThrough) { - if (this.source.statusCode && !this.statusCode) { - this.statusCode = this.source.statusCode; - } - if (this.source.headers) { - let headerKeys = Object.keys(this.source.headers); - if (headerKeys.length) { - const localHeaders = this.headers; - this.headers = {}; - const connection = this.source.headers.connection; - const byHop = {}; - if (connection) { - connection.split(/\s*,\s*/).forEach((header) => { - byHop[header] = true; - }); - } - for (const key of headerKeys) { - const lower = key.toLowerCase(); - if (!internals.hopByHop[lower] && !byHop[lower]) { - this.header(lower, Hoek.clone(this.source.headers[key])); - } - } - headerKeys = Object.keys(localHeaders); - for (const key of headerKeys) { - this.header(key, localHeaders[key], { append: key === "set-cookie" }); - } - } - } - } - this.statusCode = this.statusCode ?? 200; - } - async _marshal() { - Hoek.assert(this._state === "prepare"); - this._state = "marshall"; - let source = this.source; - if (this._processors.marshal) { - try { - source = await this._processors.marshal(this); - } catch (err) { - throw Boom5.boomify(err); - } - } - if (Streams.isStream(source)) { - this._payload = source; - return; - } - const jsonify = this.variety === "plain" && source !== null && typeof source !== "string"; - if (!jsonify && this.settings.stringify) { - throw Boom5.badImplementation("Cannot set formatting options on non object response"); - } - let payload = source; - if (jsonify) { - const options2 = this.settings.stringify ?? {}; - const space = options2.space ?? this.request.route.settings.json.space; - const replacer = options2.replacer ?? this.request.route.settings.json.replacer; - const suffix = options2.suffix ?? this.request.route.settings.json.suffix ?? ""; - const escape = this.request.route.settings.json.escape; - try { - if (replacer || space) { - payload = JSON.stringify(payload, replacer, space); - } else { - payload = JSON.stringify(payload); - } - } catch (err) { - throw Boom5.boomify(err); - } - if (suffix) { - payload = payload + suffix; - } - if (escape) { - payload = Hoek.escapeJson(payload); - } - } - this._payload = new internals.Response.Payload(payload, this.settings); - } - _tap() { - if (!this._events) { - return null; - } - if (this._events.hasListeners("peek") || this._events.hasListeners("finish")) { - return new internals.Response.Peek(this._events); - } - return null; - } - _close() { - if (this._state === "close") { - return; - } - this._state = "close"; - if (this._processors.close) { - try { - this._processors.close(this); - } catch (err) { - Bounce.rethrow(err, "system"); - this.request._log(["response", "cleanup", "error"], err); - } - } - const stream = this._payload || this.source; - if (Streams.isStream(stream)) { - internals.Response.drain(stream); - } - } - _isPayloadSupported() { - return this.request.method !== "head" && this.statusCode !== 304 && this.statusCode !== 204; - } - static drain(stream) { - stream.destroy(); - } - }; - internals.Response.reserved = internals.reserved; - internals.parseDate = function(string3) { - try { - return Date.parse(string3); - } catch (errIgnore) { - } - }; - internals.Response.Payload = class extends Stream.Readable { - constructor(payload, options2) { - super(); - this._data = payload; - this._encoding = options2.encoding; - } - _read(size) { - if (this._data) { - this.push(this._data, this._encoding); - } - this.push(null); - } - size() { - if (!this._data) { - return 0; - } - return Buffer.isBuffer(this._data) ? this._data.length : Buffer.byteLength(this._data, this._encoding); - } - writeToStream(stream) { - if (this._data) { - stream.write(this._data, this._encoding); - } - stream.end(); - } - }; - internals.Response.Peek = class extends Stream.Transform { - constructor(podium) { - super(); - this._podium = podium; - this.on("finish", () => podium.emit("finish")); - } - _transform(chunk, encoding, callback) { - this._podium.emit("peek", [chunk, encoding]); - this.push(chunk, encoding); - callback(); - } - }; - } -}); -var require_core = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/core.js"(exports2, module14) { - "use strict"; - var Http = __require2("http"); - var Https = __require2("https"); - var Os = __require2("os"); - var Path = __require2("path"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Call = require_lib14(); - var Catbox = require_lib16(); - var { Engine: CatboxMemory } = require_lib17(); - var { Heavy } = require_lib18(); - var Hoek = require_lib(); - var { Mimos } = require_lib19(); - var Podium = require_lib15(); - var Statehood = require_lib24(); - var Auth = require_auth(); - var Compression = require_compression(); - var Config = require_config(); - var Cors = require_cors(); - var Ext = require_ext(); - var Methods = require_methods(); - var Request2 = require_request2(); - var Response2 = require_response2(); - var Route = require_route2(); - var Toolkit = require_toolkit(); - var Validation = require_validation(); - var internals = { - counter: { - min: 1e4, - max: 99999 - }, - events: [ - { name: "cachePolicy", spread: true }, - { name: "log", channels: ["app", "internal"], tags: true }, - { name: "request", channels: ["app", "internal", "error"], tags: true, spread: true }, - "response", - "route", - "start", - "closing", - "stop" - ], - badRequestResponse: Buffer.from("HTTP/1.1 400 Bad Request\r\n\r\n", "ascii") - }; - exports2 = module14.exports = internals.Core = class { - actives = /* @__PURE__ */ new WeakMap(); - // Active requests being processed - app = {}; - auth = new Auth(this); - caches = /* @__PURE__ */ new Map(); - // Cache clients - compression = new Compression(); - controlled = null; - // Other servers linked to the phases of this server - dependencies = []; - // Plugin dependencies - events = new Podium.Podium(internals.events); - heavy = null; - info = null; - instances = /* @__PURE__ */ new Set(); - listener = null; - methods = new Methods(this); - // Server methods - mime = null; - onConnection = null; - // Used to remove event listener on stop - phase = "stopped"; - // 'stopped', 'initializing', 'initialized', 'starting', 'started', 'stopping', 'invalid' - plugins = {}; - // Exposed plugin properties by name - registrations = {}; - // Tracks plugin for dependency validation { name -> { version } } - registring = 0; - // > 0 while register() is waiting for plugin callbacks - Request = class extends Request2 { - }; - Response = class extends Response2 { - }; - requestCounter = { value: internals.counter.min, min: internals.counter.min, max: internals.counter.max }; - root = null; - router = null; - settings = null; - sockets = null; - // Track open sockets for graceful shutdown - started = false; - states = null; - toolkit = new Toolkit.Manager(); - type = null; - validator = null; - extensionsSeq = 0; - // Used to keep absolute order of extensions based on the order added across locations - extensions = { - server: { - onPreStart: new Ext("onPreStart", this), - onPostStart: new Ext("onPostStart", this), - onPreStop: new Ext("onPreStop", this), - onPostStop: new Ext("onPostStop", this) - }, - route: { - onRequest: new Ext("onRequest", this), - onPreAuth: new Ext("onPreAuth", this), - onCredentials: new Ext("onCredentials", this), - onPostAuth: new Ext("onPostAuth", this), - onPreHandler: new Ext("onPreHandler", this), - onPostHandler: new Ext("onPostHandler", this), - onPreResponse: new Ext("onPreResponse", this), - onPostResponse: new Ext("onPostResponse", this) - } - }; - decorations = { - handler: /* @__PURE__ */ new Map(), - request: /* @__PURE__ */ new Map(), - response: /* @__PURE__ */ new Map(), - server: /* @__PURE__ */ new Map(), - toolkit: /* @__PURE__ */ new Map(), - requestApply: null, - public: { handler: [], request: [], response: [], server: [], toolkit: [] } - }; - constructor(options2) { - const { settings, type } = internals.setup(options2); - this.settings = settings; - this.type = type; - this.heavy = new Heavy(this.settings.load); - this.mime = new Mimos(this.settings.mime); - this.router = new Call.Router(this.settings.router); - this.states = new Statehood.Definitions(this.settings.state); - this._debug(); - this._initializeCache(); - if (this.settings.routes.validate.validator) { - this.validator = Validation.validator(this.settings.routes.validate.validator); - } - this.listener = this._createListener(); - this._initializeListener(); - this.info = this._info(); - } - _debug() { - const debug = this.settings.debug; - if (!debug) { - return; - } - const method = (event) => { - const data = event.error ?? event.data; - console.error("Debug:", event.tags.join(", "), data ? "\n " + (data.stack ?? (typeof data === "object" ? Hoek.stringify(data) : data)) : ""); - }; - if (debug.log) { - const filter = debug.log.some((tag3) => tag3 === "*") ? void 0 : debug.log; - this.events.on({ name: "log", filter }, method); - } - if (debug.request) { - const filter = debug.request.some((tag3) => tag3 === "*") ? void 0 : debug.request; - this.events.on({ name: "request", filter }, (request, event) => method(event)); - } - } - _initializeCache() { - if (this.settings.cache) { - this._createCache(this.settings.cache); - } - if (!this.caches.has("_default")) { - this._createCache([{ provider: CatboxMemory }]); - } - } - _info() { - const now = Date.now(); - const protocol = this.type === "tcp" ? this.settings.tls ? "https" : "http" : this.type; - const host = this.settings.host || Os.hostname() || "localhost"; - const port = this.settings.port; - const info = { - created: now, - started: 0, - host, - port, - protocol, - id: Os.hostname() + ":" + process.pid + ":" + now.toString(36), - uri: this.settings.uri ?? protocol + ":" + (this.type === "tcp" ? "//" + host + (port ? ":" + port : "") : port) - }; - return info; - } - _counter() { - const next = ++this.requestCounter.value; - if (this.requestCounter.value > this.requestCounter.max) { - this.requestCounter.value = this.requestCounter.min; - } - return next - 1; - } - _createCache(configs) { - Hoek.assert(this.phase !== "initializing", "Cannot provision server cache while server is initializing"); - configs = Config.apply("cache", configs); - const added = []; - for (let config2 of configs) { - if (typeof config2 === "function") { - config2 = { provider: { constructor: config2 } }; - } - const name = config2.name ?? "_default"; - Hoek.assert(!this.caches.has(name), "Cannot configure the same cache more than once: ", name === "_default" ? "default cache" : name); - let client = null; - if (config2.provider) { - let provider = config2.provider; - if (typeof provider === "function") { - provider = { constructor: provider }; - } - client = new Catbox.Client(provider.constructor, provider.options ?? { partition: "hapi-cache" }); - } else { - client = new Catbox.Client(config2.engine); - } - this.caches.set(name, { client, segments: {}, shared: config2.shared ?? false }); - added.push(client); - } - return added; - } - registerServer(server) { - if (!this.root) { - this.root = server; - this._defaultRoutes(); - } - this.instances.add(server); - } - async _start() { - if (this.phase === "initialized" || this.phase === "started") { - this._validateDeps(); - } - if (this.phase === "started") { - return; - } - if (this.phase !== "stopped" && this.phase !== "initialized") { - throw new Error("Cannot start server while it is in " + this.phase + " phase"); - } - if (this.phase !== "initialized") { - await this._initialize(); - } - this.phase = "starting"; - this.started = true; - this.info.started = Date.now(); - try { - await this._listen(); - } catch (err) { - this.started = false; - this.phase = "invalid"; - throw err; - } - this.phase = "started"; - this.events.emit("start"); - try { - if (this.controlled) { - await Promise.all(this.controlled.map((control) => control.start())); - } - await this._invoke("onPostStart"); - } catch (err) { - this.phase = "invalid"; - throw err; - } - } - _listen() { - return new Promise((resolve82, reject) => { - if (!this.settings.autoListen) { - resolve82(); - return; - } - const onError = (err) => { - reject(err); - return; - }; - this.listener.once("error", onError); - const finalize = () => { - this.listener.removeListener("error", onError); - resolve82(); - return; - }; - if (this.type !== "tcp") { - this.listener.listen(this.settings.port, finalize); - } else { - const address = this.settings.address || this.settings.host || null; - this.listener.listen(this.settings.port, address, finalize); - } - }); - } - async _initialize() { - if (this.registring) { - throw new Error("Cannot start server before plugins finished registration"); - } - if (this.phase === "initialized") { - return; - } - if (this.phase !== "stopped") { - throw new Error("Cannot initialize server while it is in " + this.phase + " phase"); - } - this._validateDeps(); - this.phase = "initializing"; - try { - const caches = []; - this.caches.forEach((cache2) => caches.push(cache2.client.start())); - await Promise.all(caches); - await this._invoke("onPreStart"); - this.heavy.start(); - this.phase = "initialized"; - if (this.controlled) { - await Promise.all(this.controlled.map((control) => control.initialize())); - } - } catch (err) { - this.phase = "invalid"; - throw err; - } - } - _validateDeps() { - for (const { deps, plugin: plugin2 } of this.dependencies) { - for (const dep in deps) { - const version3 = deps[dep]; - Hoek.assert(this.registrations[dep], "Plugin", plugin2, "missing dependency", dep); - Hoek.assert(version3 === "*" || Config.versionMatch(this.registrations[dep].version, version3), "Plugin", plugin2, "requires", dep, "version", version3, "but found", this.registrations[dep].version); - } - } - } - async _stop(options2 = {}) { - options2.timeout = options2.timeout ?? 5e3; - if (["stopped", "initialized", "started", "invalid"].indexOf(this.phase) === -1) { - throw new Error("Cannot stop server while in " + this.phase + " phase"); - } - this.phase = "stopping"; - try { - await this._invoke("onPreStop"); - if (this.started) { - this.started = false; - this.info.started = 0; - await this._unlisten(options2.timeout); - } - const caches = []; - this.caches.forEach((cache2) => caches.push(cache2.client.stop())); - await Promise.all(caches); - this.events.emit("stop"); - this.heavy.stop(); - if (this.controlled) { - await Promise.all(this.controlled.map((control) => control.stop(options2))); - } - await this._invoke("onPostStop"); - this.phase = "stopped"; - } catch (err) { - this.phase = "invalid"; - throw err; - } - } - _unlisten(timeout) { - let timeoutId = null; - if (this.settings.operations.cleanStop) { - const destroy = () => { - for (const connection of this.sockets) { - connection.destroy(); - } - this.sockets.clear(); - }; - timeoutId = setTimeout(destroy, timeout); - for (const connection of this.sockets) { - if (!this.actives.has(connection)) { - connection.end(); - } - } - } - return new Promise((resolve82) => { - this.listener.close(() => { - if (this.settings.operations.cleanStop) { - this.listener.removeListener(this.settings.tls ? "secureConnection" : "connection", this.onConnection); - clearTimeout(timeoutId); - } - this._initializeListener(); - resolve82(); - }); - this.events.emit("closing"); - }); - } - async _invoke(type) { - const exts = this.extensions.server[type]; - if (!exts.nodes) { - return; - } - for (const ext of exts.nodes) { - const bind = ext.bind ?? ext.realm.settings.bind; - const operation = ext.func.call(bind, ext.server, bind); - await Toolkit.timed(operation, { timeout: ext.timeout, name: type }); - } - } - _defaultRoutes() { - this.router.special("notFound", new Route({ method: "_special", path: "/{p*}", handler: internals.notFound }, this.root, { special: true })); - this.router.special("badRequest", new Route({ method: "_special", path: "/{p*}", handler: internals.badRequest }, this.root, { special: true })); - if (this.settings.routes.cors) { - Cors.handler(this.root); - } - } - _dispatch(options2 = {}) { - return (req, res) => { - const request = Request2.generate(this.root, req, res, options2); - if (this.settings.operations.cleanStop && req.socket) { - this.actives.set(req.socket, request); - const env2 = { core: this, req }; - res.on("finish", internals.onFinish.bind(res, env2)); - } - if (this.settings.load.sampleInterval) { - try { - this.heavy.check(); - } catch (err) { - Bounce.rethrow(err, "system"); - this._log(["load"], this.heavy.load); - request._reply(err); - return; - } - } - request._execute(); - }; - } - _createListener() { - const listener = this.settings.listener ?? (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer()); - listener.on("request", this._dispatch()); - listener.on("checkContinue", this._dispatch({ expectContinue: true })); - listener.on("clientError", (err, socket) => { - this._log(["connection", "client", "error"], err); - if (socket.readable) { - const request = this.settings.operations.cleanStop && this.actives.get(socket); - if (request) { - if (err.code === "HPE_INVALID_METHOD") { - request.raw.res.once("close", () => { - if (socket.readable) { - socket.end(internals.badRequestResponse); - } else { - socket.destroy(err); - } - }); - return; - } - const error2 = Boom5.badRequest(); - error2.output.headers = { connection: "close" }; - request._reply(error2); - } else { - socket.end(internals.badRequestResponse); - } - } else { - socket.destroy(err); - } - }); - return listener; - } - _initializeListener() { - this.listener.once("listening", () => { - if (this.type === "tcp") { - const address = this.listener.address(); - this.info.address = address.address; - this.info.port = address.port; - this.info.uri = this.settings.uri ?? this.info.protocol + "://" + this.info.host + ":" + this.info.port; - } - if (this.settings.operations.cleanStop) { - this.sockets = /* @__PURE__ */ new Set(); - const self2 = this; - const onClose = function() { - self2.sockets.delete(this); - }; - this.onConnection = (connection) => { - this.sockets.add(connection); - connection.on("close", onClose); - }; - this.listener.on(this.settings.tls ? "secureConnection" : "connection", this.onConnection); - } - }); - } - _cachePolicy(options2, _segment, realm) { - options2 = Config.apply("cachePolicy", options2); - const plugin2 = realm?.plugin; - const segment = options2.segment ?? _segment ?? (plugin2 ? `!${plugin2}` : ""); - Hoek.assert(segment, "Missing cache segment name"); - const cacheName = options2.cache ?? "_default"; - const cache2 = this.caches.get(cacheName); - Hoek.assert(cache2, "Unknown cache", cacheName); - Hoek.assert(!cache2.segments[segment] || cache2.shared || options2.shared, "Cannot provision the same cache segment more than once"); - cache2.segments[segment] = true; - const policy = new Catbox.Policy(options2, cache2.client, segment); - this.events.emit("cachePolicy", [policy, options2.cache, segment]); - return policy; - } - log(tags, data) { - return this._log(tags, data, "app"); - } - _log(tags, data, channel = "internal") { - if (!this.events.hasListeners("log")) { - return; - } - if (!Array.isArray(tags)) { - tags = [tags]; - } - const timestamp = Date.now(); - const field = data instanceof Error ? "error" : "data"; - let event = { timestamp, tags, [field]: data, channel }; - if (typeof data === "function") { - event = () => ({ timestamp, tags, data: data(), channel }); - } - this.events.emit({ name: "log", tags, channel }, event); - } - }; - internals.setup = function(options2 = {}) { - let settings = Hoek.clone(options2, { shallow: ["cache", "listener", "routes.bind"] }); - settings.app = settings.app ?? {}; - settings.routes = Config.enable(settings.routes); - settings = Config.apply("server", settings); - if (settings.port === void 0) { - settings.port = 0; - } - const type = typeof settings.port === "string" ? "socket" : "tcp"; - if (type === "socket") { - settings.port = settings.port.indexOf("/") !== -1 ? Path.resolve(settings.port) : settings.port.toLowerCase(); - } - if (settings.autoListen === void 0) { - settings.autoListen = true; - } - Hoek.assert(settings.autoListen || !settings.port, "Cannot specify port when autoListen is false"); - Hoek.assert(settings.autoListen || !settings.address, "Cannot specify address when autoListen is false"); - return { settings, type }; - }; - internals.notFound = function() { - throw Boom5.notFound(); - }; - internals.badRequest = function() { - throw Boom5.badRequest(); - }; - internals.onFinish = function(env2) { - const { core, req } = env2; - core.actives.delete(req.socket); - if (!core.started) { - req.socket.end(); - } - }; - } -}); -var require_package4 = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/package.json"(exports2, module14) { - module14.exports = { - name: "@hapi/hapi", - description: "HTTP Server framework", - homepage: "https://hapi.dev", - version: "21.4.3", - repository: "git://github.com/hapijs/hapi", - main: "lib/index.js", - types: "lib/index.d.ts", - engines: { - node: ">=14.15.0" - }, - files: [ - "lib" - ], - keywords: [ - "framework", - "http", - "api", - "web" - ], - eslintConfig: { - extends: [ - "plugin:@hapi/module" - ] - }, - dependencies: { - "@hapi/accept": "^6.0.3", - "@hapi/ammo": "^6.0.1", - "@hapi/boom": "^10.0.1", - "@hapi/bounce": "^3.0.2", - "@hapi/call": "^9.0.1", - "@hapi/catbox": "^12.1.1", - "@hapi/catbox-memory": "^6.0.2", - "@hapi/heavy": "^8.0.1", - "@hapi/hoek": "^11.0.7", - "@hapi/mimos": "^7.0.1", - "@hapi/podium": "^5.0.2", - "@hapi/shot": "^6.0.2", - "@hapi/somever": "^4.1.1", - "@hapi/statehood": "^8.2.0", - "@hapi/subtext": "^8.1.1", - "@hapi/teamwork": "^6.0.0", - "@hapi/topo": "^6.0.2", - "@hapi/validate": "^2.0.1" - }, - devDependencies: { - "@hapi/code": "^9.0.3", - "@hapi/eslint-plugin": "^6.0.0", - "@hapi/inert": "^7.1.0", - "@hapi/joi-legacy-test": "npm:@hapi/joi@^15.0.0", - "@hapi/lab": "^25.3.2", - "@hapi/vision": "^7.0.3", - "@hapi/wreck": "^18.1.0", - "@types/node": "^18.19.122", - handlebars: "^4.7.8", - joi: "^17.13.3", - "legacy-readable-stream": "npm:readable-stream@^1.0.34", - typescript: "^4.9.5" - }, - scripts: { - test: "lab -a @hapi/code -t 100 -L -m 5000 -Y", - "test-tap": "lab -a @hapi/code -r tap -o tests.tap -m 5000", - "test-cov-html": "lab -a @hapi/code -r html -o coverage.html -m 5000" - }, - license: "BSD-3-Clause" - }; - } -}); -var require_server = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/server.js"(exports2, module14) { - "use strict"; - var Hoek = require_lib(); - var Shot = require_lib10(); - var Teamwork = require_lib11(); - var Config = require_config(); - var Core = require_core(); - var Cors = require_cors(); - var Ext = require_ext(); - var Package = require_package4(); - var Route = require_route2(); - var Toolkit = require_toolkit(); - var Validation = require_validation(); - var internals = {}; - exports2 = module14.exports = function(options2) { - const core = new Core(options2); - return new internals.Server(core); - }; - internals.Server = class { - constructor(core, name, parent) { - this._core = core; - this.app = core.app; - this.auth = core.auth.public(this); - this.decorations = core.decorations.public; - this.cache = internals.cache(this); - this.events = core.events; - this.info = core.info; - this.listener = core.listener; - this.load = core.heavy.load; - this.methods = core.methods.methods; - this.mime = core.mime; - this.plugins = core.plugins; - this.registrations = core.registrations; - this.settings = core.settings; - this.states = core.states; - this.type = core.type; - this.version = Package.version; - this.realm = { - _extensions: { - onPreAuth: new Ext("onPreAuth", core), - onCredentials: new Ext("onCredentials", core), - onPostAuth: new Ext("onPostAuth", core), - onPreHandler: new Ext("onPreHandler", core), - onPostHandler: new Ext("onPostHandler", core), - onPreResponse: new Ext("onPreResponse", core), - onPostResponse: new Ext("onPostResponse", core) - }, - modifiers: { - route: {} - }, - parent: parent ? parent.realm : null, - plugin: name, - pluginOptions: {}, - plugins: {}, - _rules: null, - settings: { - bind: void 0, - files: { - relativeTo: void 0 - } - }, - validator: null - }; - for (const [property, method] of core.decorations.server.entries()) { - this[property] = method; - } - core.registerServer(this); - } - _clone(name) { - return new internals.Server(this._core, name, this); - } - bind(context) { - Hoek.assert(typeof context === "object", "bind must be an object"); - this.realm.settings.bind = context; - } - control(server) { - Hoek.assert(server instanceof internals.Server, "Can only control Server objects"); - this._core.controlled = this._core.controlled ?? []; - this._core.controlled.push(server); - } - decoder(encoding, decoder) { - return this._core.compression.addDecoder(encoding, decoder); - } - decorate(type, property, method, options2 = {}) { - Hoek.assert(this._core.decorations.public[type], "Unknown decoration type:", type); - Hoek.assert(property, "Missing decoration property name"); - Hoek.assert(typeof property === "string" || typeof property === "symbol", "Decoration property must be a string or a symbol"); - const propertyName = property.toString(); - Hoek.assert(propertyName[0] !== "_", "Property name cannot begin with an underscore:", propertyName); - const existing = this._core.decorations[type].get(property); - if (options2.extend) { - Hoek.assert(type !== "handler", "Cannot extend handler decoration:", propertyName); - Hoek.assert(existing, `Cannot extend missing ${type} decoration: ${propertyName}`); - Hoek.assert(typeof method === "function", `Extended ${type} decoration method must be a function: ${propertyName}`); - method = method(existing); - } else { - Hoek.assert(existing === void 0, `${type[0].toUpperCase() + type.slice(1)} decoration already defined: ${propertyName}`); - } - if (type === "handler") { - Hoek.assert(typeof method === "function", "Handler must be a function:", propertyName); - Hoek.assert(!method.defaults || typeof method.defaults === "object" || typeof method.defaults === "function", "Handler defaults property must be an object or function"); - Hoek.assert(!options2.extend, "Cannot extend handler decoration:", propertyName); - } else if (type === "request") { - Hoek.assert(!this._core.Request.reserved.includes(property), "Cannot override the built-in request interface decoration:", propertyName); - if (options2.apply) { - this._core.decorations.requestApply = this._core.decorations.requestApply ?? /* @__PURE__ */ new Map(); - this._core.decorations.requestApply.set(property, method); - } else { - this._core.Request.prototype[property] = method; - } - } else if (type === "response") { - Hoek.assert(!this._core.Response.reserved.includes(property), "Cannot override the built-in response interface decoration:", propertyName); - this._core.Response.prototype[property] = method; - } else if (type === "toolkit") { - Hoek.assert(!Toolkit.reserved.includes(property), "Cannot override the built-in toolkit decoration:", propertyName); - this._core.toolkit.decorate(property, method); - } else { - if (typeof property === "string") { - Hoek.assert(!Object.getOwnPropertyNames(internals.Server.prototype).includes(property), "Cannot override the built-in server interface method:", propertyName); - } else { - Hoek.assert(!Object.getOwnPropertySymbols(internals.Server.prototype).includes(property), "Cannot override the built-in server interface method:", propertyName); - } - this._core.instances.forEach((server) => { - server[property] = method; - }); - } - this._core.decorations[type].set(property, method); - this._core.decorations.public[type].push(property); - } - dependency(dependencies, after) { - Hoek.assert(this.realm.plugin, "Cannot call dependency() outside of a plugin"); - Hoek.assert(!after || typeof after === "function", "Invalid after method"); - if (typeof dependencies === "string") { - dependencies = { [dependencies]: "*" }; - } else if (Array.isArray(dependencies)) { - const map = {}; - for (const dependency of dependencies) { - map[dependency] = "*"; - } - dependencies = map; - } - this._core.dependencies.push({ plugin: this.realm.plugin, deps: dependencies }); - if (after) { - this.ext("onPreStart", after, { after: Object.keys(dependencies) }); - } - } - encoder(encoding, encoder3) { - return this._core.compression.addEncoder(encoding, encoder3); - } - event(event) { - this._core.events.registerEvent(event); - } - expose(key, value, options2 = {}) { - Hoek.assert(this.realm.plugin, "Cannot call expose() outside of a plugin"); - let plugin2 = this.realm.plugin; - if (plugin2[0] === "@" && options2.scope !== true) { - plugin2 = plugin2.replace(/^@([^/]+)\//, ($0, $1) => { - return !options2.scope ? "" : `${$1}__`; - }); - } - this._core.plugins[plugin2] = this._core.plugins[plugin2] ?? {}; - if (typeof key === "string") { - this._core.plugins[plugin2][key] = value; - } else { - Hoek.merge(this._core.plugins[plugin2], key); - } - } - ext(events, method, options2) { - let promise; - if (typeof events === "string") { - if (!method) { - const team = new Teamwork.Team(); - method = (request, h2) => { - team.attend(request); - return h2.continue; - }; - promise = team.work; - } - events = { type: events, method, options: options2 }; - } - events = Config.apply("exts", events); - for (const event of events) { - this._ext(event); - } - return promise; - } - _ext(event) { - event = Object.assign({}, event); - event.realm = this.realm; - const type = event.type; - if (!this._core.extensions.server[type]) { - if (event.options.sandbox === "plugin") { - Hoek.assert(this.realm._extensions[type], "Unknown event type", type); - return this.realm._extensions[type].add(event); - } - Hoek.assert(this._core.extensions.route[type], "Unknown event type", type); - return this._core.extensions.route[type].add(event); - } - Hoek.assert(!event.options.sandbox, "Cannot specify sandbox option for server extension"); - Hoek.assert(type !== "onPreStart" || this._core.phase === "stopped", "Cannot add onPreStart (after) extension after the server was initialized"); - event.server = this; - this._core.extensions.server[type].add(event); - } - async inject(options2) { - let settings = options2; - if (typeof settings === "string") { - settings = { url: settings }; - } - if (!settings.authority || settings.auth || settings.app || settings.plugins || settings.allowInternals !== void 0) { - settings = Object.assign({}, settings); - delete settings.auth; - delete settings.app; - delete settings.plugins; - delete settings.allowInternals; - settings.authority = settings.authority ?? this._core.info.host + ":" + this._core.info.port; - } - Hoek.assert(!options2.credentials, "options.credentials no longer supported (use options.auth)"); - if (options2.auth) { - Hoek.assert(typeof options2.auth === "object", "options.auth must be an object"); - Hoek.assert(options2.auth.credentials, "options.auth.credentials is missing"); - Hoek.assert(options2.auth.strategy, "options.auth.strategy is missing"); - } - const needle = this._core._dispatch({ - auth: options2.auth, - allowInternals: options2.allowInternals, - app: options2.app, - plugins: options2.plugins, - isInjected: true - }); - const res = await Shot.inject(needle, settings); - const custom = res.raw.res[Config.symbol]; - if (custom) { - delete res.raw.res[Config.symbol]; - res.request = custom.request; - if (custom.error) { - throw custom.error; - } - if (custom.result !== void 0) { - res.result = custom.result; - } - } - if (res.result === void 0) { - res.result = res.payload; - } - return res; - } - log(tags, data) { - return this._core.log(tags, data); - } - lookup(id) { - Hoek.assert(id && typeof id === "string", "Invalid route id:", id); - const record2 = this._core.router.ids.get(id); - if (!record2) { - return null; - } - return record2.route.public; - } - match(method, path8, host) { - Hoek.assert(method && typeof method === "string", "Invalid method:", method); - Hoek.assert(path8 && typeof path8 === "string" && path8[0] === "/", "Invalid path:", path8); - Hoek.assert(!host || typeof host === "string", "Invalid host:", host); - const match = this._core.router.route(method.toLowerCase(), path8, host); - Hoek.assert(match !== this._core.router.specials.badRequest, "Invalid path:", path8); - if (match === this._core.router.specials.notFound) { - return null; - } - return match.route.public; - } - method(name, method, options2 = {}) { - return this._core.methods.add(name, method, options2, this.realm); - } - path(relativeTo) { - Hoek.assert(relativeTo && typeof relativeTo === "string", "relativeTo must be a non-empty string"); - this.realm.settings.files.relativeTo = relativeTo; - } - async register(plugins, options2 = {}) { - if (this.realm.modifiers.route.prefix || this.realm.modifiers.route.vhost) { - options2 = Hoek.clone(options2); - options2.routes = options2.routes ?? {}; - options2.routes.prefix = (this.realm.modifiers.route.prefix ?? "") + (options2.routes.prefix ?? "") || void 0; - options2.routes.vhost = this.realm.modifiers.route.vhost ?? options2.routes.vhost; - } - options2 = Config.apply("register", options2); - ++this._core.registring; - try { - const items = [].concat(plugins); - for (let item of items) { - if (!item.plugin) { - item = { - plugin: item - }; - } else if (!item.plugin.register) { - item = { - options: item.options, - once: item.once, - routes: item.routes, - plugin: item.plugin.plugin - }; - } else if (typeof item === "function") { - item = Object.assign({}, item); - } - item = Config.apply("plugin", item); - const name = item.plugin.name ?? item.plugin.pkg.name; - const clone2 = this._clone(name); - clone2.realm.modifiers.route.prefix = item.routes.prefix ?? options2.routes.prefix; - clone2.realm.modifiers.route.vhost = item.routes.vhost ?? options2.routes.vhost; - clone2.realm.pluginOptions = item.options ?? {}; - const requirements = item.plugin.requirements; - Hoek.assert(!requirements.node || Config.versionMatch(process.version, requirements.node), "Plugin", name, "requires node version", requirements.node, "but found", process.version); - Hoek.assert(!requirements.hapi || Config.versionMatch(this.version, requirements.hapi), "Plugin", name, "requires hapi version", requirements.hapi, "but found", this.version); - if (this._core.registrations[name]) { - if (item.plugin.once || item.once || options2.once) { - continue; - } - Hoek.assert(item.plugin.multiple, "Plugin", name, "already registered"); - } else { - this._core.registrations[name] = { - version: item.plugin.version ?? item.plugin.pkg.version, - name, - options: item.options - }; - } - if (item.plugin.dependencies) { - clone2.dependency(item.plugin.dependencies); - } - await item.plugin.register(clone2, item.options ?? {}); - } - } finally { - --this._core.registring; - } - return this; - } - route(options2) { - Hoek.assert(typeof options2 === "object", "Invalid route options"); - options2 = [].concat(options2); - for (const config2 of options2) { - if (Array.isArray(config2.method)) { - for (const method of config2.method) { - const settings = Object.assign({}, config2); - settings.method = method; - this._addRoute(settings, this); - } - } else { - this._addRoute(config2, this); - } - } - } - _addRoute(config2, server) { - const route2 = new Route(config2, server); - const vhosts = [].concat(route2.settings.vhost ?? "*"); - for (const vhost of vhosts) { - const record2 = this._core.router.add({ method: route2.method, path: route2.path, vhost, analysis: route2._analysis, id: route2.settings.id }, route2); - route2.fingerprint = record2.fingerprint; - route2.params = record2.params; - } - this.events.emit("route", route2.public); - Cors.options(route2.public, server); - } - rules(processor, options2 = {}) { - Hoek.assert(!this.realm._rules, "Server realm rules already defined"); - const settings = Config.apply("rules", options2); - if (settings.validate) { - const schema = settings.validate.schema; - settings.validate.schema = Validation.compile(schema, null, this.realm, this._core); - } - this.realm._rules = { processor, settings }; - } - state(name, options2) { - this.states.add(name, options2); - } - table(host) { - return this._core.router.table(host); - } - validator(validator) { - Hoek.assert(!this.realm.validator, "Validator already set"); - this.realm.validator = Validation.validator(validator); - } - start() { - return this._core._start(); - } - initialize() { - return this._core._initialize(); - } - stop(options2) { - return this._core._stop(options2); - } - }; - internals.cache = (plugin2) => { - const policy = function(options2, _segment) { - return this._core._cachePolicy(options2, _segment, plugin2.realm); - }; - policy.provision = async (opts) => { - const clients = plugin2._core._createCache(opts); - if (["initialized", "starting", "started"].includes(plugin2._core.phase)) { - await Promise.all(clients.map((client) => client.start())); - } - }; - return policy; - }; - } -}); -var require_lib34 = __commonJS({ - "node_modules/.deno/@hapi+hapi@21.4.3/node_modules/@hapi/hapi/lib/index.js"(exports2) { - "use strict"; - var Server3 = require_server(); - exports2.Server = Server3; - exports2.server = Server3; - } -}); -var require_lru_cache2 = __commonJS({ - "node_modules/.deno/lru-cache@7.18.3/node_modules/lru-cache/index.js"(exports2, module14) { - var perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date; - var hasAbortController = typeof AbortController === "function"; - var AC = hasAbortController ? AbortController : class AbortController { - constructor() { - this.signal = new AS(); - } - abort(reason = new Error("This operation was aborted")) { - this.signal.reason = this.signal.reason || reason; - this.signal.aborted = true; - this.signal.dispatchEvent({ - type: "abort", - target: this.signal - }); - } - }; - var hasAbortSignal = typeof AbortSignal === "function"; - var hasACAbortSignal = typeof AC.AbortSignal === "function"; - var AS = hasAbortSignal ? AbortSignal : hasACAbortSignal ? AC.AbortController : class AbortSignal { - constructor() { - this.reason = void 0; - this.aborted = false; - this._listeners = []; - } - dispatchEvent(e2) { - if (e2.type === "abort") { - this.aborted = true; - this.onabort(e2); - this._listeners.forEach((f) => f(e2), this); - } - } - onabort() { - } - addEventListener(ev, fn) { - if (ev === "abort") { - this._listeners.push(fn); - } - } - removeEventListener(ev, fn) { - if (ev === "abort") { - this._listeners = this._listeners.filter((f) => f !== fn); - } - } - }; - var warned = /* @__PURE__ */ new Set(); - var deprecatedOption = (opt, instead) => { - const code2 = `LRU_CACHE_OPTION_${opt}`; - if (shouldWarn(code2)) { - warn(code2, `${opt} option`, `options.${instead}`, LRUCache); - } - }; - var deprecatedMethod = (method, instead) => { - const code2 = `LRU_CACHE_METHOD_${method}`; - if (shouldWarn(code2)) { - const { prototype } = LRUCache; - const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, method); - warn(code2, `${method} method`, `cache.${instead}()`, get2); - } - }; - var deprecatedProperty = (field, instead) => { - const code2 = `LRU_CACHE_PROPERTY_${field}`; - if (shouldWarn(code2)) { - const { prototype } = LRUCache; - const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, field); - warn(code2, `${field} property`, `cache.${instead}`, get2); - } - }; - var emitWarning = (...a) => { - typeof process === "object" && process && typeof process.emitWarning === "function" ? process.emitWarning(...a) : console.error(...a); - }; - var shouldWarn = (code2) => !warned.has(code2); - var warn = (code2, what, instead, fn) => { - warned.add(code2); - const msg = `The ${what} is deprecated. Please use ${instead} instead.`; - emitWarning(msg, "DeprecationWarning", code2, fn); - }; - var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n); - var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null; - var ZeroArray = class extends Array { - constructor(size) { - super(size); - this.fill(0); - } - }; - var Stack = class { - constructor(max) { - if (max === 0) { - return []; - } - const UintArray = getUintArray(max); - this.heap = new UintArray(max); - this.length = 0; - } - push(n) { - this.heap[this.length++] = n; - } - pop() { - return this.heap[--this.length]; - } - }; - var LRUCache = class _LRUCache { - constructor(options2 = {}) { - const { - max = 0, - ttl, - ttlResolution = 1, - ttlAutopurge, - updateAgeOnGet, - updateAgeOnHas, - allowStale, - dispose, - disposeAfter, - noDisposeOnSet, - noUpdateTTL, - maxSize = 0, - maxEntrySize = 0, - sizeCalculation, - fetchMethod, - fetchContext, - noDeleteOnFetchRejection, - noDeleteOnStaleGet, - allowStaleOnFetchRejection, - allowStaleOnFetchAbort, - ignoreFetchAbort - } = options2; - const { length: length2, maxAge: maxAge2, stale } = options2 instanceof _LRUCache ? {} : options2; - if (max !== 0 && !isPosInt(max)) { - throw new TypeError("max option must be a nonnegative integer"); - } - const UintArray = max ? getUintArray(max) : Array; - if (!UintArray) { - throw new Error("invalid max value: " + max); - } - this.max = max; - this.maxSize = maxSize; - this.maxEntrySize = maxEntrySize || this.maxSize; - this.sizeCalculation = sizeCalculation || length2; - if (this.sizeCalculation) { - if (!this.maxSize && !this.maxEntrySize) { - throw new TypeError( - "cannot set sizeCalculation without setting maxSize or maxEntrySize" - ); - } - if (typeof this.sizeCalculation !== "function") { - throw new TypeError("sizeCalculation set to non-function"); - } - } - this.fetchMethod = fetchMethod || null; - if (this.fetchMethod && typeof this.fetchMethod !== "function") { - throw new TypeError( - "fetchMethod must be a function if specified" - ); - } - this.fetchContext = fetchContext; - if (!this.fetchMethod && fetchContext !== void 0) { - throw new TypeError( - "cannot set fetchContext without fetchMethod" - ); - } - this.keyMap = /* @__PURE__ */ new Map(); - this.keyList = new Array(max).fill(null); - this.valList = new Array(max).fill(null); - this.next = new UintArray(max); - this.prev = new UintArray(max); - this.head = 0; - this.tail = 0; - this.free = new Stack(max); - this.initialFill = 1; - this.size = 0; - if (typeof dispose === "function") { - this.dispose = dispose; - } - if (typeof disposeAfter === "function") { - this.disposeAfter = disposeAfter; - this.disposed = []; - } else { - this.disposeAfter = null; - this.disposed = null; - } - this.noDisposeOnSet = !!noDisposeOnSet; - this.noUpdateTTL = !!noUpdateTTL; - this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection; - this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection; - this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort; - this.ignoreFetchAbort = !!ignoreFetchAbort; - if (this.maxEntrySize !== 0) { - if (this.maxSize !== 0) { - if (!isPosInt(this.maxSize)) { - throw new TypeError( - "maxSize must be a positive integer if specified" - ); - } - } - if (!isPosInt(this.maxEntrySize)) { - throw new TypeError( - "maxEntrySize must be a positive integer if specified" - ); - } - this.initializeSizeTracking(); - } - this.allowStale = !!allowStale || !!stale; - this.noDeleteOnStaleGet = !!noDeleteOnStaleGet; - this.updateAgeOnGet = !!updateAgeOnGet; - this.updateAgeOnHas = !!updateAgeOnHas; - this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1; - this.ttlAutopurge = !!ttlAutopurge; - this.ttl = ttl || maxAge2 || 0; - if (this.ttl) { - if (!isPosInt(this.ttl)) { - throw new TypeError( - "ttl must be a positive integer if specified" - ); - } - this.initializeTTLTracking(); - } - if (this.max === 0 && this.ttl === 0 && this.maxSize === 0) { - throw new TypeError( - "At least one of max, maxSize, or ttl is required" - ); - } - if (!this.ttlAutopurge && !this.max && !this.maxSize) { - const code2 = "LRU_CACHE_UNBOUNDED"; - if (shouldWarn(code2)) { - warned.add(code2); - const msg = "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption."; - emitWarning(msg, "UnboundedCacheWarning", code2, _LRUCache); - } - } - if (stale) { - deprecatedOption("stale", "allowStale"); - } - if (maxAge2) { - deprecatedOption("maxAge", "ttl"); - } - if (length2) { - deprecatedOption("length", "sizeCalculation"); - } - } - getRemainingTTL(key) { - return this.has(key, { updateAgeOnHas: false }) ? Infinity : 0; - } - initializeTTLTracking() { - this.ttls = new ZeroArray(this.max); - this.starts = new ZeroArray(this.max); - this.setItemTTL = (index, ttl, start = perf.now()) => { - this.starts[index] = ttl !== 0 ? start : 0; - this.ttls[index] = ttl; - if (ttl !== 0 && this.ttlAutopurge) { - const t = setTimeout(() => { - if (this.isStale(index)) { - this.delete(this.keyList[index]); - } - }, ttl + 1); - if (t.unref) { - t.unref(); - } - } - }; - this.updateItemAge = (index) => { - this.starts[index] = this.ttls[index] !== 0 ? perf.now() : 0; - }; - this.statusTTL = (status, index) => { - if (status) { - status.ttl = this.ttls[index]; - status.start = this.starts[index]; - status.now = cachedNow || getNow(); - status.remainingTTL = status.now + status.ttl - status.start; - } - }; - let cachedNow = 0; - const getNow = () => { - const n = perf.now(); - if (this.ttlResolution > 0) { - cachedNow = n; - const t = setTimeout( - () => cachedNow = 0, - this.ttlResolution - ); - if (t.unref) { - t.unref(); - } - } - return n; - }; - this.getRemainingTTL = (key) => { - const index = this.keyMap.get(key); - if (index === void 0) { - return 0; - } - return this.ttls[index] === 0 || this.starts[index] === 0 ? Infinity : this.starts[index] + this.ttls[index] - (cachedNow || getNow()); - }; - this.isStale = (index) => { - return this.ttls[index] !== 0 && this.starts[index] !== 0 && (cachedNow || getNow()) - this.starts[index] > this.ttls[index]; - }; - } - updateItemAge(_index) { - } - statusTTL(_status, _index) { - } - setItemTTL(_index, _ttl, _start) { - } - isStale(_index) { - return false; - } - initializeSizeTracking() { - this.calculatedSize = 0; - this.sizes = new ZeroArray(this.max); - this.removeItemSize = (index) => { - this.calculatedSize -= this.sizes[index]; - this.sizes[index] = 0; - }; - this.requireSize = (k, v2, size, sizeCalculation) => { - if (this.isBackgroundFetch(v2)) { - return 0; - } - if (!isPosInt(size)) { - if (sizeCalculation) { - if (typeof sizeCalculation !== "function") { - throw new TypeError("sizeCalculation must be a function"); - } - size = sizeCalculation(v2, k); - if (!isPosInt(size)) { - throw new TypeError( - "sizeCalculation return invalid (expect positive integer)" - ); - } - } else { - throw new TypeError( - "invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set." - ); - } - } - return size; - }; - this.addItemSize = (index, size, status) => { - this.sizes[index] = size; - if (this.maxSize) { - const maxSize = this.maxSize - this.sizes[index]; - while (this.calculatedSize > maxSize) { - this.evict(true); - } - } - this.calculatedSize += this.sizes[index]; - if (status) { - status.entrySize = size; - status.totalCalculatedSize = this.calculatedSize; - } - }; - } - removeItemSize(_index) { - } - addItemSize(_index, _size2) { - } - requireSize(_k, _v, size, sizeCalculation) { - if (size || sizeCalculation) { - throw new TypeError( - "cannot set size without setting maxSize or maxEntrySize on cache" - ); - } - } - *indexes({ allowStale = this.allowStale } = {}) { - if (this.size) { - for (let i2 = this.tail; true; ) { - if (!this.isValidIndex(i2)) { - break; - } - if (allowStale || !this.isStale(i2)) { - yield i2; - } - if (i2 === this.head) { - break; - } else { - i2 = this.prev[i2]; - } - } - } - } - *rindexes({ allowStale = this.allowStale } = {}) { - if (this.size) { - for (let i2 = this.head; true; ) { - if (!this.isValidIndex(i2)) { - break; - } - if (allowStale || !this.isStale(i2)) { - yield i2; - } - if (i2 === this.tail) { - break; - } else { - i2 = this.next[i2]; - } - } - } - } - isValidIndex(index) { - return index !== void 0 && this.keyMap.get(this.keyList[index]) === index; - } - *entries() { - for (const i2 of this.indexes()) { - if (this.valList[i2] !== void 0 && this.keyList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield [this.keyList[i2], this.valList[i2]]; - } - } - } - *rentries() { - for (const i2 of this.rindexes()) { - if (this.valList[i2] !== void 0 && this.keyList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield [this.keyList[i2], this.valList[i2]]; - } - } - } - *keys() { - for (const i2 of this.indexes()) { - if (this.keyList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield this.keyList[i2]; - } - } - } - *rkeys() { - for (const i2 of this.rindexes()) { - if (this.keyList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield this.keyList[i2]; - } - } - } - *values() { - for (const i2 of this.indexes()) { - if (this.valList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield this.valList[i2]; - } - } - } - *rvalues() { - for (const i2 of this.rindexes()) { - if (this.valList[i2] !== void 0 && !this.isBackgroundFetch(this.valList[i2])) { - yield this.valList[i2]; - } - } - } - [Symbol.iterator]() { - return this.entries(); - } - find(fn, getOptions) { - for (const i2 of this.indexes()) { - const v2 = this.valList[i2]; - const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - if (value === void 0) continue; - if (fn(value, this.keyList[i2], this)) { - return this.get(this.keyList[i2], getOptions); - } - } - } - forEach(fn, thisp = this) { - for (const i2 of this.indexes()) { - const v2 = this.valList[i2]; - const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - if (value === void 0) continue; - fn.call(thisp, value, this.keyList[i2], this); - } - } - rforEach(fn, thisp = this) { - for (const i2 of this.rindexes()) { - const v2 = this.valList[i2]; - const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - if (value === void 0) continue; - fn.call(thisp, value, this.keyList[i2], this); - } - } - get prune() { - deprecatedMethod("prune", "purgeStale"); - return this.purgeStale; - } - purgeStale() { - let deleted = false; - for (const i2 of this.rindexes({ allowStale: true })) { - if (this.isStale(i2)) { - this.delete(this.keyList[i2]); - deleted = true; - } - } - return deleted; - } - dump() { - const arr = []; - for (const i2 of this.indexes({ allowStale: true })) { - const key = this.keyList[i2]; - const v2 = this.valList[i2]; - const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - if (value === void 0) continue; - const entry = { value }; - if (this.ttls) { - entry.ttl = this.ttls[i2]; - const age = perf.now() - this.starts[i2]; - entry.start = Math.floor(Date.now() - age); - } - if (this.sizes) { - entry.size = this.sizes[i2]; - } - arr.unshift([key, entry]); - } - return arr; - } - load(arr) { - this.clear(); - for (const [key, entry] of arr) { - if (entry.start) { - const age = Date.now() - entry.start; - entry.start = perf.now() - age; - } - this.set(key, entry.value, entry); - } - } - dispose(_v, _k, _reason) { - } - set(k, v2, { - ttl = this.ttl, - start, - noDisposeOnSet = this.noDisposeOnSet, - size = 0, - sizeCalculation = this.sizeCalculation, - noUpdateTTL = this.noUpdateTTL, - status - } = {}) { - size = this.requireSize(k, v2, size, sizeCalculation); - if (this.maxEntrySize && size > this.maxEntrySize) { - if (status) { - status.set = "miss"; - status.maxEntrySizeExceeded = true; - } - this.delete(k); - return this; - } - let index = this.size === 0 ? void 0 : this.keyMap.get(k); - if (index === void 0) { - index = this.newIndex(); - this.keyList[index] = k; - this.valList[index] = v2; - this.keyMap.set(k, index); - this.next[this.tail] = index; - this.prev[index] = this.tail; - this.tail = index; - this.size++; - this.addItemSize(index, size, status); - if (status) { - status.set = "add"; - } - noUpdateTTL = false; - } else { - this.moveToTail(index); - const oldVal = this.valList[index]; - if (v2 !== oldVal) { - if (this.isBackgroundFetch(oldVal)) { - oldVal.__abortController.abort(new Error("replaced")); - } else { - if (!noDisposeOnSet) { - this.dispose(oldVal, k, "set"); - if (this.disposeAfter) { - this.disposed.push([oldVal, k, "set"]); - } - } - } - this.removeItemSize(index); - this.valList[index] = v2; - this.addItemSize(index, size, status); - if (status) { - status.set = "replace"; - const oldValue = oldVal && this.isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal; - if (oldValue !== void 0) status.oldValue = oldValue; - } - } else if (status) { - status.set = "update"; - } - } - if (ttl !== 0 && this.ttl === 0 && !this.ttls) { - this.initializeTTLTracking(); - } - if (!noUpdateTTL) { - this.setItemTTL(index, ttl, start); - } - this.statusTTL(status, index); - if (this.disposeAfter) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); - } - } - return this; - } - newIndex() { - if (this.size === 0) { - return this.tail; - } - if (this.size === this.max && this.max !== 0) { - return this.evict(false); - } - if (this.free.length !== 0) { - return this.free.pop(); - } - return this.initialFill++; - } - pop() { - if (this.size) { - const val = this.valList[this.head]; - this.evict(true); - return val; - } - } - evict(free) { - const head = this.head; - const k = this.keyList[head]; - const v2 = this.valList[head]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(new Error("evicted")); - } else { - this.dispose(v2, k, "evict"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "evict"]); - } - } - this.removeItemSize(head); - if (free) { - this.keyList[head] = null; - this.valList[head] = null; - this.free.push(head); - } - this.head = this.next[head]; - this.keyMap.delete(k); - this.size--; - return head; - } - has(k, { updateAgeOnHas = this.updateAgeOnHas, status } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0) { - if (!this.isStale(index)) { - if (updateAgeOnHas) { - this.updateItemAge(index); - } - if (status) status.has = "hit"; - this.statusTTL(status, index); - return true; - } else if (status) { - status.has = "stale"; - this.statusTTL(status, index); - } - } else if (status) { - status.has = "miss"; - } - return false; - } - // like get(), but without any LRU updating or TTL expiration - peek(k, { allowStale = this.allowStale } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0 && (allowStale || !this.isStale(index))) { - const v2 = this.valList[index]; - return this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - } - } - backgroundFetch(k, index, options2, context) { - const v2 = index === void 0 ? void 0 : this.valList[index]; - if (this.isBackgroundFetch(v2)) { - return v2; - } - const ac = new AC(); - if (options2.signal) { - options2.signal.addEventListener( - "abort", - () => ac.abort(options2.signal.reason) - ); - } - const fetchOpts = { - signal: ac.signal, - options: options2, - context - }; - const cb = (v3, updateCache = false) => { - const { aborted: aborted2 } = ac.signal; - const ignoreAbort = options2.ignoreFetchAbort && v3 !== void 0; - if (options2.status) { - if (aborted2 && !updateCache) { - options2.status.fetchAborted = true; - options2.status.fetchError = ac.signal.reason; - if (ignoreAbort) options2.status.fetchAbortIgnored = true; - } else { - options2.status.fetchResolved = true; - } - } - if (aborted2 && !ignoreAbort && !updateCache) { - return fetchFail(ac.signal.reason); - } - if (this.valList[index] === p) { - if (v3 === void 0) { - if (p.__staleWhileFetching) { - this.valList[index] = p.__staleWhileFetching; - } else { - this.delete(k); - } - } else { - if (options2.status) options2.status.fetchUpdated = true; - this.set(k, v3, fetchOpts.options); - } - } - return v3; - }; - const eb = (er) => { - if (options2.status) { - options2.status.fetchRejected = true; - options2.status.fetchError = er; - } - return fetchFail(er); - }; - const fetchFail = (er) => { - const { aborted: aborted2 } = ac.signal; - const allowStaleAborted = aborted2 && options2.allowStaleOnFetchAbort; - const allowStale = allowStaleAborted || options2.allowStaleOnFetchRejection; - const noDelete = allowStale || options2.noDeleteOnFetchRejection; - if (this.valList[index] === p) { - const del = !noDelete || p.__staleWhileFetching === void 0; - if (del) { - this.delete(k); - } else if (!allowStaleAborted) { - this.valList[index] = p.__staleWhileFetching; - } - } - if (allowStale) { - if (options2.status && p.__staleWhileFetching !== void 0) { - options2.status.returnedStale = true; - } - return p.__staleWhileFetching; - } else if (p.__returned === p) { - throw er; - } - }; - const pcall = (res, rej) => { - this.fetchMethod(k, v2, fetchOpts).then((v3) => res(v3), rej); - ac.signal.addEventListener("abort", () => { - if (!options2.ignoreFetchAbort || options2.allowStaleOnFetchAbort) { - res(); - if (options2.allowStaleOnFetchAbort) { - res = (v3) => cb(v3, true); - } - } - }); - }; - if (options2.status) options2.status.fetchDispatched = true; - const p = new Promise(pcall).then(cb, eb); - p.__abortController = ac; - p.__staleWhileFetching = v2; - p.__returned = null; - if (index === void 0) { - this.set(k, p, { ...fetchOpts.options, status: void 0 }); - index = this.keyMap.get(k); - } else { - this.valList[index] = p; - } - return p; - } - isBackgroundFetch(p) { - return p && typeof p === "object" && typeof p.then === "function" && Object.prototype.hasOwnProperty.call( - p, - "__staleWhileFetching" - ) && Object.prototype.hasOwnProperty.call(p, "__returned") && (p.__returned === p || p.__returned === null); - } - // this takes the union of get() and set() opts, because it does both - async fetch(k, { - // get options - allowStale = this.allowStale, - updateAgeOnGet = this.updateAgeOnGet, - noDeleteOnStaleGet = this.noDeleteOnStaleGet, - // set options - ttl = this.ttl, - noDisposeOnSet = this.noDisposeOnSet, - size = 0, - sizeCalculation = this.sizeCalculation, - noUpdateTTL = this.noUpdateTTL, - // fetch exclusive options - noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, - allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, - ignoreFetchAbort = this.ignoreFetchAbort, - allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, - fetchContext = this.fetchContext, - forceRefresh = false, - status, - signal - } = {}) { - if (!this.fetchMethod) { - if (status) status.fetch = "get"; - return this.get(k, { - allowStale, - updateAgeOnGet, - noDeleteOnStaleGet, - status - }); - } - const options2 = { - allowStale, - updateAgeOnGet, - noDeleteOnStaleGet, - ttl, - noDisposeOnSet, - size, - sizeCalculation, - noUpdateTTL, - noDeleteOnFetchRejection, - allowStaleOnFetchRejection, - allowStaleOnFetchAbort, - ignoreFetchAbort, - status, - signal - }; - let index = this.keyMap.get(k); - if (index === void 0) { - if (status) status.fetch = "miss"; - const p = this.backgroundFetch(k, index, options2, fetchContext); - return p.__returned = p; - } else { - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - const stale = allowStale && v2.__staleWhileFetching !== void 0; - if (status) { - status.fetch = "inflight"; - if (stale) status.returnedStale = true; - } - return stale ? v2.__staleWhileFetching : v2.__returned = v2; - } - const isStale = this.isStale(index); - if (!forceRefresh && !isStale) { - if (status) status.fetch = "hit"; - this.moveToTail(index); - if (updateAgeOnGet) { - this.updateItemAge(index); - } - this.statusTTL(status, index); - return v2; - } - const p = this.backgroundFetch(k, index, options2, fetchContext); - const hasStale = p.__staleWhileFetching !== void 0; - const staleVal = hasStale && allowStale; - if (status) { - status.fetch = hasStale && isStale ? "stale" : "refresh"; - if (staleVal && isStale) status.returnedStale = true; - } - return staleVal ? p.__staleWhileFetching : p.__returned = p; - } - } - get(k, { - allowStale = this.allowStale, - updateAgeOnGet = this.updateAgeOnGet, - noDeleteOnStaleGet = this.noDeleteOnStaleGet, - status - } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0) { - const value = this.valList[index]; - const fetching = this.isBackgroundFetch(value); - this.statusTTL(status, index); - if (this.isStale(index)) { - if (status) status.get = "stale"; - if (!fetching) { - if (!noDeleteOnStaleGet) { - this.delete(k); - } - if (status) status.returnedStale = allowStale; - return allowStale ? value : void 0; - } else { - if (status) { - status.returnedStale = allowStale && value.__staleWhileFetching !== void 0; - } - return allowStale ? value.__staleWhileFetching : void 0; - } - } else { - if (status) status.get = "hit"; - if (fetching) { - return value.__staleWhileFetching; - } - this.moveToTail(index); - if (updateAgeOnGet) { - this.updateItemAge(index); - } - return value; - } - } else if (status) { - status.get = "miss"; - } - } - connect(p, n) { - this.prev[n] = p; - this.next[p] = n; - } - moveToTail(index) { - if (index !== this.tail) { - if (index === this.head) { - this.head = this.next[index]; - } else { - this.connect(this.prev[index], this.next[index]); - } - this.connect(this.tail, index); - this.tail = index; - } - } - get del() { - deprecatedMethod("del", "delete"); - return this.delete; - } - delete(k) { - let deleted = false; - if (this.size !== 0) { - const index = this.keyMap.get(k); - if (index !== void 0) { - deleted = true; - if (this.size === 1) { - this.clear(); - } else { - this.removeItemSize(index); - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(new Error("deleted")); - } else { - this.dispose(v2, k, "delete"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "delete"]); - } - } - this.keyMap.delete(k); - this.keyList[index] = null; - this.valList[index] = null; - if (index === this.tail) { - this.tail = this.prev[index]; - } else if (index === this.head) { - this.head = this.next[index]; - } else { - this.next[this.prev[index]] = this.next[index]; - this.prev[this.next[index]] = this.prev[index]; - } - this.size--; - this.free.push(index); - } - } - } - if (this.disposed) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); - } - } - return deleted; - } - clear() { - for (const index of this.rindexes({ allowStale: true })) { - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(new Error("deleted")); - } else { - const k = this.keyList[index]; - this.dispose(v2, k, "delete"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "delete"]); - } - } - } - this.keyMap.clear(); - this.valList.fill(null); - this.keyList.fill(null); - if (this.ttls) { - this.ttls.fill(0); - this.starts.fill(0); - } - if (this.sizes) { - this.sizes.fill(0); - } - this.head = 0; - this.tail = 0; - this.initialFill = 1; - this.free.length = 0; - this.calculatedSize = 0; - this.size = 0; - if (this.disposed) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); - } - } - } - get reset() { - deprecatedMethod("reset", "clear"); - return this.clear; - } - get length() { - deprecatedProperty("length", "size"); - return this.size; - } - static get AbortController() { - return AC; - } - static get AbortSignal() { - return AS; - } - }; - module14.exports = LRUCache; - } -}); -var require_etag = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/lib/etag.js"(exports2) { - "use strict"; - var Crypto = __require2("crypto"); - var Stream = __require2("stream"); - var Util = __require2("util"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var LruCache = require_lru_cache2(); - var internals = { - pendings: /* @__PURE__ */ new Map(), - streamEnd: Util.promisify(Stream.finished) - }; - internals.computeHashed = async function(response, stat) { - const etags = response.request.server.plugins.inert._etags; - if (!etags) { - return null; - } - const path8 = response.source.path; - const cachekey = [path8, stat.ino, stat.size, stat.mtime.getTime()].join("-"); - const cachedEtag = etags.get(cachekey); - if (cachedEtag) { - return cachedEtag; - } - let promise = internals.pendings.get(cachekey); - if (promise) { - return await promise; - } - const compute = async () => { - try { - const hash3 = await internals.hashFile(response); - etags.set(cachekey, hash3); - return hash3; - } finally { - internals.pendings.delete(cachekey); - } - }; - internals.pendings.set(cachekey, promise = compute()); - return await promise; - }; - internals.hashFile = async function(response) { - const hash3 = Crypto.createHash("sha1"); - hash3.setEncoding("hex"); - const fileStream2 = response.source.file.createReadStream({ autoClose: false }); - fileStream2.pipe(hash3); - try { - await internals.streamEnd(fileStream2); - return hash3.read(); - } catch (err) { - Bounce.rethrow(err, "system"); - throw Boom5.boomify(err, { message: "Failed to hash file", data: { path: response.source.path } }); - } - }; - internals.computeSimple = function(response, stat) { - const size = stat.size.toString(16); - const mtime = stat.mtime.getTime().toString(16); - return size + "-" + mtime; - }; - exports2.apply = async function(response, stat) { - const etagMethod = response.source.settings.etagMethod; - if (etagMethod === false) { - return; - } - let etag; - if (etagMethod === "simple") { - etag = internals.computeSimple(response, stat); - } else { - etag = await internals.computeHashed(response, stat); - } - if (etag !== null) { - response.etag(etag, { vary: true }); - } - }; - exports2.Cache = LruCache; - } -}); -var require_fs = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/lib/fs.js"(exports2) { - "use strict"; - var Fs = __require2("fs"); - var Util = __require2("util"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var internals = { - methods: { - promised: ["open", "close", "fstat", "readdir"], - raw: ["createReadStream"] - }, - notFound: /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR"]) - }; - exports2.File = class { - constructor(path8) { - this.path = path8; - this.fd = null; - } - async open(mode) { - Hoek.assert(this.fd === null); - try { - this.fd = await exports2.open(this.path, mode); - } catch (err) { - const data = { path: this.path }; - if (this.path.indexOf("\0") !== -1 || internals.notFound.has(err.code)) { - throw Boom5.notFound(null, data); - } - if (err.code === "EACCES" || err.code === "EPERM") { - data.code = err.code; - throw Boom5.forbidden(null, data); - } - throw Boom5.boomify(err, { message: "Failed to open file", data }); - } - } - close() { - if (this.fd !== null) { - Bounce.background(exports2.close(this.fd)); - this.fd = null; - } - } - async stat() { - Hoek.assert(this.fd !== null); - try { - const stat = await exports2.fstat(this.fd); - if (stat.isDirectory()) { - throw Boom5.forbidden(null, { code: "EISDIR", path: this.path }); - } - return stat; - } catch (err) { - this.close(this.fd); - Bounce.rethrow(err, ["boom", "system"]); - throw Boom5.boomify(err, { message: "Failed to stat file", data: { path: this.path } }); - } - } - async openStat(mode) { - await this.open(mode); - return this.stat(); - } - createReadStream(options2) { - Hoek.assert(this.fd !== null); - options2 = Object.assign({ fd: this.fd, start: 0 }, options2); - const stream = exports2.createReadStream(this.path, options2); - if (options2.autoClose !== false) { - this.fd = null; - } - return stream; - } - }; - for (const method of internals.methods.raw) { - exports2[method] = Fs[method].bind(Fs); - } - for (const method of internals.methods.promised) { - exports2[method] = Util.promisify(Fs[method]); - } - } -}); -var require_file2 = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/lib/file.js"(exports2) { - "use strict"; - var Path = __require2("path"); - var Ammo = require_lib32(); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Validate = require_lib9(); - var Etag = require_etag(); - var Fs = require_fs(); - var internals = {}; - internals.defaultMap = { - gzip: ".gz" - }; - internals.schema = Validate.alternatives([ - Validate.string(), - Validate.func(), - Validate.object({ - path: Validate.alternatives(Validate.string(), Validate.func()).required(), - confine: Validate.alternatives(Validate.string(), Validate.boolean()).default(true), - filename: Validate.string(), - mode: Validate.string().valid("attachment", "inline").allow(false), - lookupCompressed: Validate.boolean(), - lookupMap: Validate.object().min(1).pattern(/.+/, Validate.string()), - etagMethod: Validate.string().valid("hash", "simple").allow(false), - start: Validate.number().integer().min(0).default(0), - end: Validate.number().integer().min(Validate.ref("start")) - }).with("filename", "mode") - ]); - exports2.handler = function(route2, options2) { - let settings = Validate.attempt(options2, internals.schema, "Invalid file handler options (" + route2.path + ")"); - settings = typeof options2 !== "object" ? { path: options2, confine: "." } : settings; - settings.confine = settings.confine === true ? "." : settings.confine; - Hoek.assert(typeof settings.path !== "string" || settings.path[settings.path.length - 1] !== "/", "File path cannot end with a '/':", route2.path); - const handler = (request) => { - const path8 = typeof settings.path === "function" ? settings.path(request) : settings.path; - return exports2.response(path8, settings, request); - }; - return handler; - }; - exports2.load = function(path8, request, options2) { - const response = exports2.response(path8, options2, request, true); - return internals.prepare(response); - }; - exports2.response = function(path8, options2, request, _preloaded) { - Hoek.assert(!options2.mode || ["attachment", "inline"].indexOf(options2.mode) !== -1, "options.mode must be either false, attachment, or inline"); - if (options2.confine) { - const confineDir = Path.resolve(request.route.settings.files.relativeTo, options2.confine); - path8 = Path.isAbsolute(path8) ? Path.normalize(path8) : Path.join(confineDir, path8); - if (path8.lastIndexOf(confineDir, 0) !== 0) { - path8 = null; - } - } else { - path8 = Path.isAbsolute(path8) ? Path.normalize(path8) : Path.join(request.route.settings.files.relativeTo, path8); - } - const source = { - path: path8, - settings: options2, - stat: null, - file: null - }; - const prepare = _preloaded ? null : internals.prepare; - return request.generateResponse(source, { variety: "file", marshal: internals.marshal, prepare, close: internals.close }); - }; - internals.prepare = async function(response) { - const { request, source } = response; - const { settings, path: path8 } = source; - if (path8 === null) { - throw Boom5.forbidden(null, { code: "EACCES" }); - } - const file = source.file = new Fs.File(path8); - try { - const stat = await file.openStat("r"); - const start = settings.start ?? 0; - if (settings.end !== void 0) { - response.bytes(settings.end - start + 1); - } else { - response.bytes(stat.size - start); - } - if (!response.headers["content-type"]) { - response.type(request.server.mime.path(path8).type ?? "application/octet-stream"); - } - response.header("last-modified", stat.mtime.toUTCString()); - if (settings.mode) { - const fileName = settings.filename ?? Path.basename(path8); - response.header("content-disposition", settings.mode + "; filename=" + encodeURIComponent(fileName)); - } - await Etag.apply(response, stat); - return response; - } catch (err) { - internals.close(response); - throw err; - } - }; - internals.marshal = async function(response) { - const { request, source } = response; - const { settings } = source; - if (settings.lookupCompressed && !settings.start && settings.end === void 0 && request.server.settings.compression !== false) { - const lookupMap = settings.lookupMap ?? internals.defaultMap; - const encoding = request.info.acceptEncoding; - const extension = lookupMap.hasOwnProperty(encoding) ? lookupMap[encoding] : null; - if (extension) { - const precompressed = new Fs.File(`${source.path}${extension}`); - try { - var stat = await precompressed.openStat("r"); - } catch (err) { - precompressed.close(); - Bounce.ignore(err, "boom"); - } - if (stat) { - source.file.close(); - source.file = precompressed; - response.bytes(stat.size); - response.header("content-encoding", encoding); - response.vary("accept-encoding"); - } - } - } - return internals.createStream(response); - }; - internals.addContentRange = function(response) { - const { request } = response; - let range = null; - if (request.route.settings.response.ranges) { - const length2 = response.headers["content-length"]; - if (request.headers.range && length2) { - if (!request.headers["if-range"] || request.headers["if-range"] === response.headers.etag) { - const mime = request.server.mime.type(response.headers["content-type"] || "application/octet-stream"); - const encoding = request.server.settings.compression && mime.compressible && !response.headers["content-encoding"] ? request.info.acceptEncoding : null; - if (encoding === "identity" || !encoding) { - const ranges = Ammo.header(request.headers.range, length2); - if (!ranges) { - const error2 = Boom5.rangeNotSatisfiable(); - error2.output.headers["content-range"] = "bytes */" + length2; - throw error2; - } - if (ranges.length === 1) { - range = ranges[0]; - response.code(206); - response.bytes(range.to - range.from + 1); - response.header("content-range", "bytes " + range.from + "-" + range.to + "/" + length2); - } - } - } - } - response.header("accept-ranges", "bytes"); - } - return range; - }; - internals.createStream = function(response) { - const { settings, file } = response.source; - Hoek.assert(file !== null); - const range = internals.addContentRange(response); - const options2 = { - start: settings.start ?? 0, - end: settings.end - }; - if (range) { - options2.end = range.to + options2.start; - options2.start = range.from + options2.start; - } - return file.createReadStream(options2); - }; - internals.close = function(response) { - const { source } = response; - if (source.file !== null) { - source.file.close(); - source.file = null; - } - }; - } -}); -var require_directory = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/lib/directory.js"(exports2) { - "use strict"; - var Path = __require2("path"); - var Boom5 = require_lib2(); - var Bounce = require_lib12(); - var Hoek = require_lib(); - var Validate = require_lib9(); - var File2 = require_file2(); - var Fs = require_fs(); - var internals = {}; - internals.schema = Validate.object({ - path: Validate.alternatives(Validate.array().items(Validate.string()).single(), Validate.func()).required(), - index: Validate.alternatives(Validate.boolean(), Validate.array().items(Validate.string()).single()).default(true), - listing: Validate.boolean(), - showHidden: Validate.boolean(), - redirectToSlash: Validate.boolean(), - lookupCompressed: Validate.boolean(), - lookupMap: Validate.object().min(1).pattern(/.+/, Validate.string()), - etagMethod: Validate.string().valid("hash", "simple").allow(false), - defaultExtension: Validate.string().alphanum() - }); - internals.resolvePathOption = function(result) { - if (result instanceof Error) { - throw result; - } - if (typeof result === "string") { - return [result]; - } - if (Array.isArray(result)) { - return result; - } - throw Boom5.internal("Invalid path function"); - }; - exports2.handler = function(route2, options2) { - const settings = Validate.attempt(options2, internals.schema, "Invalid directory handler options (" + route2.path + ")"); - Hoek.assert(route2.path[route2.path.length - 1] === "}", "The route path for a directory handler must end with a parameter:", route2.path); - const paramName = /\w+/.exec(route2.path.slice(route2.path.lastIndexOf("{")))[0]; - const basePath = route2.settings.files.relativeTo; - const normalized = Array.isArray(settings.path) ? settings.path : null; - const indexNames = settings.index === true ? ["index.html"] : settings.index || []; - const handler = async (request, reply) => { - const paths = normalized ?? internals.resolvePathOption(settings.path.call(null, request)); - const selection = request.params[paramName] ?? ""; - if (Path.isAbsolute(selection)) { - throw Boom5.notFound(null, {}); - } - if (selection && !settings.showHidden && internals.isFileHidden(selection)) { - throw Boom5.notFound(null, {}); - } - if (!selection && (request.server.settings.router.stripTrailingSlash || !request.path.endsWith("/"))) { - request.path += "/"; - } - const resource = request.path; - const hasTrailingSlash = resource.endsWith("/"); - const fileOptions = { - confine: null, - lookupCompressed: settings.lookupCompressed, - lookupMap: settings.lookupMap, - etagMethod: settings.etagMethod - }; - const each = async (baseDir) => { - fileOptions.confine = baseDir; - let path8 = selection; - let error2; - try { - return await File2.load(path8, request, fileOptions); - } catch (err) { - Bounce.ignore(err, "boom"); - error2 = err; - } - if (internals.isNotFound(error2)) { - if (!settings.defaultExtension) { - throw error2; - } - if (hasTrailingSlash) { - path8 = path8.slice(0, -1); - } - return await File2.load(path8 + "." + settings.defaultExtension, request, fileOptions); - } - if (internals.isDirectory(error2)) { - if (settings.redirectToSlash !== false && // Defaults to true - !request.server.settings.router.stripTrailingSlash && !hasTrailingSlash) { - return reply.redirect(resource + "/"); - } - for (const indexName of indexNames) { - const indexFile = Path.join(path8, indexName); - try { - return await File2.load(indexFile, request, fileOptions); - } catch (err) { - Bounce.ignore(err, "boom"); - if (!internals.isNotFound(err)) { - throw Boom5.internal(indexName + " is a directory", err); - } - } - } - if (settings.listing) { - return internals.generateListing(Path.join(basePath, baseDir, path8), resource, selection, hasTrailingSlash, settings, request); - } - } - throw error2; - }; - for (let i2 = 0; i2 < paths.length; ++i2) { - try { - return await each(paths[i2]); - } catch (err) { - Bounce.ignore(err, "boom"); - if (!internals.isNotFound(err) || i2 === paths.length - 1) { - throw err; - } - } - } - throw Boom5.notFound(null, {}); - }; - return handler; - }; - internals.generateListing = async function(path8, resource, selection, hasTrailingSlash, settings, request) { - let files; - try { - files = await Fs.readdir(path8); - } catch (err) { - Bounce.rethrow(err, "system"); - throw Boom5.internal("Error accessing directory", err); - } - resource = decodeURIComponent(resource); - const display = Hoek.escapeHtml(resource); - let html = "" + display + "

Directory: " + display + "

    "; - if (selection) { - const parent = resource.substring(0, resource.lastIndexOf("/", resource.length - (hasTrailingSlash ? 2 : 1))) + "/"; - html = html + '
  • Parent Directory
  • '; - } - for (const file of files) { - if (settings.showHidden || !internals.isFileHidden(file)) { - html = html + '
  • ' + Hoek.escapeHtml(file) + "
  • "; - } - } - html = html + "
"; - return request.generateResponse(html); - }; - internals.isFileHidden = function(path8) { - return /(^|[\\\/])\.([^.\\\/]|\.[^\\\/])/.test(path8); - }; - internals.pathEncode = function(path8) { - return encodeURIComponent(path8).replace(/%2F/g, "/").replace(/%5C/g, "\\"); - }; - internals.isNotFound = function(boom) { - return boom.output.statusCode === 404; - }; - internals.isDirectory = function(boom) { - return boom.output.statusCode === 403 && boom.data.code === "EISDIR"; - }; - } -}); -var require_package5 = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/package.json"(exports2, module14) { - module14.exports = { - name: "@hapi/inert", - description: "Static file and directory handlers plugin for hapi.js", - version: "7.1.0", - repository: "https://github.com/hapijs/inert.git", - main: "lib/index.js", - types: "lib/index.d.ts", - files: [ - "lib" - ], - keywords: [ - "file", - "directory", - "handler", - "hapi", - "plugin" - ], - eslintConfig: { - extends: [ - "plugin:@hapi/module" - ] - }, - dependencies: { - "@hapi/ammo": "^6.0.1", - "@hapi/boom": "^10.0.1", - "@hapi/bounce": "^3.0.1", - "@hapi/hoek": "^11.0.2", - "@hapi/validate": "^2.0.1", - "lru-cache": "^7.14.1" - }, - devDependencies: { - "@hapi/code": "^9.0.3", - "@hapi/eslint-plugin": "*", - "@hapi/file": "^3.0.0", - "@hapi/hapi": "^21.3.0", - "@hapi/lab": "^25.1.2", - "@types/node": "^14.18.37", - joi: "^17.8.3", - typescript: "^4.9.5" - }, - scripts: { - test: "lab -f -a @hapi/code -t 100 -L -Y", - "test-cov-html": "lab -f -a @hapi/code -r html -o coverage.html" - }, - license: "BSD-3-Clause" - }; - } -}); -var require_lib35 = __commonJS({ - "node_modules/.deno/@hapi+inert@7.1.0/node_modules/@hapi/inert/lib/index.js"(exports2) { - "use strict"; - var Hoek = require_lib(); - var Validate = require_lib9(); - var Directory = require_directory(); - var Etag = require_etag(); - var File2 = require_file2(); - var internals = { - schema: Validate.object({ - etagsCacheMaxSize: Validate.number().integer().min(0).default(1e3) - }).required() - }; - internals.fileMethod = function(path8, responseOptions = {}) { - if (typeof responseOptions.confine === "undefined" || responseOptions.confine === true) { - responseOptions.confine = "."; - } - Hoek.assert(responseOptions.end === void 0 || +responseOptions.start <= +responseOptions.end, "options.start must be less than or equal to options.end"); - return this.response(File2.response(path8, responseOptions, this.request)); - }; - exports2.plugin = { - pkg: require_package5(), - once: true, - requirements: { - hapi: ">=20.0.0" - }, - register(server, options2) { - Hoek.assert(Object.keys(options2).length === 0, "Inert does not support registration options"); - const settings = Validate.attempt(server.settings.plugins?.inert ?? {}, internals.schema, 'Invalid "inert" server options'); - server.expose("_etags", settings.etagsCacheMaxSize > 0 ? new Etag.Cache({ max: settings.etagsCacheMaxSize }) : null); - server.decorate("handler", "file", File2.handler); - server.decorate("handler", "directory", Directory.handler); - server.decorate("toolkit", "file", internals.fileMethod); - } - }; - } -}); -var dashboard_server_exports = {}; -__export(dashboard_server_exports, { - default: () => dashboard_server_default, - startDashboard: () => startDashboard -}); -async function startDashboard() { - const port = import_npm_nconf4.default.get("server:dashboardPort"); - const dashboardServer = new Hapi.Server({ - port, - host: import_npm_nconf4.default.get("server:host"), - routes: { - files: { - relativeTo: getDashboardPath() - } - } - }); - await dashboardServer.register(import_inert.default); - dashboardServer.route({ - method: "GET", - path: "/assets/{path*}", - handler: { - directory: { - path: "assets", - redirectToSlash: false - } - } - }); - dashboardServer.route({ - method: "GET", - path: "/dashboard", - handler: (_request, h2) => h2.file("index.html") - }); - dashboardServer.route({ - method: "GET", - path: "/dashboard/", - handler: (_request, h2) => h2.file("index.html") - }); - dashboardServer.route({ - method: "GET", - path: "/{path*}", - handler: { - directory: { - path: ".", - index: ["index.html"] - } - } - }); - await dashboardServer.start(); -} -var Hapi; -var import_inert; -var import_npm_nconf4; -var getDashboardPath; -var dashboard_server_default; -var init_dashboard_server = __esm({ - "src/serve/dashboard-server.ts"() { - "use strict"; - Hapi = __toESM(require_lib34()); - import_inert = __toESM(require_lib35()); - import_npm_nconf4 = __toESM(require_nconf()); - getDashboardPath = () => { - return path5.resolve(import.meta.dirname || process5.cwd(), "dist-dashboard"); - }; - dashboard_server_default = startDashboard; - } -}); -var isEventQueueSbpEvent2; -var esm_default5; -var init_esm9 = __esm({ - "node_modules/.deno/@sbp+okturtles.eventqueue@1.2.0/node_modules/@sbp/okturtles.eventqueue/dist/esm/index.js"() { - init_esm(); - isEventQueueSbpEvent2 = (e2) => { - return Object.prototype.hasOwnProperty.call(e2, "sbpInvocation"); - }; - esm_default5 = esm_default("sbp/selectors/register", { - "okTurtles.eventQueue/_init": function() { - this.eventQueues = /* @__PURE__ */ Object.create(null); - }, - "okTurtles.eventQueue/isWaiting": function(name) { - var _a2; - return !!((_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.length); - }, - "okTurtles.eventQueue/queuedInvocations": function(name) { - var _a2, _b; - if (name == null) { - return Object.fromEntries(Object.entries(this.eventQueues).map(([name2, events]) => [name2, events.map((event) => { - if (isEventQueueSbpEvent2(event)) { - return event.sbpInvocation; - } else { - return event.fn; - } - })])); - } - return (_b = (_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.map((event) => { - if (isEventQueueSbpEvent2(event)) { - return event.sbpInvocation; - } else { - return event.fn; - } - })) !== null && _b !== void 0 ? _b : []; - }, - "okTurtles.eventQueue/queueEvent": async function(name, invocation) { - if (!Object.prototype.hasOwnProperty.call(this.eventQueues, name)) { - this.eventQueues[name] = []; - } - const events = this.eventQueues[name]; - let accept; - const promise = new Promise((resolve82) => { - accept = resolve82; - }); - const thisEvent = typeof invocation === "function" ? { - fn: invocation, - promise - } : { - sbpInvocation: invocation, - promise - }; - events.push(thisEvent); - while (events.length > 0) { - const event = events[0]; - if (event === thisEvent) { - try { - if (typeof invocation === "function") { - return await invocation(); - } else { - return await esm_default(...invocation); - } - } finally { - accept(); - events.shift(); - } - } else { - await event.promise; - } - } - } - }); - } -}); -var listenKey2; -var esm_default6; -var init_esm10 = __esm({ - "node_modules/.deno/@sbp+okturtles.events@1.0.0/node_modules/@sbp/okturtles.events/dist/esm/index.js"() { - init_esm(); - init_esm3(); - listenKey2 = (evt) => `events/${evt}/listeners`; - esm_default6 = esm_default("sbp/selectors/register", { - "okTurtles.events/_init": function() { - this.errorHandler = (event, e2) => { - console.error(`[okTurtles.events] Error at handler for ${event}`, e2); - }; - }, - "okTurtles.events/on": function(event, handler) { - esm_default("okTurtles.data/add", listenKey2(event), handler); - return () => esm_default("okTurtles.events/off", event, handler); - }, - "okTurtles.events/once": function(event, handler) { - const cbWithOff = (...args) => { - handler(...args); - esm_default("okTurtles.events/off", event, cbWithOff); - }; - return esm_default("okTurtles.events/on", event, cbWithOff); - }, - "okTurtles.events/emit": function(event, ...data) { - var _a2; - for (const listener of esm_default("okTurtles.data/get", listenKey2(event)) || []) { - try { - listener(...data); - } catch (e2) { - (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); - } - } - }, - // almost identical to Vue.prototype.$off, except we require `event` argument - "okTurtles.events/off": function(event, handler) { - if (handler) { - esm_default("okTurtles.data/remove", listenKey2(event), handler); - } else { - esm_default("okTurtles.data/delete", listenKey2(event)); - } - }, - "okTurtles.events/setErrorHandler": function(errorHandler) { - this.errorHandler = errorHandler; - } - }); - } -}); -var require_has_flag = __commonJS({ - "node_modules/.deno/has-flag@4.0.0/node_modules/has-flag/index.js"(exports2, module14) { - "use strict"; - module14.exports = (flag, argv = process.argv) => { - const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; - const position = argv.indexOf(prefix + flag); - const terminatorPosition = argv.indexOf("--"); - return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); - }; - } -}); -var require_supports_color = __commonJS({ - "node_modules/.deno/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module14) { - "use strict"; - var os = __require2("os"); - var tty = __require2("tty"); - var hasFlag = require_has_flag(); - var { env: env2 } = process; - var forceColor; - if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { - forceColor = 0; - } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { - forceColor = 1; - } - if ("FORCE_COLOR" in env2) { - if (env2.FORCE_COLOR === "true") { - forceColor = 1; - } else if (env2.FORCE_COLOR === "false") { - forceColor = 0; - } else { - forceColor = env2.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env2.FORCE_COLOR, 10), 3); - } - } - function translateLevel(level) { - if (level === 0) { - return false; - } - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; - } - function supportsColor(haveStream, streamIsTTY) { - if (forceColor === 0) { - return 0; - } - if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { - return 3; - } - if (hasFlag("color=256")) { - return 2; - } - if (haveStream && !streamIsTTY && forceColor === void 0) { - return 0; - } - const min = forceColor || 0; - if (env2.TERM === "dumb") { - return min; - } - if (process.platform === "win32") { - const osRelease = os.release().split("."); - if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; - } - return 1; - } - if ("CI" in env2) { - if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign2) => sign2 in env2) || env2.CI_NAME === "codeship") { - return 1; - } - return min; - } - if ("TEAMCITY_VERSION" in env2) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env2.TEAMCITY_VERSION) ? 1 : 0; - } - if (env2.COLORTERM === "truecolor") { - return 3; - } - if ("TERM_PROGRAM" in env2) { - const version3 = parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10); - switch (env2.TERM_PROGRAM) { - case "iTerm.app": - return version3 >= 3 ? 3 : 2; - case "Apple_Terminal": - return 2; - } - } - if (/-256(color)?$/i.test(env2.TERM)) { - return 2; - } - if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env2.TERM)) { - return 1; - } - if ("COLORTERM" in env2) { - return 1; - } - return min; - } - function getSupportLevel(stream) { - const level = supportsColor(stream, stream && stream.isTTY); - return translateLevel(level); - } - module14.exports = { - supportsColor: getSupportLevel, - stdout: translateLevel(supportsColor(true, tty.isatty(1))), - stderr: translateLevel(supportsColor(true, tty.isatty(2))) - }; - } -}); -var require_util2 = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/util.js"(exports2, module14) { - "use strict"; - var stringReplaceAll = (string3, substring, replacer) => { - let index = string3.indexOf(substring); - if (index === -1) { - return string3; - } - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ""; - do { - returnValue += string3.substr(endIndex, index - endIndex) + substring + replacer; - endIndex = index + substringLength; - index = string3.indexOf(substring, endIndex); - } while (index !== -1); - returnValue += string3.substr(endIndex); - return returnValue; - }; - var stringEncaseCRLFWithFirstIndex = (string3, prefix, postfix, index) => { - let endIndex = 0; - let returnValue = ""; - do { - const gotCR = string3[index - 1] === "\r"; - returnValue += string3.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? "\r\n" : "\n") + postfix; - endIndex = index + 1; - index = string3.indexOf("\n", endIndex); - } while (index !== -1); - returnValue += string3.substr(endIndex); - return returnValue; - }; - module14.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex - }; - } -}); -var require_templates = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/templates.js"(exports2, module14) { - "use strict"; - var TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; - var STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; - var STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; - var ESCAPE_REGEX2 = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; - var ESCAPES = /* @__PURE__ */ new Map([ - ["n", "\n"], - ["r", "\r"], - ["t", " "], - ["b", "\b"], - ["f", "\f"], - ["v", "\v"], - ["0", "\0"], - ["\\", "\\"], - ["e", "\x1B"], - ["a", "\x07"] - ]); - function unescape(c) { - const u2 = c[0] === "u"; - const bracket = c[1] === "{"; - if (u2 && !bracket && c.length === 5 || c[0] === "x" && c.length === 3) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } - if (u2 && bracket) { - return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); - } - return ESCAPES.get(c) || c; - } - function parseArguments(name, arguments_) { - const results = []; - const chunks = arguments_.trim().split(/\s*,\s*/g); - let matches; - for (const chunk of chunks) { - const number3 = Number(chunk); - if (!Number.isNaN(number3)) { - results.push(number3); - } else if (matches = chunk.match(STRING_REGEX)) { - results.push(matches[2].replace(ESCAPE_REGEX2, (m3, escape, character) => escape ? unescape(escape) : character)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } - return results; - } - function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; - const results = []; - let matches; - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } - return results; - } - function buildStyle(chalk5, styles) { - const enabled2 = {}; - for (const layer of styles) { - for (const style of layer.styles) { - enabled2[style[0]] = layer.inverse ? null : style.slice(1); - } - } - let current = chalk5; - for (const [styleName, styles2] of Object.entries(enabled2)) { - if (!Array.isArray(styles2)) { - continue; - } - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); - } - current = styles2.length > 0 ? current[styleName](...styles2) : current[styleName]; - } - return current; - } - module14.exports = (chalk5, temporary) => { - const styles = []; - const chunks = []; - let chunk = []; - temporary.replace(TEMPLATE_REGEX, (m3, escapeCharacter, inverse, style, close, character) => { - if (escapeCharacter) { - chunk.push(unescape(escapeCharacter)); - } else if (style) { - const string3 = chunk.join(""); - chunk = []; - chunks.push(styles.length === 0 ? string3 : buildStyle(chalk5, styles)(string3)); - styles.push({ inverse, styles: parseStyle(style) }); - } else if (close) { - if (styles.length === 0) { - throw new Error("Found extraneous } in Chalk template literal"); - } - chunks.push(buildStyle(chalk5, styles)(chunk.join(""))); - chunk = []; - styles.pop(); - } else { - chunk.push(character); - } - }); - chunks.push(chunk.join("")); - if (styles.length > 0) { - const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? "" : "s"} (\`}\`)`; - throw new Error(errMessage); - } - return chunks.join(""); - }; - } -}); -var require_source = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/index.js"(exports2, module14) { - "use strict"; - var ansiStyles = require_ansi_styles(); - var { stdout: stdoutColor, stderr: stderrColor } = require_supports_color(); - var { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex - } = require_util2(); - var { isArray } = Array; - var levelMapping = [ - "ansi", - "ansi", - "ansi256", - "ansi16m" - ]; - var styles = /* @__PURE__ */ Object.create(null); - var applyOptions = (object2, options2 = {}) => { - if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) { - throw new Error("The `level` option should be an integer from 0 to 3"); - } - const colorLevel = stdoutColor ? stdoutColor.level : 0; - object2.level = options2.level === void 0 ? colorLevel : options2.level; - }; - var ChalkClass = class { - constructor(options2) { - return chalkFactory(options2); - } - }; - var chalkFactory = (options2) => { - const chalk6 = {}; - applyOptions(chalk6, options2); - chalk6.template = (...arguments_) => chalkTag(chalk6.template, ...arguments_); - Object.setPrototypeOf(chalk6, Chalk.prototype); - Object.setPrototypeOf(chalk6.template, chalk6); - chalk6.template.constructor = () => { - throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead."); - }; - chalk6.template.Instance = ChalkClass; - return chalk6.template; - }; - function Chalk(options2) { - return chalkFactory(options2); - } - for (const [styleName, style] of Object.entries(ansiStyles)) { - styles[styleName] = { - get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); - Object.defineProperty(this, styleName, { value: builder }); - return builder; - } - }; - } - styles.visible = { - get() { - const builder = createBuilder(this, this._styler, true); - Object.defineProperty(this, "visible", { value: builder }); - return builder; - } - }; - var usedModels = ["rgb", "hex", "keyword", "hsl", "hsv", "hwb", "ansi", "ansi256"]; - for (const model of usedModels) { - styles[model] = { - get() { - const { level } = this; - return function(...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; - } - for (const model of usedModels) { - const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const { level } = this; - return function(...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; - } - }; - } - var proto3 = Object.defineProperties(() => { - }, { - ...styles, - level: { - enumerable: true, - get() { - return this._generator.level; - }, - set(level) { - this._generator.level = level; - } - } - }); - var createStyler = (open, close, parent) => { - let openAll; - let closeAll; - if (parent === void 0) { - openAll = open; - closeAll = close; - } else { - openAll = parent.openAll + open; - closeAll = close + parent.closeAll; - } - return { - open, - close, - openAll, - closeAll, - parent - }; - }; - var createBuilder = (self2, _styler, _isEmpty) => { - const builder = (...arguments_) => { - if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { - return applyStyle(builder, chalkTag(builder, ...arguments_)); - } - return applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")); - }; - Object.setPrototypeOf(builder, proto3); - builder._generator = self2; - builder._styler = _styler; - builder._isEmpty = _isEmpty; - return builder; - }; - var applyStyle = (self2, string3) => { - if (self2.level <= 0 || !string3) { - return self2._isEmpty ? "" : string3; - } - let styler = self2._styler; - if (styler === void 0) { - return string3; - } - const { openAll, closeAll } = styler; - if (string3.indexOf("\x1B") !== -1) { - while (styler !== void 0) { - string3 = stringReplaceAll(string3, styler.close, styler.open); - styler = styler.parent; - } - } - const lfIndex = string3.indexOf("\n"); - if (lfIndex !== -1) { - string3 = stringEncaseCRLFWithFirstIndex(string3, closeAll, openAll, lfIndex); - } - return openAll + string3 + closeAll; - }; - var template; - var chalkTag = (chalk6, ...strings) => { - const [firstString] = strings; - if (!isArray(firstString) || !isArray(firstString.raw)) { - return strings.join(" "); - } - const arguments_ = strings.slice(1); - const parts = [firstString.raw[0]]; - for (let i2 = 1; i2 < firstString.length; i2++) { - parts.push( - String(arguments_[i2 - 1]).replace(/[{}\\]/g, "\\$&"), - String(firstString.raw[i2]) - ); - } - if (template === void 0) { - template = require_templates(); - } - return template(chalk6, parts.join("")); - }; - Object.defineProperties(Chalk.prototype, styles); - var chalk5 = Chalk(); - chalk5.supportsColor = stdoutColor; - chalk5.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 }); - chalk5.stderr.supportsColor = stderrColor; - module14.exports = chalk5; - } -}); -var SERVER_INSTANCE; -var PUBSUB_INSTANCE; -var init_instance_keys = __esm({ - "src/serve/instance-keys.ts"() { - "use strict"; - SERVER_INSTANCE = "@instance/server"; - PUBSUB_INSTANCE = "@instance/pubsub"; - } -}); -var require_err_helpers = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-helpers.js"(exports2, module14) { - "use strict"; - var isErrorLike = (err) => { - return err && typeof err.message === "string"; - }; - var getErrorCause = (err) => { - if (!err) return; - const cause = err.cause; - if (typeof cause === "function") { - const causeResult = err.cause(); - return isErrorLike(causeResult) ? causeResult : void 0; - } else { - return isErrorLike(cause) ? cause : void 0; - } - }; - var _stackWithCauses = (err, seen) => { - if (!isErrorLike(err)) return ""; - const stack = err.stack || ""; - if (seen.has(err)) { - return stack + "\ncauses have become circular..."; - } - const cause = getErrorCause(err); - if (cause) { - seen.add(err); - return stack + "\ncaused by: " + _stackWithCauses(cause, seen); - } else { - return stack; - } - }; - var stackWithCauses = (err) => _stackWithCauses(err, /* @__PURE__ */ new Set()); - var _messageWithCauses = (err, seen, skip) => { - if (!isErrorLike(err)) return ""; - const message = skip ? "" : err.message || ""; - if (seen.has(err)) { - return message + ": ..."; - } - const cause = getErrorCause(err); - if (cause) { - seen.add(err); - const skipIfVErrorStyleCause = typeof err.cause === "function"; - return message + (skipIfVErrorStyleCause ? "" : ": ") + _messageWithCauses(cause, seen, skipIfVErrorStyleCause); - } else { - return message; - } - }; - var messageWithCauses = (err) => _messageWithCauses(err, /* @__PURE__ */ new Set()); - module14.exports = { - isErrorLike, - getErrorCause, - stackWithCauses, - messageWithCauses - }; - } -}); -var require_err_proto = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-proto.js"(exports2, module14) { - "use strict"; - var seen = Symbol("circular-ref-tag"); - var rawSymbol = Symbol("pino-raw-err-ref"); - var pinoErrProto = Object.create({}, { - type: { - enumerable: true, - writable: true, - value: void 0 - }, - message: { - enumerable: true, - writable: true, - value: void 0 - }, - stack: { - enumerable: true, - writable: true, - value: void 0 - }, - aggregateErrors: { - enumerable: true, - writable: true, - value: void 0 - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; - } - } - }); - Object.defineProperty(pinoErrProto, rawSymbol, { - writable: true, - value: {} - }); - module14.exports = { - pinoErrProto, - pinoErrorSymbols: { - seen, - rawSymbol - } - }; - } -}); -var require_err = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err.js"(exports2, module14) { - "use strict"; - module14.exports = errSerializer; - var { messageWithCauses, stackWithCauses, isErrorLike } = require_err_helpers(); - var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); - var { seen } = pinoErrorSymbols; - var { toString } = Object.prototype; - function errSerializer(err) { - if (!isErrorLike(err)) { - return err; - } - err[seen] = void 0; - const _err = Object.create(pinoErrProto); - _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; - _err.message = messageWithCauses(err); - _err.stack = stackWithCauses(err); - if (Array.isArray(err.errors)) { - _err.aggregateErrors = err.errors.map((err2) => errSerializer(err2)); - } - for (const key in err) { - if (_err[key] === void 0) { - const val = err[key]; - if (isErrorLike(val)) { - if (key !== "cause" && !Object.prototype.hasOwnProperty.call(val, seen)) { - _err[key] = errSerializer(val); - } - } else { - _err[key] = val; - } - } - } - delete err[seen]; - _err.raw = err; - return _err; - } - } -}); -var require_err_with_cause = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-with-cause.js"(exports2, module14) { - "use strict"; - module14.exports = errWithCauseSerializer; - var { isErrorLike } = require_err_helpers(); - var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); - var { seen } = pinoErrorSymbols; - var { toString } = Object.prototype; - function errWithCauseSerializer(err) { - if (!isErrorLike(err)) { - return err; - } - err[seen] = void 0; - const _err = Object.create(pinoErrProto); - _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; - _err.message = err.message; - _err.stack = err.stack; - if (Array.isArray(err.errors)) { - _err.aggregateErrors = err.errors.map((err2) => errWithCauseSerializer(err2)); - } - if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) { - _err.cause = errWithCauseSerializer(err.cause); - } - for (const key in err) { - if (_err[key] === void 0) { - const val = err[key]; - if (isErrorLike(val)) { - if (!Object.prototype.hasOwnProperty.call(val, seen)) { - _err[key] = errWithCauseSerializer(val); - } - } else { - _err[key] = val; - } - } - } - delete err[seen]; - _err.raw = err; - return _err; - } - } -}); -var require_req = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/req.js"(exports2, module14) { - "use strict"; - module14.exports = { - mapHttpRequest, - reqSerializer - }; - var rawSymbol = Symbol("pino-raw-req-ref"); - var pinoReqProto = Object.create({}, { - id: { - enumerable: true, - writable: true, - value: "" - }, - method: { - enumerable: true, - writable: true, - value: "" - }, - url: { - enumerable: true, - writable: true, - value: "" - }, - query: { - enumerable: true, - writable: true, - value: "" - }, - params: { - enumerable: true, - writable: true, - value: "" - }, - headers: { - enumerable: true, - writable: true, - value: {} - }, - remoteAddress: { - enumerable: true, - writable: true, - value: "" - }, - remotePort: { - enumerable: true, - writable: true, - value: "" - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; - } - } - }); - Object.defineProperty(pinoReqProto, rawSymbol, { - writable: true, - value: {} - }); - function reqSerializer(req) { - const connection = req.info || req.socket; - const _req = Object.create(pinoReqProto); - _req.id = typeof req.id === "function" ? req.id() : req.id || (req.info ? req.info.id : void 0); - _req.method = req.method; - if (req.originalUrl) { - _req.url = req.originalUrl; - } else { - const path8 = req.path; - _req.url = typeof path8 === "string" ? path8 : req.url ? req.url.path || req.url : void 0; - } - if (req.query) { - _req.query = req.query; - } - if (req.params) { - _req.params = req.params; - } - _req.headers = req.headers; - _req.remoteAddress = connection && connection.remoteAddress; - _req.remotePort = connection && connection.remotePort; - _req.raw = req.raw || req; - return _req; - } - function mapHttpRequest(req) { - return { - req: reqSerializer(req) - }; - } - } -}); -var require_res = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/res.js"(exports2, module14) { - "use strict"; - module14.exports = { - mapHttpResponse, - resSerializer - }; - var rawSymbol = Symbol("pino-raw-res-ref"); - var pinoResProto = Object.create({}, { - statusCode: { - enumerable: true, - writable: true, - value: 0 - }, - headers: { - enumerable: true, - writable: true, - value: "" - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; - } - } - }); - Object.defineProperty(pinoResProto, rawSymbol, { - writable: true, - value: {} - }); - function resSerializer(res) { - const _res = Object.create(pinoResProto); - _res.statusCode = res.headersSent ? res.statusCode : null; - _res.headers = res.getHeaders ? res.getHeaders() : res._headers; - _res.raw = res; - return _res; - } - function mapHttpResponse(res) { - return { - res: resSerializer(res) - }; - } - } -}); -var require_pino_std_serializers = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/index.js"(exports2, module14) { - "use strict"; - var errSerializer = require_err(); - var errWithCauseSerializer = require_err_with_cause(); - var reqSerializers = require_req(); - var resSerializers = require_res(); - module14.exports = { - err: errSerializer, - errWithCause: errWithCauseSerializer, - mapHttpRequest: reqSerializers.mapHttpRequest, - mapHttpResponse: resSerializers.mapHttpResponse, - req: reqSerializers.reqSerializer, - res: resSerializers.resSerializer, - wrapErrorSerializer: function wrapErrorSerializer(customSerializer) { - if (customSerializer === errSerializer) return customSerializer; - return function wrapErrSerializer(err) { - return customSerializer(errSerializer(err)); - }; - }, - wrapRequestSerializer: function wrapRequestSerializer(customSerializer) { - if (customSerializer === reqSerializers.reqSerializer) return customSerializer; - return function wrappedReqSerializer(req) { - return customSerializer(reqSerializers.reqSerializer(req)); - }; - }, - wrapResponseSerializer: function wrapResponseSerializer(customSerializer) { - if (customSerializer === resSerializers.resSerializer) return customSerializer; - return function wrappedResSerializer(res) { - return customSerializer(resSerializers.resSerializer(res)); - }; - } - }; - } -}); -var require_caller = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/caller.js"(exports2, module14) { - "use strict"; - function noOpPrepareStackTrace(_, stack) { - return stack; - } - module14.exports = function getCallers() { - const originalPrepare = Error.prepareStackTrace; - Error.prepareStackTrace = noOpPrepareStackTrace; - const stack = new Error().stack; - Error.prepareStackTrace = originalPrepare; - if (!Array.isArray(stack)) { - return void 0; - } - const entries = stack.slice(2); - const fileNames = []; - for (const entry of entries) { - if (!entry) { - continue; - } - fileNames.push(entry.getFileName()); - } - return fileNames; - }; - } -}); -var require_validator2 = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/validator.js"(exports2, module14) { - "use strict"; - module14.exports = validator; - function validator(opts = {}) { - const { - ERR_PATHS_MUST_BE_STRINGS = () => "fast-redact - Paths must be (non-empty) strings", - ERR_INVALID_PATH = (s) => `fast-redact \u2013 Invalid path (${s})` - } = opts; - return function validate({ paths }) { - paths.forEach((s) => { - if (typeof s !== "string") { - throw Error(ERR_PATHS_MUST_BE_STRINGS()); - } - try { - if (/〇/.test(s)) throw Error(); - const expr = (s[0] === "[" ? "" : ".") + s.replace(/^\*/, "\u3007").replace(/\.\*/g, ".\u3007").replace(/\[\*\]/g, "[\u3007]"); - if (/\n|\r|;/.test(expr)) throw Error(); - if (/\/\*/.test(expr)) throw Error(); - Function(` - 'use strict' - const o = new Proxy({}, { get: () => o, set: () => { throw Error() } }); - const \u3007 = null; - o${expr} - if ([o${expr}].length !== 1) throw Error()`)(); - } catch (e2) { - throw Error(ERR_INVALID_PATH(s)); - } - }); - }; - } - } -}); -var require_rx = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/rx.js"(exports2, module14) { - "use strict"; - module14.exports = /[^.[\]]+|\[((?:.)*?)\]/g; - } -}); -var require_parse = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/parse.js"(exports2, module14) { - "use strict"; - var rx = require_rx(); - module14.exports = parse52; - function parse52({ paths }) { - const wildcards = []; - var wcLen = 0; - const secret = paths.reduce(function(o2, strPath, ix) { - var path8 = strPath.match(rx).map((p) => p.replace(/'|"|`/g, "")); - const leadingBracket = strPath[0] === "["; - path8 = path8.map((p) => { - if (p[0] === "[") return p.substr(1, p.length - 2); - else return p; - }); - const star = path8.indexOf("*"); - if (star > -1) { - const before = path8.slice(0, star); - const beforeStr = before.join("."); - const after = path8.slice(star + 1, path8.length); - const nested = after.length > 0; - wcLen++; - wildcards.push({ - before, - beforeStr, - after, - nested - }); - } else { - o2[strPath] = { - path: path8, - val: void 0, - precensored: false, - circle: "", - escPath: JSON.stringify(strPath), - leadingBracket - }; - } - return o2; - }, {}); - return { wildcards, wcLen, secret }; - } - } -}); -var require_redactor = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/redactor.js"(exports2, module14) { - "use strict"; - var rx = require_rx(); - module14.exports = redactor; - function redactor({ secret, serialize, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { - const redact = Function("o", ` - if (typeof o !== 'object' || o == null) { - ${strictImpl(strict, serialize)} - } - const { censor, secret } = this - const originalSecret = {} - const secretKeys = Object.keys(secret) - for (var i = 0; i < secretKeys.length; i++) { - originalSecret[secretKeys[i]] = secret[secretKeys[i]] - } - - ${redactTmpl(secret, isCensorFct, censorFctTakesPath)} - this.compileRestore() - ${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} - this.secret = originalSecret - ${resultTmpl(serialize)} - `).bind(state); - redact.state = state; - if (serialize === false) { - redact.restore = (o2) => state.restore(o2); - } - return redact; - } - function redactTmpl(secret, isCensorFct, censorFctTakesPath) { - return Object.keys(secret).map((path8) => { - const { escPath, leadingBracket, path: arrPath } = secret[path8]; - const skip = leadingBracket ? 1 : 0; - const delim = leadingBracket ? "" : "."; - const hops = []; - var match; - while ((match = rx.exec(path8)) !== null) { - const [, ix] = match; - const { index, input } = match; - if (index > skip) hops.push(input.substring(0, index - (ix ? 0 : 1))); - } - var existence = hops.map((p) => `o${delim}${p}`).join(" && "); - if (existence.length === 0) existence += `o${delim}${path8} != null`; - else existence += ` && o${delim}${path8} != null`; - const circularDetection = ` - switch (true) { - ${hops.reverse().map((p) => ` - case o${delim}${p} === censor: - secret[${escPath}].circle = ${JSON.stringify(p)} - break - `).join("\n")} - } - `; - const censorArgs = censorFctTakesPath ? `val, ${JSON.stringify(arrPath)}` : `val`; - return ` - if (${existence}) { - const val = o${delim}${path8} - if (val === censor) { - secret[${escPath}].precensored = true - } else { - secret[${escPath}].val = val - o${delim}${path8} = ${isCensorFct ? `censor(${censorArgs})` : "censor"} - ${circularDetection} - } - } - `; - }).join("\n"); - } - function dynamicRedactTmpl(hasWildcards, isCensorFct, censorFctTakesPath) { - return hasWildcards === true ? ` - { - const { wildcards, wcLen, groupRedact, nestedRedact } = this - for (var i = 0; i < wcLen; i++) { - const { before, beforeStr, after, nested } = wildcards[i] - if (nested === true) { - secret[beforeStr] = secret[beforeStr] || [] - nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath}) - } else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath}) - } - } - ` : ""; - } - function resultTmpl(serialize) { - return serialize === false ? `return o` : ` - var s = this.serialize(o) - this.restore(o) - return s - `; - } - function strictImpl(strict, serialize) { - return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize === false ? `return o` : `return this.serialize(o)`; - } - } -}); -var require_modifiers = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/modifiers.js"(exports2, module14) { - "use strict"; - module14.exports = { - groupRedact, - groupRestore, - nestedRedact, - nestedRestore - }; - function groupRestore({ keys, values, target }) { - if (target == null || typeof target === "string") return; - const length2 = keys.length; - for (var i2 = 0; i2 < length2; i2++) { - const k = keys[i2]; - target[k] = values[i2]; - } - } - function groupRedact(o2, path8, censor, isCensorFct, censorFctTakesPath) { - const target = get2(o2, path8); - if (target == null || typeof target === "string") return { keys: null, values: null, target, flat: true }; - const keys = Object.keys(target); - const keysLength = keys.length; - const pathLength = path8.length; - const pathWithKey = censorFctTakesPath ? [...path8] : void 0; - const values = new Array(keysLength); - for (var i2 = 0; i2 < keysLength; i2++) { - const key = keys[i2]; - values[i2] = target[key]; - if (censorFctTakesPath) { - pathWithKey[pathLength] = key; - target[key] = censor(target[key], pathWithKey); - } else if (isCensorFct) { - target[key] = censor(target[key]); - } else { - target[key] = censor; - } - } - return { keys, values, target, flat: true }; - } - function nestedRestore(instructions) { - for (let i2 = 0; i2 < instructions.length; i2++) { - const { target, path: path8, value } = instructions[i2]; - let current = target; - for (let i3 = path8.length - 1; i3 > 0; i3--) { - current = current[path8[i3]]; - } - current[path8[0]] = value; - } - } - function nestedRedact(store, o2, path8, ns, censor, isCensorFct, censorFctTakesPath) { - const target = get2(o2, path8); - if (target == null) return; - const keys = Object.keys(target); - const keysLength = keys.length; - for (var i2 = 0; i2 < keysLength; i2++) { - const key = keys[i2]; - specialSet(store, target, key, path8, ns, censor, isCensorFct, censorFctTakesPath); - } - return store; - } - function has2(obj, prop) { - return obj !== void 0 && obj !== null ? "hasOwn" in Object ? Object.hasOwn(obj, prop) : Object.prototype.hasOwnProperty.call(obj, prop) : false; - } - function specialSet(store, o2, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath) { - const afterPathLen = afterPath.length; - const lastPathIndex = afterPathLen - 1; - const originalKey = k; - var i2 = -1; - var n; - var nv; - var ov; - var oov = null; - var wc = null; - var kIsWc; - var wcov; - var consecutive = false; - var level = 0; - var depth = 0; - var redactPathCurrent = tree(); - ov = n = o2[k]; - if (typeof n !== "object") return; - while (n != null && ++i2 < afterPathLen) { - depth += 1; - k = afterPath[i2]; - oov = ov; - if (k !== "*" && !wc && !(typeof n === "object" && k in n)) { - break; - } - if (k === "*") { - if (wc === "*") { - consecutive = true; - } - wc = k; - if (i2 !== lastPathIndex) { - continue; - } - } - if (wc) { - const wcKeys = Object.keys(n); - for (var j = 0; j < wcKeys.length; j++) { - const wck = wcKeys[j]; - wcov = n[wck]; - kIsWc = k === "*"; - if (consecutive) { - redactPathCurrent = node(redactPathCurrent, wck, depth); - level = i2; - ov = iterateNthLevel(wcov, level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, o2[originalKey], depth + 1); - } else { - if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { - if (kIsWc) { - ov = wcov; - } else { - ov = wcov[k]; - } - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (kIsWc) { - const rv = restoreInstr(node(redactPathCurrent, wck, depth), ov, o2[originalKey]); - store.push(rv); - n[wck] = nv; - } else { - if (wcov[k] === nv) { - } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { - redactPathCurrent = node(redactPathCurrent, wck, depth); - } else { - redactPathCurrent = node(redactPathCurrent, wck, depth); - const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, o2[originalKey]); - store.push(rv); - wcov[k] = nv; - } - } - } - } - } - wc = null; - } else { - ov = n[k]; - redactPathCurrent = node(redactPathCurrent, k, depth); - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (has2(n, k) && nv === ov || nv === void 0 && censor !== void 0) { - } else { - const rv = restoreInstr(redactPathCurrent, ov, o2[originalKey]); - store.push(rv); - n[k] = nv; - } - n = n[k]; - } - if (typeof n !== "object") break; - if (ov === oov || typeof ov === "undefined") { - } - } - } - function get2(o2, p) { - var i2 = -1; - var l = p.length; - var n = o2; - while (n != null && ++i2 < l) { - n = n[p[i2]]; - } - return n; - } - function iterateNthLevel(wcov, level, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth) { - if (level === 0) { - if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { - if (kIsWc) { - ov = wcov; - } else { - ov = wcov[k]; - } - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (kIsWc) { - const rv = restoreInstr(redactPathCurrent, ov, parent); - store.push(rv); - n[wck] = nv; - } else { - if (wcov[k] === nv) { - } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { - } else { - const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, parent); - store.push(rv); - wcov[k] = nv; - } - } - } - } - for (const key in wcov) { - if (typeof wcov[key] === "object") { - redactPathCurrent = node(redactPathCurrent, key, depth); - iterateNthLevel(wcov[key], level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth + 1); - } - } - } - function tree() { - return { parent: null, key: null, children: [], depth: 0 }; - } - function node(parent, key, depth) { - if (parent.depth === depth) { - return node(parent.parent, key, depth); - } - var child = { - parent, - key, - depth, - children: [] - }; - parent.children.push(child); - return child; - } - function restoreInstr(node2, value, target) { - let current = node2; - const path8 = []; - do { - path8.push(current.key); - current = current.parent; - } while (current.parent != null); - return { path: path8, value, target }; - } - } -}); -var require_restorer = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/restorer.js"(exports2, module14) { - "use strict"; - var { groupRestore, nestedRestore } = require_modifiers(); - module14.exports = restorer; - function restorer() { - return function compileRestore() { - if (this.restore) { - this.restore.state.secret = this.secret; - return; - } - const { secret, wcLen } = this; - const paths = Object.keys(secret); - const resetters = resetTmpl(secret, paths); - const hasWildcards = wcLen > 0; - const state = hasWildcards ? { secret, groupRestore, nestedRestore } : { secret }; - this.restore = Function( - "o", - restoreTmpl(resetters, paths, hasWildcards) - ).bind(state); - this.restore.state = state; - }; - } - function resetTmpl(secret, paths) { - return paths.map((path8) => { - const { circle, escPath, leadingBracket } = secret[path8]; - const delim = leadingBracket ? "" : "."; - const reset = circle ? `o.${circle} = secret[${escPath}].val` : `o${delim}${path8} = secret[${escPath}].val`; - const clear = `secret[${escPath}].val = undefined`; - return ` - if (secret[${escPath}].val !== undefined) { - try { ${reset} } catch (e) {} - ${clear} - } - `; - }).join(""); - } - function restoreTmpl(resetters, paths, hasWildcards) { - const dynamicReset = hasWildcards === true ? ` - const keys = Object.keys(secret) - const len = keys.length - for (var i = len - 1; i >= ${paths.length}; i--) { - const k = keys[i] - const o = secret[k] - if (o) { - if (o.flat === true) this.groupRestore(o) - else this.nestedRestore(o) - secret[k] = null - } - } - ` : ""; - return ` - const secret = this.secret - ${dynamicReset} - ${resetters} - return o - `; - } - } -}); -var require_state2 = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/state.js"(exports2, module14) { - "use strict"; - module14.exports = state; - function state(o2) { - const { - secret, - censor, - compileRestore, - serialize, - groupRedact, - nestedRedact, - wildcards, - wcLen - } = o2; - const builder = [{ secret, censor, compileRestore }]; - if (serialize !== false) builder.push({ serialize }); - if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }); - return Object.assign(...builder); - } - } -}); -var require_fast_redact = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/index.js"(exports2, module14) { - "use strict"; - var validator = require_validator2(); - var parse52 = require_parse(); - var redactor = require_redactor(); - var restorer = require_restorer(); - var { groupRedact, nestedRedact } = require_modifiers(); - var state = require_state2(); - var rx = require_rx(); - var validate = validator(); - var noop = (o2) => o2; - noop.restore = noop; - var DEFAULT_CENSOR = "[REDACTED]"; - fastRedact.rx = rx; - fastRedact.validator = validator; - module14.exports = fastRedact; - function fastRedact(opts = {}) { - const paths = Array.from(new Set(opts.paths || [])); - const serialize = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; - const remove = opts.remove; - if (remove === true && serialize !== JSON.stringify) { - throw Error("fast-redact \u2013 remove option may only be set when serializer is JSON.stringify"); - } - const censor = remove === true ? void 0 : "censor" in opts ? opts.censor : DEFAULT_CENSOR; - const isCensorFct = typeof censor === "function"; - const censorFctTakesPath = isCensorFct && censor.length > 1; - if (paths.length === 0) return serialize || noop; - validate({ paths, serialize, censor }); - const { wildcards, wcLen, secret } = parse52({ paths, censor }); - const compileRestore = restorer(); - const strict = "strict" in opts ? opts.strict : true; - return redactor({ secret, wcLen, serialize, strict, isCensorFct, censorFctTakesPath }, state({ - secret, - censor, - compileRestore, - serialize, - groupRedact, - nestedRedact, - wildcards, - wcLen - })); - } - } -}); -var require_symbols2 = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/symbols.js"(exports2, module14) { - "use strict"; - var setLevelSym = Symbol("pino.setLevel"); - var getLevelSym = Symbol("pino.getLevel"); - var levelValSym = Symbol("pino.levelVal"); - var levelCompSym = Symbol("pino.levelComp"); - var useLevelLabelsSym = Symbol("pino.useLevelLabels"); - var useOnlyCustomLevelsSym = Symbol("pino.useOnlyCustomLevels"); - var mixinSym = Symbol("pino.mixin"); - var lsCacheSym = Symbol("pino.lsCache"); - var chindingsSym = Symbol("pino.chindings"); - var asJsonSym = Symbol("pino.asJson"); - var writeSym = Symbol("pino.write"); - var redactFmtSym = Symbol("pino.redactFmt"); - var timeSym = Symbol("pino.time"); - var timeSliceIndexSym = Symbol("pino.timeSliceIndex"); - var streamSym = Symbol("pino.stream"); - var stringifySym = Symbol("pino.stringify"); - var stringifySafeSym = Symbol("pino.stringifySafe"); - var stringifiersSym = Symbol("pino.stringifiers"); - var endSym = Symbol("pino.end"); - var formatOptsSym = Symbol("pino.formatOpts"); - var messageKeySym = Symbol("pino.messageKey"); - var errorKeySym = Symbol("pino.errorKey"); - var nestedKeySym = Symbol("pino.nestedKey"); - var nestedKeyStrSym = Symbol("pino.nestedKeyStr"); - var mixinMergeStrategySym = Symbol("pino.mixinMergeStrategy"); - var msgPrefixSym = Symbol("pino.msgPrefix"); - var wildcardFirstSym = Symbol("pino.wildcardFirst"); - var serializersSym = Symbol.for("pino.serializers"); - var formattersSym = Symbol.for("pino.formatters"); - var hooksSym = Symbol.for("pino.hooks"); - var needsMetadataGsym = Symbol.for("pino.metadata"); - module14.exports = { - setLevelSym, - getLevelSym, - levelValSym, - levelCompSym, - useLevelLabelsSym, - mixinSym, - lsCacheSym, - chindingsSym, - asJsonSym, - writeSym, - serializersSym, - redactFmtSym, - timeSym, - timeSliceIndexSym, - streamSym, - stringifySym, - stringifySafeSym, - stringifiersSym, - endSym, - formatOptsSym, - messageKeySym, - errorKeySym, - nestedKeySym, - wildcardFirstSym, - needsMetadataGsym, - useOnlyCustomLevelsSym, - formattersSym, - hooksSym, - nestedKeyStrSym, - mixinMergeStrategySym, - msgPrefixSym - }; - } -}); -var require_redaction = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/redaction.js"(exports2, module14) { - "use strict"; - var fastRedact = require_fast_redact(); - var { redactFmtSym, wildcardFirstSym } = require_symbols2(); - var { rx, validator } = fastRedact; - var validate = validator({ - ERR_PATHS_MUST_BE_STRINGS: () => "pino \u2013 redacted paths must be strings", - ERR_INVALID_PATH: (s) => `pino \u2013 redact paths array contains an invalid path (${s})` - }); - var CENSOR = "[Redacted]"; - var strict = false; - function redaction(opts, serialize) { - const { paths, censor } = handle(opts); - const shape = paths.reduce((o2, str) => { - rx.lastIndex = 0; - const first = rx.exec(str); - const next = rx.exec(str); - let ns = first[1] !== void 0 ? first[1].replace(/^(?:"|'|`)(.*)(?:"|'|`)$/, "$1") : first[0]; - if (ns === "*") { - ns = wildcardFirstSym; - } - if (next === null) { - o2[ns] = null; - return o2; - } - if (o2[ns] === null) { - return o2; - } - const { index } = next; - const nextPath = `${str.substr(index, str.length - 1)}`; - o2[ns] = o2[ns] || []; - if (ns !== wildcardFirstSym && o2[ns].length === 0) { - o2[ns].push(...o2[wildcardFirstSym] || []); - } - if (ns === wildcardFirstSym) { - Object.keys(o2).forEach(function(k) { - if (o2[k]) { - o2[k].push(nextPath); - } - }); - } - o2[ns].push(nextPath); - return o2; - }, {}); - const result = { - [redactFmtSym]: fastRedact({ paths, censor, serialize, strict }) - }; - const topCensor = (...args) => { - return typeof censor === "function" ? serialize(censor(...args)) : serialize(censor); - }; - return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o2, k) => { - if (shape[k] === null) { - o2[k] = (value) => topCensor(value, [k]); - } else { - const wrappedCensor = typeof censor === "function" ? (value, path8) => { - return censor(value, [k, ...path8]); - } : censor; - o2[k] = fastRedact({ - paths: shape[k], - censor: wrappedCensor, - serialize, - strict - }); - } - return o2; - }, result); - } - function handle(opts) { - if (Array.isArray(opts)) { - opts = { paths: opts, censor: CENSOR }; - validate(opts); - return opts; - } - let { paths, censor = CENSOR, remove } = opts; - if (Array.isArray(paths) === false) { - throw Error("pino \u2013 redact must contain an array of strings"); - } - if (remove === true) censor = void 0; - validate({ paths, censor }); - return { paths, censor }; - } - module14.exports = redaction; - } -}); -var require_time = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/time.js"(exports2, module14) { - "use strict"; - var nullTime = () => ""; - var epochTime = () => `,"time":${Date.now()}`; - var unixTime = () => `,"time":${Math.round(Date.now() / 1e3)}`; - var isoTime = () => `,"time":"${new Date(Date.now()).toISOString()}"`; - module14.exports = { nullTime, epochTime, unixTime, isoTime }; - } -}); -var require_quick_format_unescaped = __commonJS({ - "node_modules/.deno/quick-format-unescaped@4.0.4/node_modules/quick-format-unescaped/index.js"(exports2, module14) { - "use strict"; - function tryStringify(o2) { - try { - return JSON.stringify(o2); - } catch (e2) { - return '"[Circular]"'; - } - } - module14.exports = format52; - function format52(f, args, opts) { - var ss = opts && opts.stringify || tryStringify; - var offset = 1; - if (typeof f === "object" && f !== null) { - var len = args.length + offset; - if (len === 1) return f; - var objects = new Array(len); - objects[0] = ss(f); - for (var index = 1; index < len; index++) { - objects[index] = ss(args[index]); - } - return objects.join(" "); - } - if (typeof f !== "string") { - return f; - } - var argLen = args.length; - if (argLen === 0) return f; - var str = ""; - var a = 1 - offset; - var lastPos = -1; - var flen = f && f.length || 0; - for (var i2 = 0; i2 < flen; ) { - if (f.charCodeAt(i2) === 37 && i2 + 1 < flen) { - lastPos = lastPos > -1 ? lastPos : 0; - switch (f.charCodeAt(i2 + 1)) { - case 100: - // 'd' - case 102: - if (a >= argLen) - break; - if (args[a] == null) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += Number(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 105: - if (a >= argLen) - break; - if (args[a] == null) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += Math.floor(Number(args[a])); - lastPos = i2 + 2; - i2++; - break; - case 79: - // 'O' - case 111: - // 'o' - case 106: - if (a >= argLen) - break; - if (args[a] === void 0) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - var type = typeof args[a]; - if (type === "string") { - str += "'" + args[a] + "'"; - lastPos = i2 + 2; - i2++; - break; - } - if (type === "function") { - str += args[a].name || ""; - lastPos = i2 + 2; - i2++; - break; - } - str += ss(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 115: - if (a >= argLen) - break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += String(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 37: - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += "%"; - lastPos = i2 + 2; - i2++; - a--; - break; - } - ++a; - } - ++i2; - } - if (lastPos === -1) - return f; - else if (lastPos < flen) { - str += f.slice(lastPos); - } - return str; - } - } -}); -var require_atomic_sleep = __commonJS({ - "node_modules/.deno/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module14) { - "use strict"; - if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") { - let sleep = function(ms) { - const valid = ms > 0 && ms < Infinity; - if (valid === false) { - if (typeof ms !== "number" && typeof ms !== "bigint") { - throw TypeError("sleep: ms must be a number"); - } - throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); - } - Atomics.wait(nil, 0, 0, Number(ms)); - }; - const nil = new Int32Array(new SharedArrayBuffer(4)); - module14.exports = sleep; - } else { - let sleep = function(ms) { - const valid = ms > 0 && ms < Infinity; - if (valid === false) { - if (typeof ms !== "number" && typeof ms !== "bigint") { - throw TypeError("sleep: ms must be a number"); - } - throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); - } - const target = Date.now() + Number(ms); - while (target > Date.now()) { - } - }; - module14.exports = sleep; - } - } -}); -var require_sonic_boom = __commonJS({ - "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports2, module14) { - "use strict"; - var fs = __require2("fs"); - var EventEmitter = __require2("events"); - var inherits = __require2("util").inherits; - var path8 = __require2("path"); - var sleep = require_atomic_sleep(); - var BUSY_WRITE_TIMEOUT = 100; - var kEmptyBuffer = Buffer.allocUnsafe(0); - var MAX_WRITE = 16 * 1024; - var kContentModeBuffer = "buffer"; - var kContentModeUtf8 = "utf8"; - function openFile(file, sonic) { - sonic._opening = true; - sonic._writing = true; - sonic._asyncDrainScheduled = false; - function fileOpened(err, fd) { - if (err) { - sonic._reopening = false; - sonic._writing = false; - sonic._opening = false; - if (sonic.sync) { - process.nextTick(() => { - if (sonic.listenerCount("error") > 0) { - sonic.emit("error", err); - } - }); - } else { - sonic.emit("error", err); - } - return; - } - const reopening = sonic._reopening; - sonic.fd = fd; - sonic.file = file; - sonic._reopening = false; - sonic._opening = false; - sonic._writing = false; - if (sonic.sync) { - process.nextTick(() => sonic.emit("ready")); - } else { - sonic.emit("ready"); - } - if (sonic.destroyed) { - return; - } - if (!sonic._writing && sonic._len > sonic.minLength || sonic._flushPending) { - sonic._actualWrite(); - } else if (reopening) { - process.nextTick(() => sonic.emit("drain")); - } - } - const flags = sonic.append ? "a" : "w"; - const mode = sonic.mode; - if (sonic.sync) { - try { - if (sonic.mkdir) fs.mkdirSync(path8.dirname(file), { recursive: true }); - const fd = fs.openSync(file, flags, mode); - fileOpened(null, fd); - } catch (err) { - fileOpened(err); - throw err; - } - } else if (sonic.mkdir) { - fs.mkdir(path8.dirname(file), { recursive: true }, (err) => { - if (err) return fileOpened(err); - fs.open(file, flags, mode, fileOpened); - }); - } else { - fs.open(file, flags, mode, fileOpened); - } - } - function SonicBoom(opts) { - if (!(this instanceof SonicBoom)) { - return new SonicBoom(opts); - } - let { fd, dest, minLength, maxLength, maxWrite, sync, append = true, mkdir: mkdir4, retryEAGAIN, fsync, contentMode, mode } = opts || {}; - fd = fd || dest; - this._len = 0; - this.fd = -1; - this._bufs = []; - this._lens = []; - this._writing = false; - this._ending = false; - this._reopening = false; - this._asyncDrainScheduled = false; - this._flushPending = false; - this._hwm = Math.max(minLength || 0, 16387); - this.file = null; - this.destroyed = false; - this.minLength = minLength || 0; - this.maxLength = maxLength || 0; - this.maxWrite = maxWrite || MAX_WRITE; - this.sync = sync || false; - this.writable = true; - this._fsync = fsync || false; - this.append = append || false; - this.mode = mode; - this.retryEAGAIN = retryEAGAIN || (() => true); - this.mkdir = mkdir4 || false; - let fsWriteSync; - let fsWrite; - if (contentMode === kContentModeBuffer) { - this._writingBuf = kEmptyBuffer; - this.write = writeBuffer; - this.flush = flushBuffer; - this.flushSync = flushBufferSync; - this._actualWrite = actualWriteBuffer; - fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf); - fsWrite = () => fs.write(this.fd, this._writingBuf, this.release); - } else if (contentMode === void 0 || contentMode === kContentModeUtf8) { - this._writingBuf = ""; - this.write = write; - this.flush = flush; - this.flushSync = flushSync; - this._actualWrite = actualWrite; - fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf, "utf8"); - fsWrite = () => fs.write(this.fd, this._writingBuf, "utf8", this.release); - } else { - throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`); - } - if (typeof fd === "number") { - this.fd = fd; - process.nextTick(() => this.emit("ready")); - } else if (typeof fd === "string") { - openFile(fd, this); - } else { - throw new Error("SonicBoom supports only file descriptors and files"); - } - if (this.minLength >= this.maxWrite) { - throw new Error(`minLength should be smaller than maxWrite (${this.maxWrite})`); - } - this.release = (err, n) => { - if (err) { - if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) { - if (this.sync) { - try { - sleep(BUSY_WRITE_TIMEOUT); - this.release(void 0, 0); - } catch (err2) { - this.release(err2); - } - } else { - setTimeout(fsWrite, BUSY_WRITE_TIMEOUT); - } - } else { - this._writing = false; - this.emit("error", err); - } - return; - } - this.emit("write", n); - const releasedBufObj = releaseWritingBuf(this._writingBuf, this._len, n); - this._len = releasedBufObj.len; - this._writingBuf = releasedBufObj.writingBuf; - if (this._writingBuf.length) { - if (!this.sync) { - fsWrite(); - return; - } - try { - do { - const n2 = fsWriteSync(); - const releasedBufObj2 = releaseWritingBuf(this._writingBuf, this._len, n2); - this._len = releasedBufObj2.len; - this._writingBuf = releasedBufObj2.writingBuf; - } while (this._writingBuf.length); - } catch (err2) { - this.release(err2); - return; - } - } - if (this._fsync) { - fs.fsyncSync(this.fd); - } - const len = this._len; - if (this._reopening) { - this._writing = false; - this._reopening = false; - this.reopen(); - } else if (len > this.minLength) { - this._actualWrite(); - } else if (this._ending) { - if (len > 0) { - this._actualWrite(); - } else { - this._writing = false; - actualClose(this); - } - } else { - this._writing = false; - if (this.sync) { - if (!this._asyncDrainScheduled) { - this._asyncDrainScheduled = true; - process.nextTick(emitDrain, this); - } - } else { - this.emit("drain"); - } - } - }; - this.on("newListener", function(name) { - if (name === "drain") { - this._asyncDrainScheduled = false; - } - }); - } - function releaseWritingBuf(writingBuf, len, n) { - if (typeof writingBuf === "string" && Buffer.byteLength(writingBuf) !== n) { - n = Buffer.from(writingBuf).subarray(0, n).toString().length; - } - len = Math.max(len - n, 0); - writingBuf = writingBuf.slice(n); - return { writingBuf, len }; - } - function emitDrain(sonic) { - const hasListeners = sonic.listenerCount("drain") > 0; - if (!hasListeners) return; - sonic._asyncDrainScheduled = false; - sonic.emit("drain"); - } - inherits(SonicBoom, EventEmitter); - function mergeBuf(bufs, len) { - if (bufs.length === 0) { - return kEmptyBuffer; - } - if (bufs.length === 1) { - return bufs[0]; - } - return Buffer.concat(bufs, len); - } - function write(data) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - const len = this._len + data.length; - const bufs = this._bufs; - if (this.maxLength && len > this.maxLength) { - this.emit("drop", data); - return this._len < this._hwm; - } - if (bufs.length === 0 || bufs[bufs.length - 1].length + data.length > this.maxWrite) { - bufs.push("" + data); - } else { - bufs[bufs.length - 1] += data; - } - this._len = len; - if (!this._writing && this._len >= this.minLength) { - this._actualWrite(); - } - return this._len < this._hwm; - } - function writeBuffer(data) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - const len = this._len + data.length; - const bufs = this._bufs; - const lens = this._lens; - if (this.maxLength && len > this.maxLength) { - this.emit("drop", data); - return this._len < this._hwm; - } - if (bufs.length === 0 || lens[lens.length - 1] + data.length > this.maxWrite) { - bufs.push([data]); - lens.push(data.length); - } else { - bufs[bufs.length - 1].push(data); - lens[lens.length - 1] += data.length; - } - this._len = len; - if (!this._writing && this._len >= this.minLength) { - this._actualWrite(); - } - return this._len < this._hwm; - } - function callFlushCallbackOnDrain(cb) { - this._flushPending = true; - const onDrain = () => { - if (!this._fsync) { - fs.fsync(this.fd, (err) => { - this._flushPending = false; - cb(err); - }); - } else { - this._flushPending = false; - cb(); - } - this.off("error", onError); - }; - const onError = (err) => { - this._flushPending = false; - cb(err); - this.off("drain", onDrain); - }; - this.once("drain", onDrain); - this.once("error", onError); - } - function flush(cb) { - if (cb != null && typeof cb !== "function") { - throw new Error("flush cb must be a function"); - } - if (this.destroyed) { - const error2 = new Error("SonicBoom destroyed"); - if (cb) { - cb(error2); - return; - } - throw error2; - } - if (this.minLength <= 0) { - cb?.(); - return; - } - if (cb) { - callFlushCallbackOnDrain.call(this, cb); - } - if (this._writing) { - return; - } - if (this._bufs.length === 0) { - this._bufs.push(""); - } - this._actualWrite(); - } - function flushBuffer(cb) { - if (cb != null && typeof cb !== "function") { - throw new Error("flush cb must be a function"); - } - if (this.destroyed) { - const error2 = new Error("SonicBoom destroyed"); - if (cb) { - cb(error2); - return; - } - throw error2; - } - if (this.minLength <= 0) { - cb?.(); - return; - } - if (cb) { - callFlushCallbackOnDrain.call(this, cb); - } - if (this._writing) { - return; - } - if (this._bufs.length === 0) { - this._bufs.push([]); - this._lens.push(0); - } - this._actualWrite(); - } - SonicBoom.prototype.reopen = function(file) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - if (this._opening) { - this.once("ready", () => { - this.reopen(file); - }); - return; - } - if (this._ending) { - return; - } - if (!this.file) { - throw new Error("Unable to reopen a file descriptor, you must pass a file to SonicBoom"); - } - if (file) { - this.file = file; - } - this._reopening = true; - if (this._writing) { - return; - } - const fd = this.fd; - this.once("ready", () => { - if (fd !== this.fd) { - fs.close(fd, (err) => { - if (err) { - return this.emit("error", err); - } - }); - } - }); - openFile(this.file, this); - }; - SonicBoom.prototype.end = function() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - if (this._opening) { - this.once("ready", () => { - this.end(); - }); - return; - } - if (this._ending) { - return; - } - this._ending = true; - if (this._writing) { - return; - } - if (this._len > 0 && this.fd >= 0) { - this._actualWrite(); - } else { - actualClose(this); - } - }; - function flushSync() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - if (this.fd < 0) { - throw new Error("sonic boom is not ready yet"); - } - if (!this._writing && this._writingBuf.length > 0) { - this._bufs.unshift(this._writingBuf); - this._writingBuf = ""; - } - let buf2 = ""; - while (this._bufs.length || buf2) { - if (buf2.length <= 0) { - buf2 = this._bufs[0]; - } - try { - const n = fs.writeSync(this.fd, buf2, "utf8"); - const releasedBufObj = releaseWritingBuf(buf2, this._len, n); - buf2 = releasedBufObj.writingBuf; - this._len = releasedBufObj.len; - if (buf2.length <= 0) { - this._bufs.shift(); - } - } catch (err) { - const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; - if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { - throw err; - } - sleep(BUSY_WRITE_TIMEOUT); - } - } - try { - fs.fsyncSync(this.fd); - } catch { - } - } - function flushBufferSync() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - if (this.fd < 0) { - throw new Error("sonic boom is not ready yet"); - } - if (!this._writing && this._writingBuf.length > 0) { - this._bufs.unshift([this._writingBuf]); - this._writingBuf = kEmptyBuffer; - } - let buf2 = kEmptyBuffer; - while (this._bufs.length || buf2.length) { - if (buf2.length <= 0) { - buf2 = mergeBuf(this._bufs[0], this._lens[0]); - } - try { - const n = fs.writeSync(this.fd, buf2); - buf2 = buf2.subarray(n); - this._len = Math.max(this._len - n, 0); - if (buf2.length <= 0) { - this._bufs.shift(); - this._lens.shift(); - } - } catch (err) { - const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; - if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { - throw err; - } - sleep(BUSY_WRITE_TIMEOUT); - } - } - } - SonicBoom.prototype.destroy = function() { - if (this.destroyed) { - return; - } - actualClose(this); - }; - function actualWrite() { - const release = this.release; - this._writing = true; - this._writingBuf = this._writingBuf || this._bufs.shift() || ""; - if (this.sync) { - try { - const written = fs.writeSync(this.fd, this._writingBuf, "utf8"); - release(null, written); - } catch (err) { - release(err); - } - } else { - fs.write(this.fd, this._writingBuf, "utf8", release); - } - } - function actualWriteBuffer() { - const release = this.release; - this._writing = true; - this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift()); - if (this.sync) { - try { - const written = fs.writeSync(this.fd, this._writingBuf); - release(null, written); - } catch (err) { - release(err); - } - } else { - fs.write(this.fd, this._writingBuf, release); - } - } - function actualClose(sonic) { - if (sonic.fd === -1) { - sonic.once("ready", actualClose.bind(null, sonic)); - return; - } - sonic.destroyed = true; - sonic._bufs = []; - sonic._lens = []; - fs.fsync(sonic.fd, closeWrapped); - function closeWrapped() { - if (sonic.fd !== 1 && sonic.fd !== 2) { - fs.close(sonic.fd, done); - } else { - done(); - } - } - function done(err) { - if (err) { - sonic.emit("error", err); - return; - } - if (sonic._ending && !sonic._writing) { - sonic.emit("finish"); - } - sonic.emit("close"); - } - } - SonicBoom.SonicBoom = SonicBoom; - SonicBoom.default = SonicBoom; - module14.exports = SonicBoom; - } -}); -var require_on_exit_leak_free = __commonJS({ - "node_modules/.deno/on-exit-leak-free@2.1.2/node_modules/on-exit-leak-free/index.js"(exports2, module14) { - "use strict"; - var refs = { - exit: [], - beforeExit: [] - }; - var functions = { - exit: onExit, - beforeExit: onBeforeExit - }; - var registry2; - function ensureRegistry() { - if (registry2 === void 0) { - registry2 = new FinalizationRegistry(clear); - } - } - function install(event) { - if (refs[event].length > 0) { - return; - } - process.on(event, functions[event]); - } - function uninstall(event) { - if (refs[event].length > 0) { - return; - } - process.removeListener(event, functions[event]); - if (refs.exit.length === 0 && refs.beforeExit.length === 0) { - registry2 = void 0; - } - } - function onExit() { - callRefs("exit"); - } - function onBeforeExit() { - callRefs("beforeExit"); - } - function callRefs(event) { - for (const ref of refs[event]) { - const obj = ref.deref(); - const fn = ref.fn; - if (obj !== void 0) { - fn(obj, event); - } - } - refs[event] = []; - } - function clear(ref) { - for (const event of ["exit", "beforeExit"]) { - const index = refs[event].indexOf(ref); - refs[event].splice(index, index + 1); - uninstall(event); - } - } - function _register(event, obj, fn) { - if (obj === void 0) { - throw new Error("the object can't be undefined"); - } - install(event); - const ref = new WeakRef(obj); - ref.fn = fn; - ensureRegistry(); - registry2.register(obj, ref); - refs[event].push(ref); - } - function register2(obj, fn) { - _register("exit", obj, fn); - } - function registerBeforeExit(obj, fn) { - _register("beforeExit", obj, fn); - } - function unregister(obj) { - if (registry2 === void 0) { - return; - } - registry2.unregister(obj); - for (const event of ["exit", "beforeExit"]) { - refs[event] = refs[event].filter((ref) => { - const _obj = ref.deref(); - return _obj && _obj !== obj; - }); - uninstall(event); - } - } - module14.exports = { - register: register2, - registerBeforeExit, - unregister - }; - } -}); -var require_package6 = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/package.json"(exports2, module14) { - module14.exports = { - name: "thread-stream", - version: "2.7.0", - description: "A streaming way to send data to a Node.js Worker Thread", - main: "index.js", - types: "index.d.ts", - dependencies: { - "real-require": "^0.2.0" - }, - devDependencies: { - "@types/node": "^20.1.0", - "@types/tap": "^15.0.0", - "@yao-pkg/pkg": "^5.11.5", - desm: "^1.3.0", - fastbench: "^1.0.1", - husky: "^9.0.6", - "pino-elasticsearch": "^8.0.0", - "sonic-boom": "^3.0.0", - standard: "^17.0.0", - tap: "^16.2.0", - "ts-node": "^10.8.0", - typescript: "^5.3.2", - "why-is-node-running": "^2.2.2" - }, - scripts: { - test: 'standard && npm run transpile && tap "test/**/*.test.*js" && tap --ts test/*.test.*ts', - "test:ci": "standard && npm run transpile && npm run test:ci:js && npm run test:ci:ts", - "test:ci:js": 'tap --no-check-coverage --timeout=120 --coverage-report=lcovonly "test/**/*.test.*js"', - "test:ci:ts": 'tap --ts --no-check-coverage --coverage-report=lcovonly "test/**/*.test.*ts"', - "test:yarn": 'npm run transpile && tap "test/**/*.test.js" --no-check-coverage', - transpile: "sh ./test/ts/transpile.sh", - prepare: "husky install" - }, - standard: { - ignore: [ - "test/ts/**/*" - ] - }, - repository: { - type: "git", - url: "git+https://github.com/mcollina/thread-stream.git" - }, - keywords: [ - "worker", - "thread", - "threads", - "stream" - ], - author: "Matteo Collina ", - license: "MIT", - bugs: { - url: "https://github.com/mcollina/thread-stream/issues" - }, - homepage: "https://github.com/mcollina/thread-stream#readme" - }; - } -}); -var require_wait2 = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/wait.js"(exports2, module14) { - "use strict"; - var MAX_TIMEOUT = 1e3; - function wait(state, index, expected, timeout, done) { - const max = Date.now() + timeout; - let current = Atomics.load(state, index); - if (current === expected) { - done(null, "ok"); - return; - } - let prior = current; - const check2 = (backoff) => { - if (Date.now() > max) { - done(null, "timed-out"); - } else { - setTimeout(() => { - prior = current; - current = Atomics.load(state, index); - if (current === prior) { - check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); - } else { - if (current === expected) done(null, "ok"); - else done(null, "not-equal"); - } - }, backoff); - } - }; - check2(1); - } - function waitDiff(state, index, expected, timeout, done) { - const max = Date.now() + timeout; - let current = Atomics.load(state, index); - if (current !== expected) { - done(null, "ok"); - return; - } - const check2 = (backoff) => { - if (Date.now() > max) { - done(null, "timed-out"); - } else { - setTimeout(() => { - current = Atomics.load(state, index); - if (current !== expected) { - done(null, "ok"); - } else { - check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); - } - }, backoff); - } - }; - check2(1); - } - module14.exports = { wait, waitDiff }; - } -}); -var require_indexes = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/indexes.js"(exports2, module14) { - "use strict"; - var WRITE_INDEX = 4; - var READ_INDEX = 8; - module14.exports = { - WRITE_INDEX, - READ_INDEX - }; - } -}); -var require_thread_stream = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports2, module14) { - "use strict"; - var { version: version3 } = require_package6(); - var { EventEmitter } = __require2("events"); - var { Worker: Worker2 } = __require2("worker_threads"); - var { join: join92 } = __require2("path"); - var { pathToFileURL: pathToFileURL2 } = __require2("url"); - var { wait } = require_wait2(); - var { - WRITE_INDEX, - READ_INDEX - } = require_indexes(); - var buffer = __require2("buffer"); - var assert2 = __require2("assert"); - var kImpl = Symbol("kImpl"); - var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; - var FakeWeakRef = class { - constructor(value) { - this._value = value; - } - deref() { - return this._value; - } - }; - var FakeFinalizationRegistry = class { - register() { - } - unregister() { - } - }; - var FinalizationRegistry2 = process.env.NODE_V8_COVERAGE ? FakeFinalizationRegistry : global.FinalizationRegistry || FakeFinalizationRegistry; - var WeakRef2 = process.env.NODE_V8_COVERAGE ? FakeWeakRef : global.WeakRef || FakeWeakRef; - var registry2 = new FinalizationRegistry2((worker) => { - if (worker.exited) { - return; - } - worker.terminate(); - }); - function createWorker2(stream, opts) { - const { filename, workerData } = opts; - const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; - const toExecute = bundlerOverrides["thread-stream-worker"] || join92(__dirname, "lib", "worker.js"); - const worker = new Worker2(toExecute, { - ...opts.workerOpts, - trackUnmanagedFds: false, - workerData: { - filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, - dataBuf: stream[kImpl].dataBuf, - stateBuf: stream[kImpl].stateBuf, - workerData: { - $context: { - threadStreamVersion: version3 - }, - ...workerData - } - } - }); - worker.stream = new FakeWeakRef(stream); - worker.on("message", onWorkerMessage); - worker.on("exit", onWorkerExit); - registry2.register(stream, worker); - return worker; - } - function drain(stream) { - assert2(!stream[kImpl].sync); - if (stream[kImpl].needDrain) { - stream[kImpl].needDrain = false; - stream.emit("drain"); - } - } - function nextFlush(stream) { - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let leftover = stream[kImpl].data.length - writeIndex; - if (leftover > 0) { - if (stream[kImpl].buf.length === 0) { - stream[kImpl].flushing = false; - if (stream[kImpl].ending) { - end(stream); - } else if (stream[kImpl].needDrain) { - process.nextTick(drain, stream); - } - return; - } - let toWrite = stream[kImpl].buf.slice(0, leftover); - let toWriteBytes = Buffer.byteLength(toWrite); - if (toWriteBytes <= leftover) { - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, nextFlush.bind(null, stream)); - } else { - stream.flush(() => { - if (stream.destroyed) { - return; - } - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - while (toWriteBytes > stream[kImpl].data.length) { - leftover = leftover / 2; - toWrite = stream[kImpl].buf.slice(0, leftover); - toWriteBytes = Buffer.byteLength(toWrite); - } - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, nextFlush.bind(null, stream)); - }); - } - } else if (leftover === 0) { - if (writeIndex === 0 && stream[kImpl].buf.length === 0) { - return; - } - stream.flush(() => { - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - nextFlush(stream); - }); - } else { - destroy(stream, new Error("overwritten")); - } - } - function onWorkerMessage(msg) { - const stream = this.stream.deref(); - if (stream === void 0) { - this.exited = true; - this.terminate(); - return; - } - switch (msg.code) { - case "READY": - this.stream = new WeakRef2(stream); - stream.flush(() => { - stream[kImpl].ready = true; - stream.emit("ready"); - }); - break; - case "ERROR": - destroy(stream, msg.err); - break; - case "EVENT": - if (Array.isArray(msg.args)) { - stream.emit(msg.name, ...msg.args); - } else { - stream.emit(msg.name, msg.args); - } - break; - case "WARNING": - process.emitWarning(msg.err); - break; - default: - destroy(stream, new Error("this should not happen: " + msg.code)); - } - } - function onWorkerExit(code2) { - const stream = this.stream.deref(); - if (stream === void 0) { - return; - } - registry2.unregister(stream); - stream.worker.exited = true; - stream.worker.off("exit", onWorkerExit); - destroy(stream, code2 !== 0 ? new Error("the worker thread exited") : null); - } - var ThreadStream = class extends EventEmitter { - constructor(opts = {}) { - super(); - if (opts.bufferSize < 4) { - throw new Error("bufferSize must at least fit a 4-byte utf-8 char"); - } - this[kImpl] = {}; - this[kImpl].stateBuf = new SharedArrayBuffer(128); - this[kImpl].state = new Int32Array(this[kImpl].stateBuf); - this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024); - this[kImpl].data = Buffer.from(this[kImpl].dataBuf); - this[kImpl].sync = opts.sync || false; - this[kImpl].ending = false; - this[kImpl].ended = false; - this[kImpl].needDrain = false; - this[kImpl].destroyed = false; - this[kImpl].flushing = false; - this[kImpl].ready = false; - this[kImpl].finished = false; - this[kImpl].errored = null; - this[kImpl].closed = false; - this[kImpl].buf = ""; - this.worker = createWorker2(this, opts); - this.on("message", (message, transferList) => { - this.worker.postMessage(message, transferList); - }); - } - write(data) { - if (this[kImpl].destroyed) { - error2(this, new Error("the worker has exited")); - return false; - } - if (this[kImpl].ending) { - error2(this, new Error("the worker is ending")); - return false; - } - if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) { - try { - writeSync(this); - this[kImpl].flushing = true; - } catch (err) { - destroy(this, err); - return false; - } - } - this[kImpl].buf += data; - if (this[kImpl].sync) { - try { - writeSync(this); - return true; - } catch (err) { - destroy(this, err); - return false; - } - } - if (!this[kImpl].flushing) { - this[kImpl].flushing = true; - setImmediate(nextFlush, this); - } - this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0; - return !this[kImpl].needDrain; - } - end() { - if (this[kImpl].destroyed) { - return; - } - this[kImpl].ending = true; - end(this); - } - flush(cb) { - if (this[kImpl].destroyed) { - if (typeof cb === "function") { - process.nextTick(cb, new Error("the worker has exited")); - } - return; - } - const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX); - wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => { - if (err) { - destroy(this, err); - process.nextTick(cb, err); - return; - } - if (res === "not-equal") { - this.flush(cb); - return; - } - process.nextTick(cb); - }); - } - flushSync() { - if (this[kImpl].destroyed) { - return; - } - writeSync(this); - flushSync(this); - } - unref() { - this.worker.unref(); - } - ref() { - this.worker.ref(); - } - get ready() { - return this[kImpl].ready; - } - get destroyed() { - return this[kImpl].destroyed; - } - get closed() { - return this[kImpl].closed; - } - get writable() { - return !this[kImpl].destroyed && !this[kImpl].ending; - } - get writableEnded() { - return this[kImpl].ending; - } - get writableFinished() { - return this[kImpl].finished; - } - get writableNeedDrain() { - return this[kImpl].needDrain; - } - get writableObjectMode() { - return false; - } - get writableErrored() { - return this[kImpl].errored; - } - }; - function error2(stream, err) { - setImmediate(() => { - stream.emit("error", err); - }); - } - function destroy(stream, err) { - if (stream[kImpl].destroyed) { - return; - } - stream[kImpl].destroyed = true; - if (err) { - stream[kImpl].errored = err; - error2(stream, err); - } - if (!stream.worker.exited) { - stream.worker.terminate().catch(() => { - }).then(() => { - stream[kImpl].closed = true; - stream.emit("close"); - }); - } else { - setImmediate(() => { - stream[kImpl].closed = true; - stream.emit("close"); - }); - } - } - function write(stream, data, cb) { - const current = Atomics.load(stream[kImpl].state, WRITE_INDEX); - const length2 = Buffer.byteLength(data); - stream[kImpl].data.write(data, current); - Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length2); - Atomics.notify(stream[kImpl].state, WRITE_INDEX); - cb(); - return true; - } - function end(stream) { - if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) { - return; - } - stream[kImpl].ended = true; - try { - stream.flushSync(); - let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - Atomics.store(stream[kImpl].state, WRITE_INDEX, -1); - Atomics.notify(stream[kImpl].state, WRITE_INDEX); - let spins = 0; - while (readIndex !== -1) { - Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); - readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - if (readIndex === -2) { - destroy(stream, new Error("end() failed")); - return; - } - if (++spins === 10) { - destroy(stream, new Error("end() took too long (10s)")); - return; - } - } - process.nextTick(() => { - stream[kImpl].finished = true; - stream.emit("finish"); - }); - } catch (err) { - destroy(stream, err); - } - } - function writeSync(stream) { - const cb = () => { - if (stream[kImpl].ending) { - end(stream); - } else if (stream[kImpl].needDrain) { - process.nextTick(drain, stream); - } - }; - stream[kImpl].flushing = false; - while (stream[kImpl].buf.length !== 0) { - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let leftover = stream[kImpl].data.length - writeIndex; - if (leftover === 0) { - flushSync(stream); - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - continue; - } else if (leftover < 0) { - throw new Error("overwritten"); - } - let toWrite = stream[kImpl].buf.slice(0, leftover); - let toWriteBytes = Buffer.byteLength(toWrite); - if (toWriteBytes <= leftover) { - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, cb); - } else { - flushSync(stream); - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - while (toWriteBytes > stream[kImpl].buf.length) { - leftover = leftover / 2; - toWrite = stream[kImpl].buf.slice(0, leftover); - toWriteBytes = Buffer.byteLength(toWrite); - } - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, cb); - } - } - } - function flushSync(stream) { - if (stream[kImpl].flushing) { - throw new Error("unable to flush while flushing"); - } - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let spins = 0; - while (true) { - const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - if (readIndex === -2) { - throw Error("_flushSync failed"); - } - if (readIndex !== writeIndex) { - Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); - } else { - break; - } - if (++spins === 10) { - throw new Error("_flushSync took too long (10s)"); - } - } - } - module14.exports = ThreadStream; - } -}); -var require_transport = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports2, module14) { - "use strict"; - var { createRequire } = __require2("module"); - var getCallers = require_caller(); - var { join: join92, isAbsolute: isAbsolute8, sep } = __require2("path"); - var sleep = require_atomic_sleep(); - var onExit = require_on_exit_leak_free(); - var ThreadStream = require_thread_stream(); - function setupOnExit(stream) { - onExit.register(stream, autoEnd); - onExit.registerBeforeExit(stream, flush); - stream.on("close", function() { - onExit.unregister(stream); - }); - } - function buildStream(filename, workerData, workerOpts) { - const stream = new ThreadStream({ - filename, - workerData, - workerOpts - }); - stream.on("ready", onReady); - stream.on("close", function() { - process.removeListener("exit", onExit2); - }); - process.on("exit", onExit2); - function onReady() { - process.removeListener("exit", onExit2); - stream.unref(); - if (workerOpts.autoEnd !== false) { - setupOnExit(stream); - } - } - function onExit2() { - if (stream.closed) { - return; - } - stream.flushSync(); - sleep(100); - stream.end(); - } - return stream; - } - function autoEnd(stream) { - stream.ref(); - stream.flushSync(); - stream.end(); - stream.once("close", function() { - stream.unref(); - }); - } - function flush(stream) { - stream.flushSync(); - } - function transport(fullOptions) { - const { pipeline, targets, levels, dedupe, options: options2 = {}, worker = {}, caller = getCallers() } = fullOptions; - const callers = typeof caller === "string" ? [caller] : caller; - const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; - let target = fullOptions.target; - if (target && targets) { - throw new Error("only one of target or targets can be specified"); - } - if (targets) { - target = bundlerOverrides["pino-worker"] || join92(__dirname, "worker.js"); - options2.targets = targets.map((dest) => { - return { - ...dest, - target: fixTarget(dest.target) - }; - }); - } else if (pipeline) { - target = bundlerOverrides["pino-pipeline-worker"] || join92(__dirname, "worker-pipeline.js"); - options2.targets = pipeline.map((dest) => { - return { - ...dest, - target: fixTarget(dest.target) - }; - }); - } - if (levels) { - options2.levels = levels; - } - if (dedupe) { - options2.dedupe = dedupe; - } - return buildStream(fixTarget(target), options2, worker); - function fixTarget(origin) { - origin = bundlerOverrides[origin] || origin; - if (isAbsolute8(origin) || origin.indexOf("file://") === 0) { - return origin; - } - if (origin === "pino/file") { - return join92(__dirname, "..", "file.js"); - } - let fixTarget2; - for (const filePath of callers) { - try { - const context = filePath === "node:repl" ? process.cwd() + sep : filePath; - fixTarget2 = createRequire(context).resolve(origin); - break; - } catch (err) { - continue; - } - } - if (!fixTarget2) { - throw new Error(`unable to determine transport target for "${origin}"`); - } - return fixTarget2; - } - } - module14.exports = transport; - } -}); -var require_tools = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/tools.js"(exports2, module14) { - "use strict"; - var format52 = require_quick_format_unescaped(); - var { mapHttpRequest, mapHttpResponse } = require_pino_std_serializers(); - var SonicBoom = require_sonic_boom(); - var onExit = require_on_exit_leak_free(); - var { - lsCacheSym, - chindingsSym, - writeSym, - serializersSym, - formatOptsSym, - endSym, - stringifiersSym, - stringifySym, - stringifySafeSym, - wildcardFirstSym, - nestedKeySym, - formattersSym, - messageKeySym, - errorKeySym, - nestedKeyStrSym, - msgPrefixSym - } = require_symbols2(); - var { isMainThread } = __require2("worker_threads"); - var transport = require_transport(); - function noop() { - } - function genLog(level, hook) { - if (!hook) return LOG; - return function hookWrappedLog(...args) { - hook.call(this, args, LOG, level); - }; - function LOG(o2, ...n) { - if (typeof o2 === "object") { - let msg = o2; - if (o2 !== null) { - if (o2.method && o2.headers && o2.socket) { - o2 = mapHttpRequest(o2); - } else if (typeof o2.setHeader === "function") { - o2 = mapHttpResponse(o2); - } - } - let formatParams; - if (msg === null && n.length === 0) { - formatParams = [null]; - } else { - msg = n.shift(); - formatParams = n; - } - if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { - msg = this[msgPrefixSym] + msg; - } - this[writeSym](o2, format52(msg, formatParams, this[formatOptsSym]), level); - } else { - let msg = o2 === void 0 ? n.shift() : o2; - if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { - msg = this[msgPrefixSym] + msg; - } - this[writeSym](null, format52(msg, n, this[formatOptsSym]), level); - } - } - } - function asString(str) { - let result = ""; - let last = 0; - let found = false; - let point = 255; - const l = str.length; - if (l > 100) { - return JSON.stringify(str); - } - for (var i2 = 0; i2 < l && point >= 32; i2++) { - point = str.charCodeAt(i2); - if (point === 34 || point === 92) { - result += str.slice(last, i2) + "\\"; - last = i2; - found = true; - } - } - if (!found) { - result = str; - } else { - result += str.slice(last); - } - return point < 32 ? JSON.stringify(str) : '"' + result + '"'; - } - function asJson(obj, msg, num, time3) { - const stringify3 = this[stringifySym]; - const stringifySafe = this[stringifySafeSym]; - const stringifiers = this[stringifiersSym]; - const end = this[endSym]; - const chindings = this[chindingsSym]; - const serializers = this[serializersSym]; - const formatters = this[formattersSym]; - const messageKey = this[messageKeySym]; - const errorKey = this[errorKeySym]; - let data = this[lsCacheSym][num] + time3; - data = data + chindings; - let value; - if (formatters.log) { - obj = formatters.log(obj); - } - const wildcardStringifier = stringifiers[wildcardFirstSym]; - let propStr = ""; - for (const key in obj) { - value = obj[key]; - if (Object.prototype.hasOwnProperty.call(obj, key) && value !== void 0) { - if (serializers[key]) { - value = serializers[key](value); - } else if (key === errorKey && serializers.err) { - value = serializers.err(value); - } - const stringifier = stringifiers[key] || wildcardStringifier; - switch (typeof value) { - case "undefined": - case "function": - continue; - case "number": - if (Number.isFinite(value) === false) { - value = null; - } - // this case explicitly falls through to the next one - case "boolean": - if (stringifier) value = stringifier(value); - break; - case "string": - value = (stringifier || asString)(value); - break; - default: - value = (stringifier || stringify3)(value, stringifySafe); - } - if (value === void 0) continue; - const strKey = asString(key); - propStr += "," + strKey + ":" + value; - } - } - let msgStr = ""; - if (msg !== void 0) { - value = serializers[messageKey] ? serializers[messageKey](msg) : msg; - const stringifier = stringifiers[messageKey] || wildcardStringifier; - switch (typeof value) { - case "function": - break; - case "number": - if (Number.isFinite(value) === false) { - value = null; - } - // this case explicitly falls through to the next one - case "boolean": - if (stringifier) value = stringifier(value); - msgStr = ',"' + messageKey + '":' + value; - break; - case "string": - value = (stringifier || asString)(value); - msgStr = ',"' + messageKey + '":' + value; - break; - default: - value = (stringifier || stringify3)(value, stringifySafe); - msgStr = ',"' + messageKey + '":' + value; - } - } - if (this[nestedKeySym] && propStr) { - return data + this[nestedKeyStrSym] + propStr.slice(1) + "}" + msgStr + end; - } else { - return data + propStr + msgStr + end; - } - } - function asChindings(instance, bindings) { - let value; - let data = instance[chindingsSym]; - const stringify3 = instance[stringifySym]; - const stringifySafe = instance[stringifySafeSym]; - const stringifiers = instance[stringifiersSym]; - const wildcardStringifier = stringifiers[wildcardFirstSym]; - const serializers = instance[serializersSym]; - const formatter = instance[formattersSym].bindings; - bindings = formatter(bindings); - for (const key in bindings) { - value = bindings[key]; - const valid = key !== "level" && key !== "serializers" && key !== "formatters" && key !== "customLevels" && bindings.hasOwnProperty(key) && value !== void 0; - if (valid === true) { - value = serializers[key] ? serializers[key](value) : value; - value = (stringifiers[key] || wildcardStringifier || stringify3)(value, stringifySafe); - if (value === void 0) continue; - data += ',"' + key + '":' + value; - } - } - return data; - } - function hasBeenTampered(stream) { - return stream.write !== stream.constructor.prototype.write; - } - var hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE; - function buildSafeSonicBoom(opts) { - const stream = new SonicBoom(opts); - stream.on("error", filterBrokenPipe); - if (!hasNodeCodeCoverage && !opts.sync && isMainThread) { - onExit.register(stream, autoEnd); - stream.on("close", function() { - onExit.unregister(stream); - }); - } - return stream; - function filterBrokenPipe(err) { - if (err.code === "EPIPE") { - stream.write = noop; - stream.end = noop; - stream.flushSync = noop; - stream.destroy = noop; - return; - } - stream.removeListener("error", filterBrokenPipe); - stream.emit("error", err); - } - } - function autoEnd(stream, eventName) { - if (stream.destroyed) { - return; - } - if (eventName === "beforeExit") { - stream.flush(); - stream.on("drain", function() { - stream.end(); - }); - } else { - stream.flushSync(); - } - } - function createArgsNormalizer(defaultOptions4) { - return function normalizeArgs(instance, caller, opts = {}, stream) { - if (typeof opts === "string") { - stream = buildSafeSonicBoom({ dest: opts }); - opts = {}; - } else if (typeof stream === "string") { - if (opts && opts.transport) { - throw Error("only one of option.transport or stream can be specified"); - } - stream = buildSafeSonicBoom({ dest: stream }); - } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) { - stream = opts; - opts = {}; - } else if (opts.transport) { - if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) { - throw Error("option.transport do not allow stream, please pass to option directly. e.g. pino(transport)"); - } - if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === "function") { - throw Error("option.transport.targets do not allow custom level formatters"); - } - let customLevels; - if (opts.customLevels) { - customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels); - } - stream = transport({ caller, ...opts.transport, levels: customLevels }); - } - opts = Object.assign({}, defaultOptions4, opts); - opts.serializers = Object.assign({}, defaultOptions4.serializers, opts.serializers); - opts.formatters = Object.assign({}, defaultOptions4.formatters, opts.formatters); - if (opts.prettyPrint) { - throw new Error("prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)"); - } - const { enabled: enabled2, onChild } = opts; - if (enabled2 === false) opts.level = "silent"; - if (!onChild) opts.onChild = noop; - if (!stream) { - if (!hasBeenTampered(process.stdout)) { - stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 }); - } else { - stream = process.stdout; - } - } - return { opts, stream }; - }; - } - function stringify2(obj, stringifySafeFn) { - try { - return JSON.stringify(obj); - } catch (_) { - try { - const stringify3 = stringifySafeFn || this[stringifySafeSym]; - return stringify3(obj); - } catch (_2) { - return '"[unable to serialize, circular reference is too complex to analyze]"'; - } - } - } - function buildFormatters(level, bindings, log2) { - return { - level, - bindings, - log: log2 - }; - } - function normalizeDestFileDescriptor(destination) { - const fd = Number(destination); - if (typeof destination === "string" && Number.isFinite(fd)) { - return fd; - } - if (destination === void 0) { - return 1; - } - return destination; - } - module14.exports = { - noop, - buildSafeSonicBoom, - asChindings, - asJson, - genLog, - createArgsNormalizer, - stringify: stringify2, - buildFormatters, - normalizeDestFileDescriptor - }; - } -}); -var require_constants = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/constants.js"(exports2, module14) { - var DEFAULT_LEVELS = { - trace: 10, - debug: 20, - info: 30, - warn: 40, - error: 50, - fatal: 60 - }; - var SORTING_ORDER = { - ASC: "ASC", - DESC: "DESC" - }; - module14.exports = { - DEFAULT_LEVELS, - SORTING_ORDER - }; - } -}); -var require_levels = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/levels.js"(exports2, module14) { - "use strict"; - var { - lsCacheSym, - levelValSym, - useOnlyCustomLevelsSym, - streamSym, - formattersSym, - hooksSym, - levelCompSym - } = require_symbols2(); - var { noop, genLog } = require_tools(); - var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); - var levelMethods = { - fatal: (hook) => { - const logFatal = genLog(DEFAULT_LEVELS.fatal, hook); - return function(...args) { - const stream = this[streamSym]; - logFatal.call(this, ...args); - if (typeof stream.flushSync === "function") { - try { - stream.flushSync(); - } catch (e2) { - } - } - }; - }, - error: (hook) => genLog(DEFAULT_LEVELS.error, hook), - warn: (hook) => genLog(DEFAULT_LEVELS.warn, hook), - info: (hook) => genLog(DEFAULT_LEVELS.info, hook), - debug: (hook) => genLog(DEFAULT_LEVELS.debug, hook), - trace: (hook) => genLog(DEFAULT_LEVELS.trace, hook) - }; - var nums = Object.keys(DEFAULT_LEVELS).reduce((o2, k) => { - o2[DEFAULT_LEVELS[k]] = k; - return o2; - }, {}); - var initialLsCache = Object.keys(nums).reduce((o2, k) => { - o2[k] = '{"level":' + Number(k); - return o2; - }, {}); - function genLsCache(instance) { - const formatter = instance[formattersSym].level; - const { labels } = instance.levels; - const cache2 = {}; - for (const label in labels) { - const level = formatter(labels[label], Number(label)); - cache2[label] = JSON.stringify(level).slice(0, -1); - } - instance[lsCacheSym] = cache2; - return instance; - } - function isStandardLevel(level, useOnlyCustomLevels) { - if (useOnlyCustomLevels) { - return false; - } - switch (level) { - case "fatal": - case "error": - case "warn": - case "info": - case "debug": - case "trace": - return true; - default: - return false; - } - } - function setLevel(level) { - const { labels, values } = this.levels; - if (typeof level === "number") { - if (labels[level] === void 0) throw Error("unknown level value" + level); - level = labels[level]; - } - if (values[level] === void 0) throw Error("unknown level " + level); - const preLevelVal = this[levelValSym]; - const levelVal = this[levelValSym] = values[level]; - const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]; - const levelComparison = this[levelCompSym]; - const hook = this[hooksSym].logMethod; - for (const key in values) { - if (levelComparison(values[key], levelVal) === false) { - this[key] = noop; - continue; - } - this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook); - } - this.emit( - "level-change", - level, - levelVal, - labels[preLevelVal], - preLevelVal, - this - ); - } - function getLevel(level) { - const { levels, levelVal } = this; - return levels && levels.labels ? levels.labels[levelVal] : ""; - } - function isLevelEnabled(logLevel2) { - const { values } = this.levels; - const logLevelVal = values[logLevel2]; - return logLevelVal !== void 0 && this[levelCompSym](logLevelVal, this[levelValSym]); - } - function compareLevel(direction, current, expected) { - if (direction === SORTING_ORDER.DESC) { - return current <= expected; - } - return current >= expected; - } - function genLevelComparison(levelComparison) { - if (typeof levelComparison === "string") { - return compareLevel.bind(null, levelComparison); - } - return levelComparison; - } - function mappings(customLevels = null, useOnlyCustomLevels = false) { - const customNums = customLevels ? Object.keys(customLevels).reduce((o2, k) => { - o2[customLevels[k]] = k; - return o2; - }, {}) : null; - const labels = Object.assign( - Object.create(Object.prototype, { Infinity: { value: "silent" } }), - useOnlyCustomLevels ? null : nums, - customNums - ); - const values = Object.assign( - Object.create(Object.prototype, { silent: { value: Infinity } }), - useOnlyCustomLevels ? null : DEFAULT_LEVELS, - customLevels - ); - return { labels, values }; - } - function assertDefaultLevelFound(defaultLevel, customLevels, useOnlyCustomLevels) { - if (typeof defaultLevel === "number") { - const values = [].concat( - Object.keys(customLevels || {}).map((key) => customLevels[key]), - useOnlyCustomLevels ? [] : Object.keys(nums).map((level) => +level), - Infinity - ); - if (!values.includes(defaultLevel)) { - throw Error(`default level:${defaultLevel} must be included in custom levels`); - } - return; - } - const labels = Object.assign( - Object.create(Object.prototype, { silent: { value: Infinity } }), - useOnlyCustomLevels ? null : DEFAULT_LEVELS, - customLevels - ); - if (!(defaultLevel in labels)) { - throw Error(`default level:${defaultLevel} must be included in custom levels`); - } - } - function assertNoLevelCollisions(levels, customLevels) { - const { labels, values } = levels; - for (const k in customLevels) { - if (k in values) { - throw Error("levels cannot be overridden"); - } - if (customLevels[k] in labels) { - throw Error("pre-existing level values cannot be used for new levels"); - } - } - } - function assertLevelComparison(levelComparison) { - if (typeof levelComparison === "function") { - return; - } - if (typeof levelComparison === "string" && Object.values(SORTING_ORDER).includes(levelComparison)) { - return; - } - throw new Error('Levels comparison should be one of "ASC", "DESC" or "function" type'); - } - module14.exports = { - initialLsCache, - genLsCache, - levelMethods, - getLevel, - setLevel, - isLevelEnabled, - mappings, - assertNoLevelCollisions, - assertDefaultLevelFound, - genLevelComparison, - assertLevelComparison - }; - } -}); -var require_meta = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/meta.js"(exports2, module14) { - "use strict"; - module14.exports = { version: "8.19.0" }; - } -}); -var require_proto = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports2, module14) { - "use strict"; - var { EventEmitter } = __require2("events"); - var { - lsCacheSym, - levelValSym, - setLevelSym, - getLevelSym, - chindingsSym, - parsedChindingsSym, - mixinSym, - asJsonSym, - writeSym, - mixinMergeStrategySym, - timeSym, - timeSliceIndexSym, - streamSym, - serializersSym, - formattersSym, - errorKeySym, - messageKeySym, - useOnlyCustomLevelsSym, - needsMetadataGsym, - redactFmtSym, - stringifySym, - formatOptsSym, - stringifiersSym, - msgPrefixSym - } = require_symbols2(); - var { - getLevel, - setLevel, - isLevelEnabled, - mappings, - initialLsCache, - genLsCache, - assertNoLevelCollisions - } = require_levels(); - var { - asChindings, - asJson, - buildFormatters, - stringify: stringify2 - } = require_tools(); - var { - version: version3 - } = require_meta(); - var redaction = require_redaction(); - var constructor = class Pino { - }; - var prototype = { - constructor, - child, - bindings, - setBindings, - flush, - isLevelEnabled, - version: version3, - get level() { - return this[getLevelSym](); - }, - set level(lvl) { - this[setLevelSym](lvl); - }, - get levelVal() { - return this[levelValSym]; - }, - set levelVal(n) { - throw Error("levelVal is read-only"); - }, - [lsCacheSym]: initialLsCache, - [writeSym]: write, - [asJsonSym]: asJson, - [getLevelSym]: getLevel, - [setLevelSym]: setLevel - }; - Object.setPrototypeOf(prototype, EventEmitter.prototype); - module14.exports = function() { - return Object.create(prototype); - }; - var resetChildingsFormatter = (bindings2) => bindings2; - function child(bindings2, options2) { - if (!bindings2) { - throw Error("missing bindings for child Pino"); - } - options2 = options2 || {}; - const serializers = this[serializersSym]; - const formatters = this[formattersSym]; - const instance = Object.create(this); - if (options2.hasOwnProperty("serializers") === true) { - instance[serializersSym] = /* @__PURE__ */ Object.create(null); - for (const k in serializers) { - instance[serializersSym][k] = serializers[k]; - } - const parentSymbols = Object.getOwnPropertySymbols(serializers); - for (var i2 = 0; i2 < parentSymbols.length; i2++) { - const ks = parentSymbols[i2]; - instance[serializersSym][ks] = serializers[ks]; - } - for (const bk in options2.serializers) { - instance[serializersSym][bk] = options2.serializers[bk]; - } - const bindingsSymbols = Object.getOwnPropertySymbols(options2.serializers); - for (var bi = 0; bi < bindingsSymbols.length; bi++) { - const bks = bindingsSymbols[bi]; - instance[serializersSym][bks] = options2.serializers[bks]; - } - } else instance[serializersSym] = serializers; - if (options2.hasOwnProperty("formatters")) { - const { level, bindings: chindings, log: log2 } = options2.formatters; - instance[formattersSym] = buildFormatters( - level || formatters.level, - chindings || resetChildingsFormatter, - log2 || formatters.log - ); - } else { - instance[formattersSym] = buildFormatters( - formatters.level, - resetChildingsFormatter, - formatters.log - ); - } - if (options2.hasOwnProperty("customLevels") === true) { - assertNoLevelCollisions(this.levels, options2.customLevels); - instance.levels = mappings(options2.customLevels, instance[useOnlyCustomLevelsSym]); - genLsCache(instance); - } - if (typeof options2.redact === "object" && options2.redact !== null || Array.isArray(options2.redact)) { - instance.redact = options2.redact; - const stringifiers = redaction(instance.redact, stringify2); - const formatOpts = { stringify: stringifiers[redactFmtSym] }; - instance[stringifySym] = stringify2; - instance[stringifiersSym] = stringifiers; - instance[formatOptsSym] = formatOpts; - } - if (typeof options2.msgPrefix === "string") { - instance[msgPrefixSym] = (this[msgPrefixSym] || "") + options2.msgPrefix; - } - instance[chindingsSym] = asChindings(instance, bindings2); - const childLevel = options2.level || this.level; - instance[setLevelSym](childLevel); - this.onChild(instance); - return instance; - } - function bindings() { - const chindings = this[chindingsSym]; - const chindingsJson = `{${chindings.substr(1)}}`; - const bindingsFromJson = JSON.parse(chindingsJson); - delete bindingsFromJson.pid; - delete bindingsFromJson.hostname; - return bindingsFromJson; - } - function setBindings(newBindings) { - const chindings = asChindings(this, newBindings); - this[chindingsSym] = chindings; - delete this[parsedChindingsSym]; - } - function defaultMixinMergeStrategy(mergeObject, mixinObject) { - return Object.assign(mixinObject, mergeObject); - } - function write(_obj, msg, num) { - const t = this[timeSym](); - const mixin3 = this[mixinSym]; - const errorKey = this[errorKeySym]; - const messageKey = this[messageKeySym]; - const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy; - let obj; - if (_obj === void 0 || _obj === null) { - obj = {}; - } else if (_obj instanceof Error) { - obj = { [errorKey]: _obj }; - if (msg === void 0) { - msg = _obj.message; - } - } else { - obj = _obj; - if (msg === void 0 && _obj[messageKey] === void 0 && _obj[errorKey]) { - msg = _obj[errorKey].message; - } - } - if (mixin3) { - obj = mixinMergeStrategy(obj, mixin3(obj, num, this)); - } - const s = this[asJsonSym](obj, msg, num, t); - const stream = this[streamSym]; - if (stream[needsMetadataGsym] === true) { - stream.lastLevel = num; - stream.lastObj = obj; - stream.lastMsg = msg; - stream.lastTime = t.slice(this[timeSliceIndexSym]); - stream.lastLogger = this; - } - stream.write(s); - } - function noop() { - } - function flush(cb) { - if (cb != null && typeof cb !== "function") { - throw Error("callback must be a function"); - } - const stream = this[streamSym]; - if (typeof stream.flush === "function") { - stream.flush(cb || noop); - } else if (cb) cb(); - } - } -}); -var require_safe_stable_stringify = __commonJS({ - "node_modules/.deno/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports2, module14) { - "use strict"; - var { hasOwnProperty } = Object.prototype; - var stringify2 = configure(); - stringify2.configure = configure; - stringify2.stringify = stringify2; - stringify2.default = stringify2; - exports2.stringify = stringify2; - exports2.configure = configure; - module14.exports = stringify2; - var strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/; - function strEscape(str) { - if (str.length < 5e3 && !strEscapeSequencesRegExp.test(str)) { - return `"${str}"`; - } - return JSON.stringify(str); - } - function sort(array2, comparator) { - if (array2.length > 200 || comparator) { - return array2.sort(comparator); - } - for (let i2 = 1; i2 < array2.length; i2++) { - const currentValue = array2[i2]; - let position = i2; - while (position !== 0 && array2[position - 1] > currentValue) { - array2[position] = array2[position - 1]; - position--; - } - array2[position] = currentValue; - } - return array2; - } - var typedArrayPrototypeGetSymbolToStringTag = Object.getOwnPropertyDescriptor( - Object.getPrototypeOf( - Object.getPrototypeOf( - new Int8Array() - ) - ), - Symbol.toStringTag - ).get; - function isTypedArrayWithEntries(value) { - return typedArrayPrototypeGetSymbolToStringTag.call(value) !== void 0 && value.length !== 0; - } - function stringifyTypedArray(array2, separator, maximumBreadth) { - if (array2.length < maximumBreadth) { - maximumBreadth = array2.length; - } - const whitespace = separator === "," ? "" : " "; - let res = `"0":${whitespace}${array2[0]}`; - for (let i2 = 1; i2 < maximumBreadth; i2++) { - res += `${separator}"${i2}":${whitespace}${array2[i2]}`; - } - return res; - } - function getCircularValueOption(options2) { - if (hasOwnProperty.call(options2, "circularValue")) { - const circularValue = options2.circularValue; - if (typeof circularValue === "string") { - return `"${circularValue}"`; - } - if (circularValue == null) { - return circularValue; - } - if (circularValue === Error || circularValue === TypeError) { - return { - toString() { - throw new TypeError("Converting circular structure to JSON"); - } - }; - } - throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined'); - } - return '"[Circular]"'; - } - function getDeterministicOption(options2) { - let value; - if (hasOwnProperty.call(options2, "deterministic")) { - value = options2.deterministic; - if (typeof value !== "boolean" && typeof value !== "function") { - throw new TypeError('The "deterministic" argument must be of type boolean or comparator function'); - } - } - return value === void 0 ? true : value; - } - function getBooleanOption(options2, key) { - let value; - if (hasOwnProperty.call(options2, key)) { - value = options2[key]; - if (typeof value !== "boolean") { - throw new TypeError(`The "${key}" argument must be of type boolean`); - } - } - return value === void 0 ? true : value; - } - function getPositiveIntegerOption(options2, key) { - let value; - if (hasOwnProperty.call(options2, key)) { - value = options2[key]; - if (typeof value !== "number") { - throw new TypeError(`The "${key}" argument must be of type number`); - } - if (!Number.isInteger(value)) { - throw new TypeError(`The "${key}" argument must be an integer`); - } - if (value < 1) { - throw new RangeError(`The "${key}" argument must be >= 1`); - } - } - return value === void 0 ? Infinity : value; - } - function getItemCount(number3) { - if (number3 === 1) { - return "1 item"; - } - return `${number3} items`; - } - function getUniqueReplacerSet(replacerArray) { - const replacerSet = /* @__PURE__ */ new Set(); - for (const value of replacerArray) { - if (typeof value === "string" || typeof value === "number") { - replacerSet.add(String(value)); - } - } - return replacerSet; - } - function getStrictOption(options2) { - if (hasOwnProperty.call(options2, "strict")) { - const value = options2.strict; - if (typeof value !== "boolean") { - throw new TypeError('The "strict" argument must be of type boolean'); - } - if (value) { - return (value2) => { - let message = `Object can not safely be stringified. Received type ${typeof value2}`; - if (typeof value2 !== "function") message += ` (${value2.toString()})`; - throw new Error(message); - }; - } - } - } - function configure(options2) { - options2 = { ...options2 }; - const fail = getStrictOption(options2); - if (fail) { - if (options2.bigint === void 0) { - options2.bigint = false; - } - if (!("circularValue" in options2)) { - options2.circularValue = Error; - } - } - const circularValue = getCircularValueOption(options2); - const bigint2 = getBooleanOption(options2, "bigint"); - const deterministic = getDeterministicOption(options2); - const comparator = typeof deterministic === "function" ? deterministic : void 0; - const maximumDepth = getPositiveIntegerOption(options2, "maximumDepth"); - const maximumBreadth = getPositiveIntegerOption(options2, "maximumBreadth"); - function stringifyFnReplacer(key, parent, stack, replacer, spacer, indentation) { - let value = parent[key]; - if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { - value = value.toJSON(key); - } - value = replacer.call(parent, key, value); - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - let res = ""; - let join92 = ","; - const originalIndentation = indentation; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - if (spacer !== "") { - indentation += spacer; - res += ` -${indentation}`; - join92 = `, -${indentation}`; - } - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += join92; - } - const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `${join92}"... ${getItemCount(removedKeys)} not stringified"`; - } - if (spacer !== "") { - res += ` -${originalIndentation}`; - } - stack.pop(); - return `[${res}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - let whitespace = ""; - let separator = ""; - if (spacer !== "") { - indentation += spacer; - join92 = `, -${indentation}`; - whitespace = " "; - } - const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (deterministic && !isTypedArrayWithEntries(value)) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join92; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`; - separator = join92; - } - if (spacer !== "" && separator.length > 1) { - res = ` -${indentation}${res} -${originalIndentation}`; - } - stack.pop(); - return `{${res}}`; - } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; - } - } - function stringifyArrayReplacer(key, value, stack, replacer, spacer, indentation) { - if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { - value = value.toJSON(key); - } - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - const originalIndentation = indentation; - let res = ""; - let join92 = ","; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - if (spacer !== "") { - indentation += spacer; - res += ` -${indentation}`; - join92 = `, -${indentation}`; - } - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += join92; - } - const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `${join92}"... ${getItemCount(removedKeys)} not stringified"`; - } - if (spacer !== "") { - res += ` -${originalIndentation}`; - } - stack.pop(); - return `[${res}]`; - } - stack.push(value); - let whitespace = ""; - if (spacer !== "") { - indentation += spacer; - join92 = `, -${indentation}`; - whitespace = " "; - } - let separator = ""; - for (const key2 of replacer) { - const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join92; - } - } - if (spacer !== "" && separator.length > 1) { - res = ` -${indentation}${res} -${originalIndentation}`; - } - stack.pop(); - return `{${res}}`; - } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; - } - } - function stringifyIndent(key, value, stack, spacer, indentation) { - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (typeof value.toJSON === "function") { - value = value.toJSON(key); - if (typeof value !== "object") { - return stringifyIndent(key, value, stack, spacer, indentation); - } - if (value === null) { - return "null"; - } - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - const originalIndentation = indentation; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - indentation += spacer; - let res2 = ` -${indentation}`; - const join10 = `, -${indentation}`; - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); - res2 += tmp2 !== void 0 ? tmp2 : "null"; - res2 += join10; - } - const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); - res2 += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res2 += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; - } - res2 += ` -${originalIndentation}`; - stack.pop(); - return `[${res2}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - indentation += spacer; - const join92 = `, -${indentation}`; - let res = ""; - let separator = ""; - let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (isTypedArrayWithEntries(value)) { - res += stringifyTypedArray(value, join92, maximumBreadth); - keys = keys.slice(value.length); - maximumPropertiesToStringify -= value.length; - separator = join92; - } - if (deterministic) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}: ${tmp}`; - separator = join92; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`; - separator = join92; - } - if (separator !== "") { - res = ` -${indentation}${res} -${originalIndentation}`; - } - stack.pop(); - return `{${res}}`; - } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; - } - } - function stringifySimple(key, value, stack) { - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (typeof value.toJSON === "function") { - value = value.toJSON(key); - if (typeof value !== "object") { - return stringifySimple(key, value, stack); - } - if (value === null) { - return "null"; - } - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - let res = ""; - const hasLength = value.length !== void 0; - if (hasLength && Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifySimple(String(i2), value[i2], stack); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += ","; - } - const tmp = stringifySimple(String(i2), value[i2], stack); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `,"... ${getItemCount(removedKeys)} not stringified"`; - } - stack.pop(); - return `[${res}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - let separator = ""; - let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (hasLength && isTypedArrayWithEntries(value)) { - res += stringifyTypedArray(value, ",", maximumBreadth); - keys = keys.slice(value.length); - maximumPropertiesToStringify -= value.length; - separator = ","; - } - if (deterministic) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifySimple(key2, value[key2], stack); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${tmp}`; - separator = ","; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`; - } - stack.pop(); - return `{${res}}`; - } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; - } - } - function stringify3(value, replacer, space) { - if (arguments.length > 1) { - let spacer = ""; - if (typeof space === "number") { - spacer = " ".repeat(Math.min(space, 10)); - } else if (typeof space === "string") { - spacer = space.slice(0, 10); - } - if (replacer != null) { - if (typeof replacer === "function") { - return stringifyFnReplacer("", { "": value }, [], replacer, spacer, ""); - } - if (Array.isArray(replacer)) { - return stringifyArrayReplacer("", value, [], getUniqueReplacerSet(replacer), spacer, ""); - } - } - if (spacer.length !== 0) { - return stringifyIndent("", value, [], spacer, ""); - } - } - return stringifySimple("", value, []); - } - return stringify3; - } - } -}); -var require_multistream = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/multistream.js"(exports2, module14) { - "use strict"; - var metadata = Symbol.for("pino.metadata"); - var { DEFAULT_LEVELS } = require_constants(); - var DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info; - function multistream(streamsArray, opts) { - let counter = 0; - streamsArray = streamsArray || []; - opts = opts || { dedupe: false }; - const streamLevels = Object.create(DEFAULT_LEVELS); - streamLevels.silent = Infinity; - if (opts.levels && typeof opts.levels === "object") { - Object.keys(opts.levels).forEach((i2) => { - streamLevels[i2] = opts.levels[i2]; - }); - } - const res = { - write, - add, - flushSync, - end, - minLevel: 0, - streams: [], - clone: clone2, - [metadata]: true, - streamLevels - }; - if (Array.isArray(streamsArray)) { - streamsArray.forEach(add, res); - } else { - add.call(res, streamsArray); - } - streamsArray = null; - return res; - function write(data) { - let dest; - const level = this.lastLevel; - const { streams } = this; - let recordedLevel = 0; - let stream; - for (let i2 = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i2, streams.length, opts.dedupe); i2 = adjustLoopVar(i2, opts.dedupe)) { - dest = streams[i2]; - if (dest.level <= level) { - if (recordedLevel !== 0 && recordedLevel !== dest.level) { - break; - } - stream = dest.stream; - if (stream[metadata]) { - const { lastTime, lastMsg, lastObj, lastLogger } = this; - stream.lastLevel = level; - stream.lastTime = lastTime; - stream.lastMsg = lastMsg; - stream.lastObj = lastObj; - stream.lastLogger = lastLogger; - } - stream.write(data); - if (opts.dedupe) { - recordedLevel = dest.level; - } - } else if (!opts.dedupe) { - break; - } - } - } - function flushSync() { - for (const { stream } of this.streams) { - if (typeof stream.flushSync === "function") { - stream.flushSync(); - } - } - } - function add(dest) { - if (!dest) { - return res; - } - const isStream = typeof dest.write === "function" || dest.stream; - const stream_ = dest.write ? dest : dest.stream; - if (!isStream) { - throw Error("stream object needs to implement either StreamEntry or DestinationStream interface"); - } - const { streams, streamLevels: streamLevels2 } = this; - let level; - if (typeof dest.levelVal === "number") { - level = dest.levelVal; - } else if (typeof dest.level === "string") { - level = streamLevels2[dest.level]; - } else if (typeof dest.level === "number") { - level = dest.level; - } else { - level = DEFAULT_INFO_LEVEL; - } - const dest_ = { - stream: stream_, - level, - levelVal: void 0, - id: counter++ - }; - streams.unshift(dest_); - streams.sort(compareByLevel); - this.minLevel = streams[0].level; - return res; - } - function end() { - for (const { stream } of this.streams) { - if (typeof stream.flushSync === "function") { - stream.flushSync(); - } - stream.end(); - } - } - function clone2(level) { - const streams = new Array(this.streams.length); - for (let i2 = 0; i2 < streams.length; i2++) { - streams[i2] = { - level, - stream: this.streams[i2].stream - }; - } - return { - write, - add, - minLevel: level, - streams, - clone: clone2, - flushSync, - [metadata]: true - }; - } - } - function compareByLevel(a, b) { - return a.level - b.level; - } - function initLoopVar(length2, dedupe) { - return dedupe ? length2 - 1 : 0; - } - function adjustLoopVar(i2, dedupe) { - return dedupe ? i2 - 1 : i2 + 1; - } - function checkLoopVar(i2, length2, dedupe) { - return dedupe ? i2 >= 0 : i2 < length2; - } - module14.exports = multistream; - } -}); -var require_pino = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports2, module14) { - "use strict"; - var os = __require2("os"); - var stdSerializers = require_pino_std_serializers(); - var caller = require_caller(); - var redaction = require_redaction(); - var time3 = require_time(); - var proto3 = require_proto(); - var symbols2 = require_symbols2(); - var { configure } = require_safe_stable_stringify(); - var { assertDefaultLevelFound, mappings, genLsCache, genLevelComparison, assertLevelComparison } = require_levels(); - var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); - var { - createArgsNormalizer, - asChindings, - buildSafeSonicBoom, - buildFormatters, - stringify: stringify2, - normalizeDestFileDescriptor, - noop - } = require_tools(); - var { version: version3 } = require_meta(); - var { - chindingsSym, - redactFmtSym, - serializersSym, - timeSym, - timeSliceIndexSym, - streamSym, - stringifySym, - stringifySafeSym, - stringifiersSym, - setLevelSym, - endSym, - formatOptsSym, - messageKeySym, - errorKeySym, - nestedKeySym, - mixinSym, - levelCompSym, - useOnlyCustomLevelsSym, - formattersSym, - hooksSym, - nestedKeyStrSym, - mixinMergeStrategySym, - msgPrefixSym - } = symbols2; - var { epochTime, nullTime } = time3; - var { pid } = process; - var hostname2 = os.hostname(); - var defaultErrorSerializer = stdSerializers.err; - var defaultOptions4 = { - level: "info", - levelComparison: SORTING_ORDER.ASC, - levels: DEFAULT_LEVELS, - messageKey: "msg", - errorKey: "err", - nestedKey: null, - enabled: true, - base: { pid, hostname: hostname2 }, - serializers: Object.assign(/* @__PURE__ */ Object.create(null), { - err: defaultErrorSerializer - }), - formatters: Object.assign(/* @__PURE__ */ Object.create(null), { - bindings(bindings) { - return bindings; - }, - level(label, number3) { - return { level: number3 }; - } - }), - hooks: { - logMethod: void 0 - }, - timestamp: epochTime, - name: void 0, - redact: null, - customLevels: null, - useOnlyCustomLevels: false, - depthLimit: 5, - edgeLimit: 100 - }; - var normalize32 = createArgsNormalizer(defaultOptions4); - var serializers = Object.assign(/* @__PURE__ */ Object.create(null), stdSerializers); - function pino2(...args) { - const instance = {}; - const { opts, stream } = normalize32(instance, caller(), ...args); - const { - redact, - crlf, - serializers: serializers2, - timestamp, - messageKey, - errorKey, - nestedKey, - base: base2, - name, - level, - customLevels, - levelComparison, - mixin: mixin3, - mixinMergeStrategy, - useOnlyCustomLevels, - formatters, - hooks, - depthLimit, - edgeLimit, - onChild, - msgPrefix - } = opts; - const stringifySafe = configure({ - maximumDepth: depthLimit, - maximumBreadth: edgeLimit - }); - const allFormatters = buildFormatters( - formatters.level, - formatters.bindings, - formatters.log - ); - const stringifyFn = stringify2.bind({ - [stringifySafeSym]: stringifySafe - }); - const stringifiers = redact ? redaction(redact, stringifyFn) : {}; - const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn }; - const end = "}" + (crlf ? "\r\n" : "\n"); - const coreChindings = asChindings.bind(null, { - [chindingsSym]: "", - [serializersSym]: serializers2, - [stringifiersSym]: stringifiers, - [stringifySym]: stringify2, - [stringifySafeSym]: stringifySafe, - [formattersSym]: allFormatters - }); - let chindings = ""; - if (base2 !== null) { - if (name === void 0) { - chindings = coreChindings(base2); - } else { - chindings = coreChindings(Object.assign({}, base2, { name })); - } - } - const time4 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime; - const timeSliceIndex = time4().indexOf(":") + 1; - if (useOnlyCustomLevels && !customLevels) throw Error("customLevels is required if useOnlyCustomLevels is set true"); - if (mixin3 && typeof mixin3 !== "function") throw Error(`Unknown mixin type "${typeof mixin3}" - expected "function"`); - if (msgPrefix && typeof msgPrefix !== "string") throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`); - assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels); - const levels = mappings(customLevels, useOnlyCustomLevels); - assertLevelComparison(levelComparison); - const levelCompFunc = genLevelComparison(levelComparison); - Object.assign(instance, { - levels, - [levelCompSym]: levelCompFunc, - [useOnlyCustomLevelsSym]: useOnlyCustomLevels, - [streamSym]: stream, - [timeSym]: time4, - [timeSliceIndexSym]: timeSliceIndex, - [stringifySym]: stringify2, - [stringifySafeSym]: stringifySafe, - [stringifiersSym]: stringifiers, - [endSym]: end, - [formatOptsSym]: formatOpts, - [messageKeySym]: messageKey, - [errorKeySym]: errorKey, - [nestedKeySym]: nestedKey, - // protect against injection - [nestedKeyStrSym]: nestedKey ? `,${JSON.stringify(nestedKey)}:{` : "", - [serializersSym]: serializers2, - [mixinSym]: mixin3, - [mixinMergeStrategySym]: mixinMergeStrategy, - [chindingsSym]: chindings, - [formattersSym]: allFormatters, - [hooksSym]: hooks, - silent: noop, - onChild, - [msgPrefixSym]: msgPrefix - }); - Object.setPrototypeOf(instance, proto3()); - genLsCache(instance); - instance[setLevelSym](level); - return instance; - } - module14.exports = pino2; - module14.exports.destination = (dest = process.stdout.fd) => { - if (typeof dest === "object") { - dest.dest = normalizeDestFileDescriptor(dest.dest || process.stdout.fd); - return buildSafeSonicBoom(dest); - } else { - return buildSafeSonicBoom({ dest: normalizeDestFileDescriptor(dest), minLength: 0 }); - } - }; - module14.exports.transport = require_transport(); - module14.exports.multistream = require_multistream(); - module14.exports.levels = mappings(); - module14.exports.stdSerializers = serializers; - module14.exports.stdTimeFunctions = Object.assign({}, time3); - module14.exports.symbols = symbols2; - module14.exports.version = version3; - module14.exports.default = pino2; - module14.exports.pino = pino2; - } -}); -function logMethod(args, method) { - const stringIdx = typeof args[0] === "string" ? 0 : 1; - if (args.length > 1) { - for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { - args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; - } - } - method.apply(this, args); -} -var import_npm_pino; -var prettyPrint; -var logger; -var logLevel; -var logger_default; -var init_logger = __esm({ - "src/serve/logger.ts"() { - "use strict"; - import_npm_pino = __toESM(require_pino()); - prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; - if (prettyPrint) { - try { - logger = (0, import_npm_pino.default)({ - hooks: { logMethod }, - transport: { - target: "pino-pretty", - options: { - colorize: true - } - } - }); - } catch (e2) { - console.warn("pino-pretty transport unavailable, using basic logging", e2); - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); - } - } else { - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); - } - logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); - if (Object.keys(logger.levels.values).includes(logLevel)) { - logger.level = logLevel; - } else { - logger.warn(`Unknown log level: ${logLevel}`); - } - console.debug = logger.debug.bind(logger); - console.info = logger.info.bind(logger); - console.log = logger.info.bind(logger); - console.warn = logger.warn.bind(logger); - console.error = logger.error.bind(logger); - logger_default = logger; - } -}); -var timer; -var coerceToError; -var defaultOptions2; -var tag; -var PersistentAction; -var persistent_actions_default; -var init_persistent_actions = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/persistent-actions.mjs"() { - init_esm4(); - init_esm(); - init_events(); - timer = Symbol("timer"); - coerceToError = (arg) => { - if (arg && arg instanceof Error) - return arg; - console.warn(tag, "Please use Error objects when throwing or rejecting"); - return new Error((typeof arg === "string" ? arg : JSON.stringify(arg)) ?? "undefined"); - }; - defaultOptions2 = { - maxAttempts: Number.POSITIVE_INFINITY, - retrySeconds: 30 - }; - tag = "[chelonia.persistentActions]"; - PersistentAction = class { - id; - invocation; - options; - status; - [timer]; - constructor(invocation, options2 = {}) { - this.id = crypto.randomUUID(); - this.invocation = invocation; - this.options = { ...defaultOptions2, ...options2 }; - this.status = { - attempting: false, - failedAttemptsSoFar: 0, - lastError: "", - nextRetry: "", - resolved: false - }; - } - async attempt() { - if (this.status.attempting || this.status.resolved) - return; - if (await this.trySBP(this.options.skipCondition)) - this.cancel(); - if (this.status.resolved) - return; - try { - this.status.attempting = true; - const result = await esm_default(...this.invocation); - this.status.attempting = false; - this.handleSuccess(result); - } catch (error2) { - this.status.attempting = false; - await this.handleError(coerceToError(error2)); - } - } - cancel() { - if (this[timer]) - clearTimeout(this[timer]); - this.status.nextRetry = ""; - this.status.resolved = true; - } - async handleError(error2) { - const { id, options: options2, status } = this; - status.failedAttemptsSoFar++; - status.lastError = error2.message; - const anyAttemptLeft = options2.maxAttempts > status.failedAttemptsSoFar; - if (!anyAttemptLeft) - status.resolved = true; - status.nextRetry = anyAttemptLeft && !status.resolved ? new Date(Date.now() + options2.retrySeconds * 1e3).toISOString() : ""; - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_FAILURE, { error: error2, id }); - await this.trySBP(options2.errorInvocation); - if (!anyAttemptLeft) { - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_TOTAL_FAILURE, { error: error2, id }); - await this.trySBP(options2.totalFailureInvocation); - } - if (status.nextRetry) { - this[timer] = setTimeout(() => { - this.attempt().catch((e2) => { - console.error("Error attempting persistent action", id, e2); - }); - }, this.options.retrySeconds * 1e3); - } - } - handleSuccess(result) { - const { id, status } = this; - status.lastError = ""; - status.nextRetry = ""; - status.resolved = true; - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_SUCCESS, { id, result }); - } - async trySBP(invocation) { - try { - return invocation ? await esm_default(...invocation) : void 0; - } catch (error2) { - console.error(tag, coerceToError(error2).message); - } - } - }; - persistent_actions_default = esm_default("sbp/selectors/register", { - "chelonia.persistentActions/_init"() { - this.actionsByID = /* @__PURE__ */ Object.create(null); - this.checkDatabaseKey = () => { - if (!this.databaseKey) - throw new TypeError(`${tag} No database key configured`); - }; - esm_default("okTurtles.events/on", PERSISTENT_ACTION_SUCCESS, ({ id }) => { - esm_default("chelonia.persistentActions/cancel", id); - }); - esm_default("okTurtles.events/on", PERSISTENT_ACTION_TOTAL_FAILURE, ({ id }) => { - esm_default("chelonia.persistentActions/cancel", id); - }); - }, - // Cancels a specific action by its ID. - // The action won't be retried again, but an async action cannot be aborted if its promise is stil attempting. - async "chelonia.persistentActions/cancel"(id) { - if (id in this.actionsByID) { - this.actionsByID[id].cancel(); - delete this.actionsByID[id]; - return await esm_default("chelonia.persistentActions/save"); - } - }, - // TODO: validation - "chelonia.persistentActions/configure"({ databaseKey, options: options2 = {} }) { - this.databaseKey = databaseKey; - for (const key in options2) { - if (key in defaultOptions2) { - defaultOptions2[key] = options2[key]; - } else { - throw new TypeError(`${tag} Unknown option: ${key}`); - } - } - }, - "chelonia.persistentActions/enqueue"(...args) { - const ids = []; - for (const arg of args) { - const action = Array.isArray(arg) ? new PersistentAction(arg) : new PersistentAction(arg.invocation, arg); - this.actionsByID[action.id] = action; - ids.push(action.id); - } - esm_default("chelonia.persistentActions/save").catch((e2) => { - console.error("Error saving persistent actions", e2); - }); - for (const id of ids) { - this.actionsByID[id].attempt().catch((e2) => { - console.error("Error attempting persistent action", id, e2); - }); - } - return ids; - }, - // Forces retrying a given persisted action immediately, rather than waiting for the scheduled retry. - // - 'status.failedAttemptsSoFar' will still be increased upon failure. - // - Does nothing if a retry is already running. - // - Does nothing if the action has already been resolved, rejected or cancelled. - "chelonia.persistentActions/forceRetry"(id) { - if (id in this.actionsByID) { - return this.actionsByID[id].attempt(); - } - }, - // Loads and tries every stored persistent action under the configured database key. - async "chelonia.persistentActions/load"() { - this.checkDatabaseKey(); - const storedActions = JSON.parse(await esm_default("chelonia.db/get", this.databaseKey) ?? "[]"); - for (const { id, invocation, options: options2 } of storedActions) { - this.actionsByID[id] = new PersistentAction(invocation, options2); - this.actionsByID[id].id = id; - } - return esm_default("chelonia.persistentActions/retryAll"); - }, - // Retry all existing persisted actions. - // TODO: add some delay between actions so as not to spam the server, - // or have a way to issue them all at once in a single network call. - "chelonia.persistentActions/retryAll"() { - return Promise.allSettled(Object.keys(this.actionsByID).map((id) => esm_default("chelonia.persistentActions/forceRetry", id))); - }, - // Updates the database version of the attempting action list. - "chelonia.persistentActions/save"() { - this.checkDatabaseKey(); - return esm_default("chelonia.db/set", this.databaseKey, JSON.stringify(Object.values(this.actionsByID))); - }, - "chelonia.persistentActions/status"() { - return Object.values(this.actionsByID).map((action) => ({ - id: action.id, - invocation: action.invocation, - ...action.status - })); - }, - // Pauses every currently loaded action, and removes them from memory. - // Note: persistent storage is not affected, so that these actions can be later loaded again and retried. - "chelonia.persistentActions/unload"() { - for (const id in this.actionsByID) { - if (this.actionsByID[id][timer]) { - clearTimeout(this.actionsByID[id][timer]); - } - delete this.actionsByID[id]; - } - } - }); - } -}); -var SERVER; -var init_presets = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/presets.mjs"() { - SERVER = { - // We don't check the subscriptionSet in the server because we accpt new - // contract registrations, and are also not subcribed to contracts the same - // way clients are - acceptAllMessages: true, - // The server also doesn't process actions - skipActionProcessing: true, - // The previous setting implies this one, which we set to be on the safe side - skipSideEffects: true, - // Changes the behaviour of unwrapMaybeEncryptedData so that it never decrypts. - // Mostly useful for the server, to avoid filling up the logs and for faster - // execution. - skipDecryptionAttempts: true, - // If an error occurs during processing, the message is rejected rather than - // ignored - strictProcessing: true, - // The server expects events to be received in order (no past or future events) - strictOrdering: true - }; - } -}); -var createWorker; -var createWorker_default; -var init_createWorker = __esm({ - "src/serve/createWorker.ts"() { - "use strict"; - init_esm8(); - init_esm(); - Object.defineProperties(Buffer13, { - [serdesDeserializeSymbol]: { - value(buf2) { - return Buffer13.from(buf2); - } - }, - [serdesSerializeSymbol]: { - value(buf2) { - return new Uint8Array(buf2.buffer, buf2.byteOffset, buf2.byteLength); - } - }, - [serdesTagSymbol]: { - value: "node:buffer" - } - }); - deserializer.register(Buffer13); - createWorker = (path8) => { - let worker; - let ready; - const launchWorker = () => { - worker = new Worker(new URL(path8, import.meta.url), { type: "module" }); - return new Promise((resolve82, reject) => { - const msgHandler = (event) => { - const msg = event.data; - if (msg === "ready") { - worker.removeEventListener("error", reject, { capture: false }); - worker.addEventListener("error", (ev) => { - const e2 = ev.error; - console.error(e2, `Running worker ${basename52(path8)} terminated. Attempting relaunch...`); - worker.removeEventListener("message", msgHandler, false); - ready = launchWorker().catch((e3) => { - console.error(e3, `Error on worker ${basename52(path8)} relaunch`); - process7.exit(1); - }); - }, false); - resolve82(); - } else if (msg && typeof msg === "object" && msg.type === "sbp" && Array.isArray(msg.data) && String(msg.data[0]).startsWith("chelonia.db/")) { - const port = msg.port; - Promise.try(() => esm_default(...deserializer(msg.data))).then((r) => { - const { data, transferables } = serializer(r); - port.postMessage([true, data], transferables); - }).catch((e2) => { - const { data, transferables } = serializer(e2); - port.postMessage([false, data], transferables); - }).finally(() => { - port.close(); - }); - } - }; - worker.addEventListener("message", msgHandler, false); - worker.addEventListener("error", reject, { capture: false, once: true }); - }); - }; - ready = launchWorker(); - const rpcSbp = (...args) => { - return ready.then(() => new Promise((resolve82, reject) => { - const mc = new MessageChannel(); - const cleanup = /* @__PURE__ */ ((worker2) => () => { - worker2.removeEventListener("error", reject, { capture: true }); - mc.port2.close(); - mc.port2.onmessage = null; - mc.port2.onmessageerror = null; - })(worker); - mc.port2.onmessage = (event) => { - cleanup(); - const [success, result] = event.data; - if (success) return resolve82(result); - reject(result); - }; - mc.port2.onmessageerror = () => { - cleanup(); - reject(new Error("Message error")); - }; - worker.postMessage([mc.port1, ...args], [mc.port1]); - worker.addEventListener("error", reject, { capture: false, once: true }); - })); - }; - return { - ready, - rpcSbp, - terminate: () => worker.terminate() - }; - }; - createWorker_default = createWorker; - } -}); -var import_boom2; -var plugin; -var auth_default; -var init_auth = __esm({ - "src/serve/auth.ts"() { - "use strict"; - init_utils(); - import_boom2 = __toESM(require_lib2()); - plugin = { - name: "chel-auth", - register: function(server) { - server.auth.scheme("chel-bearer", () => { - return { - authenticate: function(request, h2) { - const { authorization } = request.headers; - if (!authorization) { - return h2.unauthenticated(import_boom2.default.unauthorized(null, "bearer")); - } - const thisScheme = "bearer "; - if (authorization.slice(0, thisScheme.length) !== thisScheme) { - return h2.unauthenticated(import_boom2.default.unauthorized(null, "bearer")); - } - const token = authorization.slice(thisScheme.length); - return h2.authenticated({ credentials: { token } }); - } - }; - }); - server.auth.scheme("chel-shelter", () => { - return { - authenticate: function(request, h2) { - const { authorization } = request.headers; - if (!authorization) { - return h2.unauthenticated(import_boom2.default.unauthorized(null, "shelter")); - } - const thisScheme = "shelter "; - if (authorization.slice(0, thisScheme.length) !== thisScheme) { - return h2.unauthenticated(import_boom2.default.unauthorized(null, "shelter")); - } - try { - const billableContractID = verifyShelterAuthorizationHeader(authorization); - return h2.authenticated({ credentials: { billableContractID } }); - } catch (e2) { - console.warn(e2, "Shelter authorization failed"); - return h2.unauthenticated(import_boom2.default.unauthorized("Authentication failed", "shelter")); - } - } - }; - }); - server.auth.strategy("chel-bearer", "chel-bearer"); - server.auth.strategy("chel-shelter", "chel-shelter"); - } - }; - auth_default = plugin; - } -}); -var CREDITS_WORKER_TASK_TIME_INTERVAL; -var OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL; -var init_constants2 = __esm({ - "src/serve/constants.ts"() { - "use strict"; - CREDITS_WORKER_TASK_TIME_INTERVAL = 3e5; - OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL = 3e4; - } -}); -var BackendErrorNotFound; -var BackendErrorGone; -var BackendErrorBadData; -var init_errors4 = __esm({ - "src/serve/errors.ts"() { - "use strict"; - init_errors3(); - BackendErrorNotFound = ChelErrorGenerator("BackendErrorNotFound"); - BackendErrorGone = ChelErrorGenerator("BackendErrorGone"); - BackendErrorBadData = ChelErrorGenerator("BackendErrorBadData"); - } -}); -var x2; -var init_encodings2 = __esm({ - "node_modules/.deno/@apeleghq+rfc8188@1.0.7/node_modules/@apeleghq/rfc8188/dist/encodings.mjs"() { - x2 = { params: { name: "AES-GCM", length: 128 }, get cek_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 49, 50, 56, 103, 99, 109, 0]); - }, get nonce_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); - }, block_size: 16, tag_length: 16, nonce_length: 12 }; - } -}); -var R3; -var E2; -var B3; -var w3; -var N10; -var U2; -var K2; -var init_encrypt2 = __esm({ - "node_modules/.deno/@apeleghq+rfc8188@1.0.7/node_modules/@apeleghq/rfc8188/dist/encrypt.mjs"() { - R3 = async (e2, b, f, i2) => { - let A2 = await globalThis.crypto.subtle.importKey("raw", b, "HKDF", false, ["deriveKey", "deriveBits"]), y = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: e2.cek_info, salt: f }, A2, e2.params, false, i2), u2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: e2.nonce_info, salt: f }, A2, e2.nonce_length << 3); - return [y, function* () { - let L = new ArrayBuffer(e2.nonce_length), c = new DataView(L), h2 = new Uint8Array(L), a = new Uint8Array(u2), g2 = 4294967295, o2 = (e2.nonce_length >> 2) - 1, s = new Array(o2).fill(0); - for (; ; ) { - for (let t = 0; t <= g2; t++) { - c.setUint32(c.byteLength - 4, t, false); - let n = new Uint8Array(e2.nonce_length); - for (let r = 0; r < n.length; r++) n[r] = a[r] ^ h2[r]; - yield n; - } - for (let t = 0; t < o2; t++) { - if (t === o2 - 1 && s[t] === g2) throw new RangeError("Maximum number of segments exceeded"); - if (s[t] = (s[t] + 1) % (g2 + 1), c.setUint32(c.byteLength - 4 * (t + 2), s[t], false), s[t] !== 0) break; - } - } - }()]; - }; - E2 = R3; - B3 = (e2) => ArrayBuffer.isView(e2) ? new Uint8Array(e2.buffer).subarray(e2.byteOffset, e2.byteOffset + e2.byteLength) : new Uint8Array(e2); - w3 = B3; - N10 = () => { - let e2 = new Uint8Array(16); - return globalThis.crypto.getRandomValues(e2), e2; - }; - U2 = async (e2, b, f, i2, A2, y) => { - if (f <= e2.tag_length + 1 || f > 4294967295) throw new RangeError("Invalid record size: " + f); - if (i2.byteLength > 255) throw new RangeError("Key ID too long"); - if (y && y.byteLength !== 16) throw new RangeError("Invald salt length: " + y.byteLength); - let u2 = f - e2.tag_length - 1, l = y ? w3(y) : N10(), [L, c] = await E2(e2, A2, l, ["encrypt"]); - A2 = void 0; - let h2 = new Uint8Array(u2), a = 0, g2 = new TransformStream({ start: (o2) => { - let s = l.byteLength + 4 + 1 + i2.byteLength, t = new ArrayBuffer(s); - new Uint8Array(t, 0, l.byteLength).set(l); - let r = new DataView(t, l.byteLength, 5); - r.setUint32(0, f, false), r.setUint8(4, i2.byteLength); - let d = new Uint8Array(t, l.byteLength + 4 + 1, i2.byteLength), m3 = w3(i2); - d.set(m3), o2.enqueue(t); - }, transform: async (o2, s) => { - let t = w3(o2), n = 0; - for (; n < o2.byteLength; ) { - let r = t.subarray(n, n + u2 - a); - if (h2.set(r, a), a += r.byteLength, n += r.byteLength, a === u2) { - let m3 = c.next().value, p = new Uint8Array(u2 + 1); - p.set(h2.subarray(0, a)), p[a] = 1; - let T2 = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: m3, tagLength: e2.tag_length << 3 }, L, p); - s.enqueue(T2), a = 0; - } - } - }, flush: async (o2) => { - let t = c.next().value, n = new Uint8Array(a + 1); - n.set(h2.subarray(0, a)), n[a] = 2; - let r = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: t, tagLength: e2.tag_length << 3 }, L, n); - o2.enqueue(r), h2.fill(0), n.fill(0); - } }); - return b.pipeThrough(g2), g2.readable; - }; - K2 = U2; - } -}); -var rfc8291Ikm_default; -var init_rfc8291Ikm = __esm({ - "src/serve/rfc8291Ikm.ts"() { - "use strict"; - rfc8291Ikm_default = async (uaPublic, salt) => { - const [[asPrivateKey, asPublic], uaPublicKey] = await Promise.all([ - crypto.subtle.generateKey( - { - name: "ECDH", - namedCurve: "P-256" - }, - false, - ["deriveKey"] - ).then(async (asKeyPair) => { - const asPublic2 = await crypto.subtle.exportKey( - "raw", - asKeyPair.publicKey - ); - return [asKeyPair.privateKey, asPublic2]; - }), - crypto.subtle.importKey( - "raw", - uaPublic, - { name: "ECDH", namedCurve: "P-256" }, - false, - [] - ) - ]); - const ecdhSecret = await crypto.subtle.deriveKey( - { - name: "ECDH", - public: uaPublicKey - }, - asPrivateKey, - { - name: "HKDF", - hash: "SHA-256" - }, - false, - ["deriveBits"] - ); - const infoString = new Uint8Array([ - 87, - 101, - 98, - 80, - 117, - 115, - 104, - 58, - 32, - 105, - 110, - 102, - 111, - 0 - ]); - const info = new Uint8Array(infoString.byteLength + uaPublic.byteLength + asPublic.byteLength); - info.set(infoString, 0); - info.set(uaPublic, infoString.byteLength); - info.set( - new Uint8Array(asPublic), - infoString.byteLength + uaPublic.byteLength - ); - const IKM = await crypto.subtle.deriveBits( - { - name: "HKDF", - hash: "SHA-256", - salt, - info - }, - ecdhSecret, - 32 << 3 - ); - return [asPublic, IKM]; - }; - } -}); -var addSubscriptionToIndex; -var deleteSubscriptionFromIndex; -var saveSubscription; -var addChannelToSubscription; -var deleteChannelFromSubscription; -var removeSubscription; -var subscriptionInfoWrapper; -var encryptPayload; -var postEvent; -var pushServerActionhandlers; -var init_push = __esm({ - "src/serve/push.ts"() { - "use strict"; - init_encodings2(); - init_encrypt2(); - init_functions(); - init_pubsub(); - init_esm(); - init_database(); - init_instance_keys(); - init_rfc8291Ikm(); - init_vapid(); - addSubscriptionToIndex = appendToIndexFactory("_private_webpush_index"); - deleteSubscriptionFromIndex = removeFromIndexFactory("_private_webpush_index"); - saveSubscription = (server, subscriptionId) => { - return esm_default("chelonia.db/set", `_private_webpush_${subscriptionId}`, JSON.stringify({ - settings: server.pushSubscriptions[subscriptionId].settings, - subscriptionInfo: server.pushSubscriptions[subscriptionId], - channelIDs: [...server.pushSubscriptions[subscriptionId].subscriptions] - })).catch((e2) => { - console.error(e2, "Error saving subscription", subscriptionId); - throw e2; - }); - }; - addChannelToSubscription = (server, subscriptionId, channelID) => { - server.pushSubscriptions[subscriptionId].subscriptions.add(channelID); - return saveSubscription(server, subscriptionId); - }; - deleteChannelFromSubscription = (server, subscriptionId, channelID) => { - server.pushSubscriptions[subscriptionId].subscriptions.delete(channelID); - return saveSubscription(server, subscriptionId); - }; - removeSubscription = async (subscriptionId) => { - try { - const server = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const subscription = server.pushSubscriptions[subscriptionId]; - if (subscription) { - delete server.pushSubscriptions[subscriptionId]; - if (server.subscribersByChannelID) { - subscription.subscriptions.forEach((channelID) => { - server.subscribersByChannelID[channelID]?.delete(subscription); - }); - } - } else { - } - await esm_default("chelonia.db/delete", `_private_webpush_${subscriptionId}`); - await deleteSubscriptionFromIndex(subscriptionId); - } catch (e2) { - console.error(e2, "Error removing subscription", subscriptionId); - } - }; - subscriptionInfoWrapper = (subscriptionId, subscriptionInfo, extra) => { - subscriptionInfo.endpoint = new URL(subscriptionInfo.endpoint); - Object.defineProperties(subscriptionInfo, { - "id": { - get() { - return subscriptionId; - } - }, - // These encryption keys are used for encrypting push notification bodies - // and are unrelated to VAPID, which is used for provenance. - "encryptionKeys": { - get: /* @__PURE__ */ (() => { - let count = 0; - let resultPromise; - let salt; - let uaPublic; - return function() { - if ((count | 0) === 0) { - if (!salt) { - salt = Buffer14.from(this.keys.auth, "base64url"); - } - if (!uaPublic) { - uaPublic = Buffer14.from(this.keys.p256dh, "base64url"); - } - resultPromise = rfc8291Ikm_default(uaPublic, salt); - count = 1; - } else { - count++; - } - return resultPromise; - }; - })() - }, - "settings": { - value: extra.settings || {} - }, - "sockets": { - value: /* @__PURE__ */ new Set() - }, - "subscriptions": { - value: new Set(extra.channelIDs) - } - }); - Object.freeze(subscriptionInfo); - return subscriptionInfo; - }; - encryptPayload = async (subscription, data) => { - const readableStream = new Response(data).body; - if (!readableStream) throw new Error("Failed to create readable stream"); - const [asPublic, IKM] = await subscription.encryptionKeys; - return K2(x2, readableStream, 32768, asPublic, IKM).then(async (bodyStream) => { - const chunks = []; - const reader = bodyStream.getReader(); - for (; ; ) { - const { done, value } = await reader.read(); - if (done) break; - chunks.push(new Uint8Array(value)); - } - return Buffer14.concat(chunks); - }); - }; - postEvent = async (subscription, event) => { - const authorization = await vapidAuthorization(subscription.endpoint); - const body = event ? await encryptPayload(subscription, event) : void 0; - const req = await fetch(subscription.endpoint, { - method: "POST", - headers: [ - ["authorization", authorization], - ...body ? [ - ["content-encoding", "aes128gcm"], - [ - "content-type", - "application/octet-stream" - ] - ] : [], - // ['push-receipt', ''], - ["ttl", "60"] - ], - body - }); - if (!req.ok) { - const endpointHost = new URL(subscription.endpoint).host; - console.info( - await req.text().then((response) => ({ response })).catch((e2) => `ERR: ${e2?.message}`), - `Error ${req.status} sending push notification to '${subscription.id}' via ${endpointHost}` - ); - if ([401, 404, 410].includes(req.status)) { - removeSubscription(subscription.id); - throw new Error(`Error sending push: ${req.status}`); - } - if (req.status === 413) { - throw new Error("Payload too large"); - } - } - }; - pushServerActionhandlers = { - [PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY]() { - const socket = this; - socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); - }, - async [PUSH_SERVER_ACTION_TYPE.STORE_SUBSCRIPTION](payload) { - const socket = this; - const { server } = socket; - const { applicationServerKey, settings, subscriptionInfo } = payload; - if (applicationServerKey) { - const ourVapidPublicKey = getVapidPublicKey(); - const theirVapidPublicKey = Buffer14.from(applicationServerKey, "base64").toString("base64url"); - if (ourVapidPublicKey !== theirVapidPublicKey) { - socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); - console.warn({ ourVapidPublicKey, theirVapidPublicKey }, "Refusing to store subscription because the associated public VAPID key does not match ours"); - return; - } - } - let subscriptionId = null; - let host = ""; - let subscriptionWrapper = null; - try { - subscriptionId = await getSubscriptionId(subscriptionInfo); - subscriptionWrapper = server.pushSubscriptions[subscriptionId]; - if (!subscriptionWrapper) { - console.debug(`saving new push subscription '${subscriptionId}':`, subscriptionInfo); - server.pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { settings }); - subscriptionWrapper = server.pushSubscriptions[subscriptionId]; - host = subscriptionWrapper.endpoint.host; - await addSubscriptionToIndex(subscriptionId); - await saveSubscription(server, subscriptionId); - await postEvent(subscriptionWrapper, JSON.stringify({ type: "initial" })); - } else { - host = subscriptionWrapper.endpoint.host; - if (subscriptionWrapper.sockets.size === 0) { - subscriptionWrapper.subscriptions.forEach((channelID) => { - if (!server.subscribersByChannelID[channelID]) return; - server.subscribersByChannelID[channelID].delete(subscriptionWrapper); - }); - } - } - if (socket.pushSubscriptionId) { - if (socket.pushSubscriptionId === subscriptionId) return; - await removeSubscription(socket.pushSubscriptionId); - } - socket.pushSubscriptionId = subscriptionId; - subscriptionWrapper.subscriptions.forEach((channelID) => { - server.subscribersByChannelID[channelID]?.delete(subscriptionWrapper); - }); - subscriptionWrapper.sockets.add(socket); - socket.subscriptions?.forEach((channelID) => { - subscriptionWrapper.subscriptions.add(channelID); - }); - await saveSubscription(server, subscriptionId); - } catch (e2) { - console.error(e2, `[${socket.ip}] Failed to store subscription '${subscriptionId || "??"}' (${host}), removing it!`); - subscriptionId && removeSubscription(subscriptionId); - throw e2; - } - }, - [PUSH_SERVER_ACTION_TYPE.DELETE_SUBSCRIPTION]() { - const socket = this; - const { pushSubscriptionId: subscriptionId } = socket; - if (subscriptionId) { - return removeSubscription(subscriptionId); - } - } - }; - } -}); -var require_stream = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/stream.js"(exports2, module14) { - "use strict"; - var { Duplex } = __require2("stream"); - function emitClose(stream) { - stream.emit("close"); - } - function duplexOnEnd() { - if (!this.destroyed && this._writableState.finished) { - this.destroy(); - } - } - function duplexOnError(err) { - this.removeListener("error", duplexOnError); - this.destroy(); - if (this.listenerCount("error") === 0) { - this.emit("error", err); - } - } - function createWebSocketStream2(ws, options2) { - let terminateOnDestroy = true; - const duplex = new Duplex({ - ...options2, - autoDestroy: false, - emitClose: false, - objectMode: false, - writableObjectMode: false - }); - ws.on("message", function message(msg, isBinary) { - const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; - if (!duplex.push(data)) ws.pause(); - }); - ws.once("error", function error2(err) { - if (duplex.destroyed) return; - terminateOnDestroy = false; - duplex.destroy(err); - }); - ws.once("close", function close() { - if (duplex.destroyed) return; - duplex.push(null); - }); - duplex._destroy = function(err, callback) { - if (ws.readyState === ws.CLOSED) { - callback(err); - process.nextTick(emitClose, duplex); - return; - } - let called = false; - ws.once("error", function error2(err2) { - called = true; - callback(err2); - }); - ws.once("close", function close() { - if (!called) callback(err); - process.nextTick(emitClose, duplex); - }); - if (terminateOnDestroy) ws.terminate(); - }; - duplex._final = function(callback) { - if (ws.readyState === ws.CONNECTING) { - ws.once("open", function open() { - duplex._final(callback); - }); - return; - } - if (ws._socket === null) return; - if (ws._socket._writableState.finished) { - callback(); - if (duplex._readableState.endEmitted) duplex.destroy(); - } else { - ws._socket.once("finish", function finish() { - callback(); - }); - ws.close(); - } - }; - duplex._read = function() { - if (ws.isPaused) ws.resume(); - }; - duplex._write = function(chunk, encoding, callback) { - if (ws.readyState === ws.CONNECTING) { - ws.once("open", function open() { - duplex._write(chunk, encoding, callback); - }); - return; - } - ws.send(chunk, callback); - }; - duplex.on("end", duplexOnEnd); - duplex.on("error", duplexOnError); - return duplex; - } - module14.exports = createWebSocketStream2; - } -}); -var require_constants2 = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/constants.js"(exports2, module14) { - "use strict"; - module14.exports = { - BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], - EMPTY_BUFFER: Buffer.alloc(0), - GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", - kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), - kListener: Symbol("kListener"), - kStatusCode: Symbol("status-code"), - kWebSocket: Symbol("websocket"), - NOOP: () => { - } - }; - } -}); -var require_buffer_util = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/buffer-util.js"(exports2, module14) { - "use strict"; - var { EMPTY_BUFFER } = require_constants2(); - function concat2(list, totalLength) { - if (list.length === 0) return EMPTY_BUFFER; - if (list.length === 1) return list[0]; - const target = Buffer.allocUnsafe(totalLength); - let offset = 0; - for (let i2 = 0; i2 < list.length; i2++) { - const buf2 = list[i2]; - target.set(buf2, offset); - offset += buf2.length; - } - if (offset < totalLength) return target.slice(0, offset); - return target; - } - function _mask(source, mask, output, offset, length2) { - for (let i2 = 0; i2 < length2; i2++) { - output[offset + i2] = source[i2] ^ mask[i2 & 3]; - } - } - function _unmask(buffer, mask) { - for (let i2 = 0; i2 < buffer.length; i2++) { - buffer[i2] ^= mask[i2 & 3]; - } - } - function toArrayBuffer(buf2) { - if (buf2.byteLength === buf2.buffer.byteLength) { - return buf2.buffer; - } - return buf2.buffer.slice(buf2.byteOffset, buf2.byteOffset + buf2.byteLength); - } - function toBuffer(data) { - toBuffer.readOnly = true; - if (Buffer.isBuffer(data)) return data; - let buf2; - if (data instanceof ArrayBuffer) { - buf2 = Buffer.from(data); - } else if (ArrayBuffer.isView(data)) { - buf2 = Buffer.from(data.buffer, data.byteOffset, data.byteLength); - } else { - buf2 = Buffer.from(data); - toBuffer.readOnly = false; - } - return buf2; - } - try { - const bufferUtil = __require2("bufferutil"); - module14.exports = { - concat: concat2, - mask(source, mask, output, offset, length2) { - if (length2 < 48) _mask(source, mask, output, offset, length2); - else bufferUtil.mask(source, mask, output, offset, length2); - }, - toArrayBuffer, - toBuffer, - unmask(buffer, mask) { - if (buffer.length < 32) _unmask(buffer, mask); - else bufferUtil.unmask(buffer, mask); - } - }; - } catch (e2) { - module14.exports = { - concat: concat2, - mask: _mask, - toArrayBuffer, - toBuffer, - unmask: _unmask - }; - } - } -}); -var require_limiter = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/limiter.js"(exports2, module14) { - "use strict"; - var kDone = Symbol("kDone"); - var kRun = Symbol("kRun"); - var Limiter = class { - /** - * Creates a new `Limiter`. - * - * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed - * to run concurrently - */ - constructor(concurrency) { - this[kDone] = () => { - this.pending--; - this[kRun](); - }; - this.concurrency = concurrency || Infinity; - this.jobs = []; - this.pending = 0; - } - /** - * Adds a job to the queue. - * - * @param {Function} job The job to run - * @public - */ - add(job) { - this.jobs.push(job); - this[kRun](); - } - /** - * Removes a job from the queue and runs it if possible. - * - * @private - */ - [kRun]() { - if (this.pending === this.concurrency) return; - if (this.jobs.length) { - const job = this.jobs.shift(); - this.pending++; - job(this[kDone]); - } - } - }; - module14.exports = Limiter; - } -}); -var require_permessage_deflate = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module14) { - "use strict"; - var zlib = __require2("zlib"); - var bufferUtil = require_buffer_util(); - var Limiter = require_limiter(); - var { kStatusCode } = require_constants2(); - var TRAILER = Buffer.from([0, 0, 255, 255]); - var kPerMessageDeflate = Symbol("permessage-deflate"); - var kTotalLength = Symbol("total-length"); - var kCallback = Symbol("callback"); - var kBuffers = Symbol("buffers"); - var kError = Symbol("error"); - var zlibLimiter; - var PerMessageDeflate = class { - /** - * Creates a PerMessageDeflate instance. - * - * @param {Object} [options] Configuration options - * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support - * for, or request, a custom client window size - * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ - * acknowledge disabling of client context takeover - * @param {Number} [options.concurrencyLimit=10] The number of concurrent - * calls to zlib - * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the - * use of a custom server window size - * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept - * disabling of server context takeover - * @param {Number} [options.threshold=1024] Size (in bytes) below which - * messages should not be compressed if context takeover is disabled - * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on - * deflate - * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on - * inflate - * @param {Boolean} [isServer=false] Create the instance in either server or - * client mode - * @param {Number} [maxPayload=0] The maximum allowed message length - */ - constructor(options2, isServer, maxPayload) { - this._maxPayload = maxPayload | 0; - this._options = options2 || {}; - this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; - this._isServer = !!isServer; - this._deflate = null; - this._inflate = null; - this.params = null; - if (!zlibLimiter) { - const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; - zlibLimiter = new Limiter(concurrency); - } - } - /** - * @type {String} - */ - static get extensionName() { - return "permessage-deflate"; - } - /** - * Create an extension negotiation offer. - * - * @return {Object} Extension parameters - * @public - */ - offer() { - const params = {}; - if (this._options.serverNoContextTakeover) { - params.server_no_context_takeover = true; - } - if (this._options.clientNoContextTakeover) { - params.client_no_context_takeover = true; - } - if (this._options.serverMaxWindowBits) { - params.server_max_window_bits = this._options.serverMaxWindowBits; - } - if (this._options.clientMaxWindowBits) { - params.client_max_window_bits = this._options.clientMaxWindowBits; - } else if (this._options.clientMaxWindowBits == null) { - params.client_max_window_bits = true; - } - return params; - } - /** - * Accept an extension negotiation offer/response. - * - * @param {Array} configurations The extension negotiation offers/reponse - * @return {Object} Accepted configuration - * @public - */ - accept(configurations) { - configurations = this.normalizeParams(configurations); - this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); - return this.params; - } - /** - * Releases all resources used by the extension. - * - * @public - */ - cleanup() { - if (this._inflate) { - this._inflate.close(); - this._inflate = null; - } - if (this._deflate) { - const callback = this._deflate[kCallback]; - this._deflate.close(); - this._deflate = null; - if (callback) { - callback( - new Error( - "The deflate stream was closed while data was being processed" - ) - ); - } - } - } - /** - * Accept an extension negotiation offer. - * - * @param {Array} offers The extension negotiation offers - * @return {Object} Accepted configuration - * @private - */ - acceptAsServer(offers) { - const opts = this._options; - const accepted = offers.find((params) => { - if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { - return false; - } - return true; - }); - if (!accepted) { - throw new Error("None of the extension offers can be accepted"); - } - if (opts.serverNoContextTakeover) { - accepted.server_no_context_takeover = true; - } - if (opts.clientNoContextTakeover) { - accepted.client_no_context_takeover = true; - } - if (typeof opts.serverMaxWindowBits === "number") { - accepted.server_max_window_bits = opts.serverMaxWindowBits; - } - if (typeof opts.clientMaxWindowBits === "number") { - accepted.client_max_window_bits = opts.clientMaxWindowBits; - } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { - delete accepted.client_max_window_bits; - } - return accepted; - } - /** - * Accept the extension negotiation response. - * - * @param {Array} response The extension negotiation response - * @return {Object} Accepted configuration - * @private - */ - acceptAsClient(response) { - const params = response[0]; - if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { - throw new Error('Unexpected parameter "client_no_context_takeover"'); - } - if (!params.client_max_window_bits) { - if (typeof this._options.clientMaxWindowBits === "number") { - params.client_max_window_bits = this._options.clientMaxWindowBits; - } - } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { - throw new Error( - 'Unexpected or invalid parameter "client_max_window_bits"' - ); - } - return params; - } - /** - * Normalize parameters. - * - * @param {Array} configurations The extension negotiation offers/reponse - * @return {Array} The offers/response with normalized parameters - * @private - */ - normalizeParams(configurations) { - configurations.forEach((params) => { - Object.keys(params).forEach((key) => { - let value = params[key]; - if (value.length > 1) { - throw new Error(`Parameter "${key}" must have only a single value`); - } - value = value[0]; - if (key === "client_max_window_bits") { - if (value !== true) { - const num = +value; - if (!Number.isInteger(num) || num < 8 || num > 15) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); - } - value = num; - } else if (!this._isServer) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); - } - } else if (key === "server_max_window_bits") { - const num = +value; - if (!Number.isInteger(num) || num < 8 || num > 15) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); - } - value = num; - } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { - if (value !== true) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); - } - } else { - throw new Error(`Unknown parameter "${key}"`); - } - params[key] = value; - }); - }); - return configurations; - } - /** - * Decompress data. Concurrency limited. - * - * @param {Buffer} data Compressed data - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @public - */ - decompress(data, fin, callback) { - zlibLimiter.add((done) => { - this._decompress(data, fin, (err, result) => { - done(); - callback(err, result); - }); - }); - } - /** - * Compress data. Concurrency limited. - * - * @param {(Buffer|String)} data Data to compress - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @public - */ - compress(data, fin, callback) { - zlibLimiter.add((done) => { - this._compress(data, fin, (err, result) => { - done(); - callback(err, result); - }); - }); - } - /** - * Decompress data. - * - * @param {Buffer} data Compressed data - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @private - */ - _decompress(data, fin, callback) { - const endpoint = this._isServer ? "client" : "server"; - if (!this._inflate) { - const key = `${endpoint}_max_window_bits`; - const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; - this._inflate = zlib.createInflateRaw({ - ...this._options.zlibInflateOptions, - windowBits - }); - this._inflate[kPerMessageDeflate] = this; - this._inflate[kTotalLength] = 0; - this._inflate[kBuffers] = []; - this._inflate.on("error", inflateOnError); - this._inflate.on("data", inflateOnData); - } - this._inflate[kCallback] = callback; - this._inflate.write(data); - if (fin) this._inflate.write(TRAILER); - this._inflate.flush(() => { - const err = this._inflate[kError]; - if (err) { - this._inflate.close(); - this._inflate = null; - callback(err); - return; - } - const data2 = bufferUtil.concat( - this._inflate[kBuffers], - this._inflate[kTotalLength] - ); - if (this._inflate._readableState.endEmitted) { - this._inflate.close(); - this._inflate = null; - } else { - this._inflate[kTotalLength] = 0; - this._inflate[kBuffers] = []; - if (fin && this.params[`${endpoint}_no_context_takeover`]) { - this._inflate.reset(); - } - } - callback(null, data2); - }); - } - /** - * Compress data. - * - * @param {(Buffer|String)} data Data to compress - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @private - */ - _compress(data, fin, callback) { - const endpoint = this._isServer ? "server" : "client"; - if (!this._deflate) { - const key = `${endpoint}_max_window_bits`; - const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; - this._deflate = zlib.createDeflateRaw({ - ...this._options.zlibDeflateOptions, - windowBits - }); - this._deflate[kTotalLength] = 0; - this._deflate[kBuffers] = []; - this._deflate.on("data", deflateOnData); - } - this._deflate[kCallback] = callback; - this._deflate.write(data); - this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { - if (!this._deflate) { - return; - } - let data2 = bufferUtil.concat( - this._deflate[kBuffers], - this._deflate[kTotalLength] - ); - if (fin) data2 = data2.slice(0, data2.length - 4); - this._deflate[kCallback] = null; - this._deflate[kTotalLength] = 0; - this._deflate[kBuffers] = []; - if (fin && this.params[`${endpoint}_no_context_takeover`]) { - this._deflate.reset(); - } - callback(null, data2); - }); - } - }; - module14.exports = PerMessageDeflate; - function deflateOnData(chunk) { - this[kBuffers].push(chunk); - this[kTotalLength] += chunk.length; - } - function inflateOnData(chunk) { - this[kTotalLength] += chunk.length; - if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { - this[kBuffers].push(chunk); - return; - } - this[kError] = new RangeError("Max payload size exceeded"); - this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; - this[kError][kStatusCode] = 1009; - this.removeListener("data", inflateOnData); - this.reset(); - } - function inflateOnError(err) { - this[kPerMessageDeflate]._inflate = null; - err[kStatusCode] = 1007; - this[kCallback](err); - } - } -}); -var require_validation2 = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/validation.js"(exports2, module14) { - "use strict"; - var tokenChars = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // 0 - 15 - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // 16 - 31 - 0, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - // 32 - 47 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - // 48 - 63 - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - // 64 - 79 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - // 80 - 95 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - // 96 - 111 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 1, - 0 - // 112 - 127 - ]; - function isValidStatusCode(code2) { - return code2 >= 1e3 && code2 <= 1014 && code2 !== 1004 && code2 !== 1005 && code2 !== 1006 || code2 >= 3e3 && code2 <= 4999; - } - function _isValidUTF8(buf2) { - const len = buf2.length; - let i2 = 0; - while (i2 < len) { - if ((buf2[i2] & 128) === 0) { - i2++; - } else if ((buf2[i2] & 224) === 192) { - if (i2 + 1 === len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2] & 254) === 192) { - return false; - } - i2 += 2; - } else if ((buf2[i2] & 240) === 224) { - if (i2 + 2 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || buf2[i2] === 224 && (buf2[i2 + 1] & 224) === 128 || // Overlong - buf2[i2] === 237 && (buf2[i2 + 1] & 224) === 160) { - return false; - } - i2 += 3; - } else if ((buf2[i2] & 248) === 240) { - if (i2 + 3 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || (buf2[i2 + 3] & 192) !== 128 || buf2[i2] === 240 && (buf2[i2 + 1] & 240) === 128 || // Overlong - buf2[i2] === 244 && buf2[i2 + 1] > 143 || buf2[i2] > 244) { - return false; - } - i2 += 4; - } else { - return false; - } - } - return true; - } - try { - const isValidUTF8 = __require2("utf-8-validate"); - module14.exports = { - isValidStatusCode, - isValidUTF8(buf2) { - return buf2.length < 150 ? _isValidUTF8(buf2) : isValidUTF8(buf2); - }, - tokenChars - }; - } catch (e2) { - module14.exports = { - isValidStatusCode, - isValidUTF8: _isValidUTF8, - tokenChars - }; - } - } -}); -var require_receiver = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/receiver.js"(exports2, module14) { - "use strict"; - var { Writable } = __require2("stream"); - var PerMessageDeflate = require_permessage_deflate(); - var { - BINARY_TYPES, - EMPTY_BUFFER, - kStatusCode, - kWebSocket - } = require_constants2(); - var { concat: concat2, toArrayBuffer, unmask } = require_buffer_util(); - var { isValidStatusCode, isValidUTF8 } = require_validation2(); - var GET_INFO = 0; - var GET_PAYLOAD_LENGTH_16 = 1; - var GET_PAYLOAD_LENGTH_64 = 2; - var GET_MASK = 3; - var GET_DATA = 4; - var INFLATING = 5; - var Receiver2 = class extends Writable { - /** - * Creates a Receiver instance. - * - * @param {Object} [options] Options object - * @param {String} [options.binaryType=nodebuffer] The type for binary data - * @param {Object} [options.extensions] An object containing the negotiated - * extensions - * @param {Boolean} [options.isServer=false] Specifies whether to operate in - * client or server mode - * @param {Number} [options.maxPayload=0] The maximum allowed message length - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages - */ - constructor(options2 = {}) { - super(); - this._binaryType = options2.binaryType || BINARY_TYPES[0]; - this._extensions = options2.extensions || {}; - this._isServer = !!options2.isServer; - this._maxPayload = options2.maxPayload | 0; - this._skipUTF8Validation = !!options2.skipUTF8Validation; - this[kWebSocket] = void 0; - this._bufferedBytes = 0; - this._buffers = []; - this._compressed = false; - this._payloadLength = 0; - this._mask = void 0; - this._fragmented = 0; - this._masked = false; - this._fin = false; - this._opcode = 0; - this._totalPayloadLength = 0; - this._messageLength = 0; - this._fragments = []; - this._state = GET_INFO; - this._loop = false; - } - /** - * Implements `Writable.prototype._write()`. - * - * @param {Buffer} chunk The chunk of data to write - * @param {String} encoding The character encoding of `chunk` - * @param {Function} cb Callback - * @private - */ - _write(chunk, encoding, cb) { - if (this._opcode === 8 && this._state == GET_INFO) return cb(); - this._bufferedBytes += chunk.length; - this._buffers.push(chunk); - this.startLoop(cb); - } - /** - * Consumes `n` bytes from the buffered data. - * - * @param {Number} n The number of bytes to consume - * @return {Buffer} The consumed bytes - * @private - */ - consume(n) { - this._bufferedBytes -= n; - if (n === this._buffers[0].length) return this._buffers.shift(); - if (n < this._buffers[0].length) { - const buf2 = this._buffers[0]; - this._buffers[0] = buf2.slice(n); - return buf2.slice(0, n); - } - const dst = Buffer.allocUnsafe(n); - do { - const buf2 = this._buffers[0]; - const offset = dst.length - n; - if (n >= buf2.length) { - dst.set(this._buffers.shift(), offset); - } else { - dst.set(new Uint8Array(buf2.buffer, buf2.byteOffset, n), offset); - this._buffers[0] = buf2.slice(n); - } - n -= buf2.length; - } while (n > 0); - return dst; - } - /** - * Starts the parsing loop. - * - * @param {Function} cb Callback - * @private - */ - startLoop(cb) { - let err; - this._loop = true; - do { - switch (this._state) { - case GET_INFO: - err = this.getInfo(); - break; - case GET_PAYLOAD_LENGTH_16: - err = this.getPayloadLength16(); - break; - case GET_PAYLOAD_LENGTH_64: - err = this.getPayloadLength64(); - break; - case GET_MASK: - this.getMask(); - break; - case GET_DATA: - err = this.getData(cb); - break; - default: - this._loop = false; - return; - } - } while (this._loop); - cb(err); - } - /** - * Reads the first two bytes of a frame. - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getInfo() { - if (this._bufferedBytes < 2) { - this._loop = false; - return; - } - const buf2 = this.consume(2); - if ((buf2[0] & 48) !== 0) { - this._loop = false; - return error2( - RangeError, - "RSV2 and RSV3 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_2_3" - ); - } - const compressed = (buf2[0] & 64) === 64; - if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - this._fin = (buf2[0] & 128) === 128; - this._opcode = buf2[0] & 15; - this._payloadLength = buf2[1] & 127; - if (this._opcode === 0) { - if (compressed) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - if (!this._fragmented) { - this._loop = false; - return error2( - RangeError, - "invalid opcode 0", - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - this._opcode = this._fragmented; - } else if (this._opcode === 1 || this._opcode === 2) { - if (this._fragmented) { - this._loop = false; - return error2( - RangeError, - `invalid opcode ${this._opcode}`, - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - this._compressed = compressed; - } else if (this._opcode > 7 && this._opcode < 11) { - if (!this._fin) { - this._loop = false; - return error2( - RangeError, - "FIN must be set", - true, - 1002, - "WS_ERR_EXPECTED_FIN" - ); - } - if (compressed) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - if (this._payloadLength > 125) { - this._loop = false; - return error2( - RangeError, - `invalid payload length ${this._payloadLength}`, - true, - 1002, - "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" - ); - } - } else { - this._loop = false; - return error2( - RangeError, - `invalid opcode ${this._opcode}`, - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - if (!this._fin && !this._fragmented) this._fragmented = this._opcode; - this._masked = (buf2[1] & 128) === 128; - if (this._isServer) { - if (!this._masked) { - this._loop = false; - return error2( - RangeError, - "MASK must be set", - true, - 1002, - "WS_ERR_EXPECTED_MASK" - ); - } - } else if (this._masked) { - this._loop = false; - return error2( - RangeError, - "MASK must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_MASK" - ); - } - if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; - else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; - else return this.haveLength(); - } - /** - * Gets extended payload length (7+16). - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getPayloadLength16() { - if (this._bufferedBytes < 2) { - this._loop = false; - return; - } - this._payloadLength = this.consume(2).readUInt16BE(0); - return this.haveLength(); - } - /** - * Gets extended payload length (7+64). - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getPayloadLength64() { - if (this._bufferedBytes < 8) { - this._loop = false; - return; - } - const buf2 = this.consume(8); - const num = buf2.readUInt32BE(0); - if (num > Math.pow(2, 53 - 32) - 1) { - this._loop = false; - return error2( - RangeError, - "Unsupported WebSocket frame: payload length > 2^53 - 1", - false, - 1009, - "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" - ); - } - this._payloadLength = num * Math.pow(2, 32) + buf2.readUInt32BE(4); - return this.haveLength(); - } - /** - * Payload length has been read. - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - haveLength() { - if (this._payloadLength && this._opcode < 8) { - this._totalPayloadLength += this._payloadLength; - if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { - this._loop = false; - return error2( - RangeError, - "Max payload size exceeded", - false, - 1009, - "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" - ); - } - } - if (this._masked) this._state = GET_MASK; - else this._state = GET_DATA; - } - /** - * Reads mask bytes. - * - * @private - */ - getMask() { - if (this._bufferedBytes < 4) { - this._loop = false; - return; - } - this._mask = this.consume(4); - this._state = GET_DATA; - } - /** - * Reads data bytes. - * - * @param {Function} cb Callback - * @return {(Error|RangeError|undefined)} A possible error - * @private - */ - getData(cb) { - let data = EMPTY_BUFFER; - if (this._payloadLength) { - if (this._bufferedBytes < this._payloadLength) { - this._loop = false; - return; - } - data = this.consume(this._payloadLength); - if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { - unmask(data, this._mask); - } - } - if (this._opcode > 7) return this.controlMessage(data); - if (this._compressed) { - this._state = INFLATING; - this.decompress(data, cb); - return; - } - if (data.length) { - this._messageLength = this._totalPayloadLength; - this._fragments.push(data); - } - return this.dataMessage(); - } - /** - * Decompresses data. - * - * @param {Buffer} data Compressed data - * @param {Function} cb Callback - * @private - */ - decompress(data, cb) { - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - perMessageDeflate.decompress(data, this._fin, (err, buf2) => { - if (err) return cb(err); - if (buf2.length) { - this._messageLength += buf2.length; - if (this._messageLength > this._maxPayload && this._maxPayload > 0) { - return cb( - error2( - RangeError, - "Max payload size exceeded", - false, - 1009, - "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" - ) - ); - } - this._fragments.push(buf2); - } - const er = this.dataMessage(); - if (er) return cb(er); - this.startLoop(cb); - }); - } - /** - * Handles a data message. - * - * @return {(Error|undefined)} A possible error - * @private - */ - dataMessage() { - if (this._fin) { - const messageLength = this._messageLength; - const fragments = this._fragments; - this._totalPayloadLength = 0; - this._messageLength = 0; - this._fragmented = 0; - this._fragments = []; - if (this._opcode === 2) { - let data; - if (this._binaryType === "nodebuffer") { - data = concat2(fragments, messageLength); - } else if (this._binaryType === "arraybuffer") { - data = toArrayBuffer(concat2(fragments, messageLength)); - } else { - data = fragments; - } - this.emit("message", data, true); - } else { - const buf2 = concat2(fragments, messageLength); - if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { - this._loop = false; - return error2( - Error, - "invalid UTF-8 sequence", - true, - 1007, - "WS_ERR_INVALID_UTF8" - ); - } - this.emit("message", buf2, false); - } - } - this._state = GET_INFO; - } - /** - * Handles a control message. - * - * @param {Buffer} data Data to handle - * @return {(Error|RangeError|undefined)} A possible error - * @private - */ - controlMessage(data) { - if (this._opcode === 8) { - this._loop = false; - if (data.length === 0) { - this.emit("conclude", 1005, EMPTY_BUFFER); - this.end(); - } else if (data.length === 1) { - return error2( - RangeError, - "invalid payload length 1", - true, - 1002, - "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" - ); - } else { - const code2 = data.readUInt16BE(0); - if (!isValidStatusCode(code2)) { - return error2( - RangeError, - `invalid status code ${code2}`, - true, - 1002, - "WS_ERR_INVALID_CLOSE_CODE" - ); - } - const buf2 = data.slice(2); - if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { - return error2( - Error, - "invalid UTF-8 sequence", - true, - 1007, - "WS_ERR_INVALID_UTF8" - ); - } - this.emit("conclude", code2, buf2); - this.end(); - } - } else if (this._opcode === 9) { - this.emit("ping", data); - } else { - this.emit("pong", data); - } - this._state = GET_INFO; - } - }; - module14.exports = Receiver2; - function error2(ErrorCtor, message, prefix, statusCode, errorCode) { - const err = new ErrorCtor( - prefix ? `Invalid WebSocket frame: ${message}` : message - ); - Error.captureStackTrace(err, error2); - err.code = errorCode; - err[kStatusCode] = statusCode; - return err; - } - } -}); -var require_sender = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/sender.js"(exports2, module14) { - "use strict"; - var net = __require2("net"); - var tls = __require2("tls"); - var { randomFillSync } = __require2("crypto"); - var PerMessageDeflate = require_permessage_deflate(); - var { EMPTY_BUFFER } = require_constants2(); - var { isValidStatusCode } = require_validation2(); - var { mask: applyMask, toBuffer } = require_buffer_util(); - var kByteLength = Symbol("kByteLength"); - var maskBuffer = Buffer.alloc(4); - var Sender2 = class _Sender { - /** - * Creates a Sender instance. - * - * @param {(net.Socket|tls.Socket)} socket The connection socket - * @param {Object} [extensions] An object containing the negotiated extensions - * @param {Function} [generateMask] The function used to generate the masking - * key - */ - constructor(socket, extensions, generateMask) { - this._extensions = extensions || {}; - if (generateMask) { - this._generateMask = generateMask; - this._maskBuffer = Buffer.alloc(4); - } - this._socket = socket; - this._firstFragment = true; - this._compress = false; - this._bufferedBytes = 0; - this._deflating = false; - this._queue = []; - } - /** - * Frames a piece of data according to the HyBi WebSocket protocol. - * - * @param {(Buffer|String)} data The data to frame - * @param {Object} options Options object - * @param {Boolean} [options.fin=false] Specifies whether or not to set the - * FIN bit - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Buffer} [options.maskBuffer] The buffer used to store the masking - * key - * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified - * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the - * RSV1 bit - * @return {(Buffer|String)[]} The framed data - * @public - */ - static frame(data, options2) { - let mask; - let merge3 = false; - let offset = 2; - let skipMasking = false; - if (options2.mask) { - mask = options2.maskBuffer || maskBuffer; - if (options2.generateMask) { - options2.generateMask(mask); - } else { - randomFillSync(mask, 0, 4); - } - skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; - offset = 6; - } - let dataLength; - if (typeof data === "string") { - if ((!options2.mask || skipMasking) && options2[kByteLength] !== void 0) { - dataLength = options2[kByteLength]; - } else { - data = Buffer.from(data); - dataLength = data.length; - } - } else { - dataLength = data.length; - merge3 = options2.mask && options2.readOnly && !skipMasking; - } - let payloadLength = dataLength; - if (dataLength >= 65536) { - offset += 8; - payloadLength = 127; - } else if (dataLength > 125) { - offset += 2; - payloadLength = 126; - } - const target = Buffer.allocUnsafe(merge3 ? dataLength + offset : offset); - target[0] = options2.fin ? options2.opcode | 128 : options2.opcode; - if (options2.rsv1) target[0] |= 64; - target[1] = payloadLength; - if (payloadLength === 126) { - target.writeUInt16BE(dataLength, 2); - } else if (payloadLength === 127) { - target[2] = target[3] = 0; - target.writeUIntBE(dataLength, 4, 6); - } - if (!options2.mask) return [target, data]; - target[1] |= 128; - target[offset - 4] = mask[0]; - target[offset - 3] = mask[1]; - target[offset - 2] = mask[2]; - target[offset - 1] = mask[3]; - if (skipMasking) return [target, data]; - if (merge3) { - applyMask(data, mask, target, offset, dataLength); - return [target]; - } - applyMask(data, mask, data, 0, dataLength); - return [target, data]; - } - /** - * Sends a close message to the other peer. - * - * @param {Number} [code] The status code component of the body - * @param {(String|Buffer)} [data] The message component of the body - * @param {Boolean} [mask=false] Specifies whether or not to mask the message - * @param {Function} [cb] Callback - * @public - */ - close(code2, data, mask, cb) { - let buf2; - if (code2 === void 0) { - buf2 = EMPTY_BUFFER; - } else if (typeof code2 !== "number" || !isValidStatusCode(code2)) { - throw new TypeError("First argument must be a valid error code number"); - } else if (data === void 0 || !data.length) { - buf2 = Buffer.allocUnsafe(2); - buf2.writeUInt16BE(code2, 0); - } else { - const length2 = Buffer.byteLength(data); - if (length2 > 123) { - throw new RangeError("The message must not be greater than 123 bytes"); - } - buf2 = Buffer.allocUnsafe(2 + length2); - buf2.writeUInt16BE(code2, 0); - if (typeof data === "string") { - buf2.write(data, 2); - } else { - buf2.set(data, 2); - } - } - const options2 = { - [kByteLength]: buf2.length, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 8, - readOnly: false, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, buf2, false, options2, cb]); - } else { - this.sendFrame(_Sender.frame(buf2, options2), cb); - } - } - /** - * Sends a ping message to the other peer. - * - * @param {*} data The message to send - * @param {Boolean} [mask=false] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback - * @public - */ - ping(data, mask, cb) { - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; - } - if (byteLength > 125) { - throw new RangeError("The data size must not be greater than 125 bytes"); - } - const options2 = { - [kByteLength]: byteLength, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 9, - readOnly, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, false, options2, cb]); - } else { - this.sendFrame(_Sender.frame(data, options2), cb); - } - } - /** - * Sends a pong message to the other peer. - * - * @param {*} data The message to send - * @param {Boolean} [mask=false] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback - * @public - */ - pong(data, mask, cb) { - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; - } - if (byteLength > 125) { - throw new RangeError("The data size must not be greater than 125 bytes"); - } - const options2 = { - [kByteLength]: byteLength, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 10, - readOnly, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, false, options2, cb]); - } else { - this.sendFrame(_Sender.frame(data, options2), cb); - } - } - /** - * Sends a data message to the other peer. - * - * @param {*} data The message to send - * @param {Object} options Options object - * @param {Boolean} [options.binary=false] Specifies whether `data` is binary - * or text - * @param {Boolean} [options.compress=false] Specifies whether or not to - * compress `data` - * @param {Boolean} [options.fin=false] Specifies whether the fragment is the - * last one - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Function} [cb] Callback - * @public - */ - send(data, options2, cb) { - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - let opcode = options2.binary ? 2 : 1; - let rsv1 = options2.compress; - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; - } - if (this._firstFragment) { - this._firstFragment = false; - if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { - rsv1 = byteLength >= perMessageDeflate._threshold; - } - this._compress = rsv1; - } else { - rsv1 = false; - opcode = 0; - } - if (options2.fin) this._firstFragment = true; - if (perMessageDeflate) { - const opts = { - [kByteLength]: byteLength, - fin: options2.fin, - generateMask: this._generateMask, - mask: options2.mask, - maskBuffer: this._maskBuffer, - opcode, - readOnly, - rsv1 - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, this._compress, opts, cb]); - } else { - this.dispatch(data, this._compress, opts, cb); - } - } else { - this.sendFrame( - _Sender.frame(data, { - [kByteLength]: byteLength, - fin: options2.fin, - generateMask: this._generateMask, - mask: options2.mask, - maskBuffer: this._maskBuffer, - opcode, - readOnly, - rsv1: false - }), - cb - ); - } - } - /** - * Dispatches a message. - * - * @param {(Buffer|String)} data The message to send - * @param {Boolean} [compress=false] Specifies whether or not to compress - * `data` - * @param {Object} options Options object - * @param {Boolean} [options.fin=false] Specifies whether or not to set the - * FIN bit - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Buffer} [options.maskBuffer] The buffer used to store the masking - * key - * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified - * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the - * RSV1 bit - * @param {Function} [cb] Callback - * @private - */ - dispatch(data, compress, options2, cb) { - if (!compress) { - this.sendFrame(_Sender.frame(data, options2), cb); - return; - } - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - this._bufferedBytes += options2[kByteLength]; - this._deflating = true; - perMessageDeflate.compress(data, options2.fin, (_, buf2) => { - if (this._socket.destroyed) { - const err = new Error( - "The socket was closed while data was being compressed" - ); - if (typeof cb === "function") cb(err); - for (let i2 = 0; i2 < this._queue.length; i2++) { - const params = this._queue[i2]; - const callback = params[params.length - 1]; - if (typeof callback === "function") callback(err); - } - return; - } - this._bufferedBytes -= options2[kByteLength]; - this._deflating = false; - options2.readOnly = false; - this.sendFrame(_Sender.frame(buf2, options2), cb); - this.dequeue(); - }); - } - /** - * Executes queued send operations. - * - * @private - */ - dequeue() { - while (!this._deflating && this._queue.length) { - const params = this._queue.shift(); - this._bufferedBytes -= params[3][kByteLength]; - Reflect.apply(params[0], this, params.slice(1)); - } - } - /** - * Enqueues a send operation. - * - * @param {Array} params Send operation parameters. - * @private - */ - enqueue(params) { - this._bufferedBytes += params[3][kByteLength]; - this._queue.push(params); - } - /** - * Sends a frame. - * - * @param {Buffer[]} list The frame to send - * @param {Function} [cb] Callback - * @private - */ - sendFrame(list, cb) { - if (list.length === 2) { - this._socket.cork(); - this._socket.write(list[0]); - this._socket.write(list[1], cb); - this._socket.uncork(); - } else { - this._socket.write(list[0], cb); - } - } - }; - module14.exports = Sender2; - } -}); -var require_event_target = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/event-target.js"(exports2, module14) { - "use strict"; - var { kForOnEventAttribute, kListener } = require_constants2(); - var kCode = Symbol("kCode"); - var kData = Symbol("kData"); - var kError = Symbol("kError"); - var kMessage = Symbol("kMessage"); - var kReason = Symbol("kReason"); - var kTarget = Symbol("kTarget"); - var kType = Symbol("kType"); - var kWasClean = Symbol("kWasClean"); - var Event = class { - /** - * Create a new `Event`. - * - * @param {String} type The name of the event - * @throws {TypeError} If the `type` argument is not specified - */ - constructor(type) { - this[kTarget] = null; - this[kType] = type; - } - /** - * @type {*} - */ - get target() { - return this[kTarget]; - } - /** - * @type {String} - */ - get type() { - return this[kType]; - } - }; - Object.defineProperty(Event.prototype, "target", { enumerable: true }); - Object.defineProperty(Event.prototype, "type", { enumerable: true }); - var CloseEvent = class extends Event { - /** - * Create a new `CloseEvent`. - * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {Number} [options.code=0] The status code explaining why the - * connection was closed - * @param {String} [options.reason=''] A human-readable string explaining why - * the connection was closed - * @param {Boolean} [options.wasClean=false] Indicates whether or not the - * connection was cleanly closed - */ - constructor(type, options2 = {}) { - super(type); - this[kCode] = options2.code === void 0 ? 0 : options2.code; - this[kReason] = options2.reason === void 0 ? "" : options2.reason; - this[kWasClean] = options2.wasClean === void 0 ? false : options2.wasClean; - } - /** - * @type {Number} - */ - get code() { - return this[kCode]; - } - /** - * @type {String} - */ - get reason() { - return this[kReason]; - } - /** - * @type {Boolean} - */ - get wasClean() { - return this[kWasClean]; - } - }; - Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); - Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); - Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); - var ErrorEvent = class extends Event { - /** - * Create a new `ErrorEvent`. - * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {*} [options.error=null] The error that generated this event - * @param {String} [options.message=''] The error message - */ - constructor(type, options2 = {}) { - super(type); - this[kError] = options2.error === void 0 ? null : options2.error; - this[kMessage] = options2.message === void 0 ? "" : options2.message; - } - /** - * @type {*} - */ - get error() { - return this[kError]; - } - /** - * @type {String} - */ - get message() { - return this[kMessage]; - } - }; - Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); - Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); - var MessageEvent = class extends Event { - /** - * Create a new `MessageEvent`. - * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {*} [options.data=null] The message content - */ - constructor(type, options2 = {}) { - super(type); - this[kData] = options2.data === void 0 ? null : options2.data; - } - /** - * @type {*} - */ - get data() { - return this[kData]; - } - }; - Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true }); - var EventTarget2 = { - /** - * Register an event listener. - * - * @param {String} type A string representing the event type to listen for - * @param {Function} listener The listener to add - * @param {Object} [options] An options object specifies characteristics about - * the event listener - * @param {Boolean} [options.once=false] A `Boolean` indicating that the - * listener should be invoked at most once after being added. If `true`, - * the listener would be automatically removed when invoked. - * @public - */ - addEventListener(type, listener, options2 = {}) { - let wrapper3; - if (type === "message") { - wrapper3 = function onMessage(data, isBinary) { - const event = new MessageEvent("message", { - data: isBinary ? data : data.toString() - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "close") { - wrapper3 = function onClose(code2, message) { - const event = new CloseEvent("close", { - code: code2, - reason: message.toString(), - wasClean: this._closeFrameReceived && this._closeFrameSent - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "error") { - wrapper3 = function onError(error2) { - const event = new ErrorEvent("error", { - error: error2, - message: error2.message - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "open") { - wrapper3 = function onOpen() { - const event = new Event("open"); - event[kTarget] = this; - listener.call(this, event); - }; - } else { - return; - } - wrapper3[kForOnEventAttribute] = !!options2[kForOnEventAttribute]; - wrapper3[kListener] = listener; - if (options2.once) { - this.once(type, wrapper3); - } else { - this.on(type, wrapper3); - } + scripts: { + test: 'standard && npm run transpile && tap "test/**/*.test.*js" && tap --ts test/*.test.*ts', + "test:ci": "standard && npm run transpile && npm run test:ci:js && npm run test:ci:ts", + "test:ci:js": 'tap --no-check-coverage --timeout=120 --coverage-report=lcovonly "test/**/*.test.*js"', + "test:ci:ts": 'tap --ts --no-check-coverage --coverage-report=lcovonly "test/**/*.test.*ts"', + "test:yarn": 'npm run transpile && tap "test/**/*.test.js" --no-check-coverage', + transpile: "sh ./test/ts/transpile.sh", + prepare: "husky install" }, - /** - * Remove an event listener. - * - * @param {String} type A string representing the event type to remove - * @param {Function} handler The listener to remove - * @public - */ - removeEventListener(type, handler) { - for (const listener of this.listeners(type)) { - if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { - this.removeListener(type, listener); - break; - } - } - } - }; - module14.exports = { - CloseEvent, - ErrorEvent, - Event, - EventTarget: EventTarget2, - MessageEvent + standard: { + ignore: [ + "test/ts/**/*" + ] + }, + repository: { + type: "git", + url: "git+https://github.com/mcollina/thread-stream.git" + }, + keywords: [ + "worker", + "thread", + "threads", + "stream" + ], + author: "Matteo Collina ", + license: "MIT", + bugs: { + url: "https://github.com/mcollina/thread-stream/issues" + }, + homepage: "https://github.com/mcollina/thread-stream#readme" }; } }); -var require_extension = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/extension.js"(exports2, module14) { - "use strict"; - var { tokenChars } = require_validation2(); - function push(dest, name, elem) { - if (dest[name] === void 0) dest[name] = [elem]; - else dest[name].push(elem); - } - function parse52(header) { - const offers = /* @__PURE__ */ Object.create(null); - let params = /* @__PURE__ */ Object.create(null); - let mustUnescape = false; - let isEscaping = false; - let inQuotes = false; - let extensionName; - let paramName; - let start = -1; - let code2 = -1; - let end = -1; - let i2 = 0; - for (; i2 < header.length; i2++) { - code2 = header.charCodeAt(i2); - if (extensionName === void 0) { - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - const name = header.slice(start, end); - if (code2 === 44) { - push(offers, name, params); - params = /* @__PURE__ */ Object.create(null); - } else { - extensionName = name; - } - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } else if (paramName === void 0) { - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (code2 === 32 || code2 === 9) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - push(params, header.slice(start, end), true); - if (code2 === 44) { - push(offers, extensionName, params); - params = /* @__PURE__ */ Object.create(null); - extensionName = void 0; - } - start = end = -1; - } else if (code2 === 61 && start !== -1 && end === -1) { - paramName = header.slice(start, i2); - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } else { - if (isEscaping) { - if (tokenChars[code2] !== 1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (start === -1) start = i2; - else if (!mustUnescape) mustUnescape = true; - isEscaping = false; - } else if (inQuotes) { - if (tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (code2 === 34 && start !== -1) { - inQuotes = false; - end = i2; - } else if (code2 === 92) { - isEscaping = true; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } else if (code2 === 34 && header.charCodeAt(i2 - 1) === 61) { - inQuotes = true; - } else if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (start !== -1 && (code2 === 32 || code2 === 9)) { - if (end === -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - let value = header.slice(start, end); - if (mustUnescape) { - value = value.replace(/\\/g, ""); - mustUnescape = false; - } - push(params, paramName, value); - if (code2 === 44) { - push(offers, extensionName, params); - params = /* @__PURE__ */ Object.create(null); - extensionName = void 0; - } - paramName = void 0; - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } - } - if (start === -1 || inQuotes || code2 === 32 || code2 === 9) { - throw new SyntaxError("Unexpected end of input"); - } - if (end === -1) end = i2; - const token = header.slice(start, end); - if (extensionName === void 0) { - push(offers, token, params); - } else { - if (paramName === void 0) { - push(params, token, true); - } else if (mustUnescape) { - push(params, paramName, token.replace(/\\/g, "")); - } else { - push(params, paramName, token); - } - push(offers, extensionName, params); - } - return offers; - } - function format52(extensions) { - return Object.keys(extensions).map((extension) => { - let configurations = extensions[extension]; - if (!Array.isArray(configurations)) configurations = [configurations]; - return configurations.map((params) => { - return [extension].concat( - Object.keys(params).map((k) => { - let values = params[k]; - if (!Array.isArray(values)) values = [values]; - return values.map((v2) => v2 === true ? k : `${k}=${v2}`).join("; "); - }) - ).join("; "); - }).join(", "); - }).join(", "); - } - module14.exports = { format: format52, parse: parse52 }; - } -}); -var require_websocket = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket.js"(exports2, module14) { - "use strict"; - var EventEmitter = __require2("events"); - var https = __require2("https"); - var http = __require2("http"); - var net = __require2("net"); - var tls = __require2("tls"); - var { randomBytes: randomBytes3, createHash } = __require2("crypto"); - var { Readable: Readable2 } = __require2("stream"); - var { URL: URL2 } = __require2("url"); - var PerMessageDeflate = require_permessage_deflate(); - var Receiver2 = require_receiver(); - var Sender2 = require_sender(); - var { - BINARY_TYPES, - EMPTY_BUFFER, - GUID, - kForOnEventAttribute, - kListener, - kStatusCode, - kWebSocket, - NOOP - } = require_constants2(); - var { - EventTarget: { addEventListener, removeEventListener } - } = require_event_target(); - var { format: format52, parse: parse52 } = require_extension(); - var { toBuffer } = require_buffer_util(); - var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; - var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; - var protocolVersions = [8, 13]; - var closeTimeout = 30 * 1e3; - var WebSocket3 = class _WebSocket extends EventEmitter { - /** - * Create a new `WebSocket`. - * - * @param {(String|URL)} address The URL to which to connect - * @param {(String|String[])} [protocols] The subprotocols - * @param {Object} [options] Connection options - */ - constructor(address, protocols, options2) { - super(); - this._binaryType = BINARY_TYPES[0]; - this._closeCode = 1006; - this._closeFrameReceived = false; - this._closeFrameSent = false; - this._closeMessage = EMPTY_BUFFER; - this._closeTimer = null; - this._extensions = {}; - this._paused = false; - this._protocol = ""; - this._readyState = _WebSocket.CONNECTING; - this._receiver = null; - this._sender = null; - this._socket = null; - if (address !== null) { - this._bufferedAmount = 0; - this._isServer = false; - this._redirects = 0; - if (protocols === void 0) { - protocols = []; - } else if (!Array.isArray(protocols)) { - if (typeof protocols === "object" && protocols !== null) { - options2 = protocols; - protocols = []; - } else { - protocols = [protocols]; - } - } - initAsClient(this, address, protocols, options2); - } else { - this._isServer = true; - } - } - /** - * This deviates from the WHATWG interface since ws doesn't support the - * required default "blob" type (instead we define a custom "nodebuffer" - * type). - * - * @type {String} - */ - get binaryType() { - return this._binaryType; - } - set binaryType(type) { - if (!BINARY_TYPES.includes(type)) return; - this._binaryType = type; - if (this._receiver) this._receiver._binaryType = type; - } - /** - * @type {Number} - */ - get bufferedAmount() { - if (!this._socket) return this._bufferedAmount; - return this._socket._writableState.length + this._sender._bufferedBytes; - } - /** - * @type {String} - */ - get extensions() { - return Object.keys(this._extensions).join(); - } - /** - * @type {Boolean} - */ - get isPaused() { - return this._paused; - } - /** - * @type {Function} - */ - /* istanbul ignore next */ - get onclose() { - return null; - } - /** - * @type {Function} - */ - /* istanbul ignore next */ - get onerror() { - return null; - } - /** - * @type {Function} - */ - /* istanbul ignore next */ - get onopen() { - return null; - } - /** - * @type {Function} - */ - /* istanbul ignore next */ - get onmessage() { - return null; - } - /** - * @type {String} - */ - get protocol() { - return this._protocol; - } - /** - * @type {Number} - */ - get readyState() { - return this._readyState; - } - /** - * @type {String} - */ - get url() { - return this._url; - } - /** - * Set up the socket and the internal resources. - * - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Object} options Options object - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Number} [options.maxPayload=0] The maximum allowed message size - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages - * @private - */ - setSocket(socket, head, options2) { - const receiver = new Receiver2({ - binaryType: this.binaryType, - extensions: this._extensions, - isServer: this._isServer, - maxPayload: options2.maxPayload, - skipUTF8Validation: options2.skipUTF8Validation - }); - this._sender = new Sender2(socket, this._extensions, options2.generateMask); - this._receiver = receiver; - this._socket = socket; - receiver[kWebSocket] = this; - socket[kWebSocket] = this; - receiver.on("conclude", receiverOnConclude); - receiver.on("drain", receiverOnDrain); - receiver.on("error", receiverOnError); - receiver.on("message", receiverOnMessage); - receiver.on("ping", receiverOnPing); - receiver.on("pong", receiverOnPong); - socket.setTimeout(0); - socket.setNoDelay(); - if (head.length > 0) socket.unshift(head); - socket.on("close", socketOnClose); - socket.on("data", socketOnData); - socket.on("end", socketOnEnd); - socket.on("error", socketOnError); - this._readyState = _WebSocket.OPEN; - this.emit("open"); - } - /** - * Emit the `'close'` event. - * - * @private - */ - emitClose() { - if (!this._socket) { - this._readyState = _WebSocket.CLOSED; - this.emit("close", this._closeCode, this._closeMessage); - return; - } - if (this._extensions[PerMessageDeflate.extensionName]) { - this._extensions[PerMessageDeflate.extensionName].cleanup(); - } - this._receiver.removeAllListeners(); - this._readyState = _WebSocket.CLOSED; - this.emit("close", this._closeCode, this._closeMessage); - } - /** - * Start a closing handshake. - * - * +----------+ +-----------+ +----------+ - * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - - * | +----------+ +-----------+ +----------+ | - * +----------+ +-----------+ | - * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING - * +----------+ +-----------+ | - * | | | +---+ | - * +------------------------+-->|fin| - - - - - * | +---+ | +---+ - * - - - - -|fin|<---------------------+ - * +---+ - * - * @param {Number} [code] Status code explaining why the connection is closing - * @param {(String|Buffer)} [data] The reason why the connection is - * closing - * @public - */ - close(code2, data) { - if (this.readyState === _WebSocket.CLOSED) return; - if (this.readyState === _WebSocket.CONNECTING) { - const msg = "WebSocket was closed before the connection was established"; - return abortHandshake(this, this._req, msg); - } - if (this.readyState === _WebSocket.CLOSING) { - if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { - this._socket.end(); - } - return; - } - this._readyState = _WebSocket.CLOSING; - this._sender.close(code2, data, !this._isServer, (err) => { - if (err) return; - this._closeFrameSent = true; - if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { - this._socket.end(); - } - }); - this._closeTimer = setTimeout( - this._socket.destroy.bind(this._socket), - closeTimeout - ); - } - /** - * Pause the socket. - * - * @public - */ - pause() { - if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { - return; - } - this._paused = true; - this._socket.pause(); +var require_wait = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/wait.js"(exports2, module14) { + "use strict"; + var MAX_TIMEOUT = 1e3; + function wait(state, index, expected, timeout, done) { + const max = Date.now() + timeout; + let current = Atomics.load(state, index); + if (current === expected) { + done(null, "ok"); + return; } - /** - * Send a ping. - * - * @param {*} [data] The data to send - * @param {Boolean} [mask] Indicates whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when the ping is sent - * @public - */ - ping(data, mask, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); - } - if (typeof data === "function") { - cb = data; - data = mask = void 0; - } else if (typeof mask === "function") { - cb = mask; - mask = void 0; - } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; + let prior = current; + const check2 = (backoff) => { + if (Date.now() > max) { + done(null, "timed-out"); + } else { + setTimeout(() => { + prior = current; + current = Atomics.load(state, index); + if (current === prior) { + check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); + } else { + if (current === expected) done(null, "ok"); + else done(null, "not-equal"); + } + }, backoff); } - if (mask === void 0) mask = !this._isServer; - this._sender.ping(data || EMPTY_BUFFER, mask, cb); + }; + check2(1); + } + function waitDiff(state, index, expected, timeout, done) { + const max = Date.now() + timeout; + let current = Atomics.load(state, index); + if (current !== expected) { + done(null, "ok"); + return; } - /** - * Send a pong. - * - * @param {*} [data] The data to send - * @param {Boolean} [mask] Indicates whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when the pong is sent - * @public - */ - pong(data, mask, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); - } - if (typeof data === "function") { - cb = data; - data = mask = void 0; - } else if (typeof mask === "function") { - cb = mask; - mask = void 0; - } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; + const check2 = (backoff) => { + if (Date.now() > max) { + done(null, "timed-out"); + } else { + setTimeout(() => { + current = Atomics.load(state, index); + if (current !== expected) { + done(null, "ok"); + } else { + check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); + } + }, backoff); } - if (mask === void 0) mask = !this._isServer; - this._sender.pong(data || EMPTY_BUFFER, mask, cb); + }; + check2(1); + } + module14.exports = { wait, waitDiff }; + } +}); +var require_indexes = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/indexes.js"(exports2, module14) { + "use strict"; + var WRITE_INDEX = 4; + var READ_INDEX = 8; + module14.exports = { + WRITE_INDEX, + READ_INDEX + }; + } +}); +var require_thread_stream = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports2, module14) { + "use strict"; + var { version: version3 } = require_package3(); + var { EventEmitter } = __require2("events"); + var { Worker: Worker2 } = __require2("worker_threads"); + var { join: join10 } = __require2("path"); + var { pathToFileURL: pathToFileURL2 } = __require2("url"); + var { wait } = require_wait(); + var { + WRITE_INDEX, + READ_INDEX + } = require_indexes(); + var buffer = __require2("buffer"); + var assert2 = __require2("assert"); + var kImpl = Symbol("kImpl"); + var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; + var FakeWeakRef = class { + constructor(value) { + this._value = value; } - /** - * Resume the socket. - * - * @public - */ - resume() { - if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { - return; - } - this._paused = false; - if (!this._receiver._writableState.needDrain) this._socket.resume(); + deref() { + return this._value; } - /** - * Send a data message. - * - * @param {*} data The message to send - * @param {Object} [options] Options object - * @param {Boolean} [options.binary] Specifies whether `data` is binary or - * text - * @param {Boolean} [options.compress] Specifies whether or not to compress - * `data` - * @param {Boolean} [options.fin=true] Specifies whether the fragment is the - * last one - * @param {Boolean} [options.mask] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when data is written out - * @public - */ - send(data, options2, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); - } - if (typeof options2 === "function") { - cb = options2; - options2 = {}; - } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; - } - const opts = { - binary: typeof data !== "string", - mask: !this._isServer, - compress: true, - fin: true, - ...options2 - }; - if (!this._extensions[PerMessageDeflate.extensionName]) { - opts.compress = false; - } - this._sender.send(data || EMPTY_BUFFER, opts, cb); + }; + var FakeFinalizationRegistry = class { + register() { } - /** - * Forcibly close the connection. - * - * @public - */ - terminate() { - if (this.readyState === _WebSocket.CLOSED) return; - if (this.readyState === _WebSocket.CONNECTING) { - const msg = "WebSocket was closed before the connection was established"; - return abortHandshake(this, this._req, msg); - } - if (this._socket) { - this._readyState = _WebSocket.CLOSING; - this._socket.destroy(); - } + unregister() { } }; - Object.defineProperty(WebSocket3, "CONNECTING", { - enumerable: true, - value: readyStates.indexOf("CONNECTING") - }); - Object.defineProperty(WebSocket3.prototype, "CONNECTING", { - enumerable: true, - value: readyStates.indexOf("CONNECTING") - }); - Object.defineProperty(WebSocket3, "OPEN", { - enumerable: true, - value: readyStates.indexOf("OPEN") - }); - Object.defineProperty(WebSocket3.prototype, "OPEN", { - enumerable: true, - value: readyStates.indexOf("OPEN") - }); - Object.defineProperty(WebSocket3, "CLOSING", { - enumerable: true, - value: readyStates.indexOf("CLOSING") - }); - Object.defineProperty(WebSocket3.prototype, "CLOSING", { - enumerable: true, - value: readyStates.indexOf("CLOSING") - }); - Object.defineProperty(WebSocket3, "CLOSED", { - enumerable: true, - value: readyStates.indexOf("CLOSED") - }); - Object.defineProperty(WebSocket3.prototype, "CLOSED", { - enumerable: true, - value: readyStates.indexOf("CLOSED") - }); - [ - "binaryType", - "bufferedAmount", - "extensions", - "isPaused", - "protocol", - "readyState", - "url" - ].forEach((property) => { - Object.defineProperty(WebSocket3.prototype, property, { enumerable: true }); + var FinalizationRegistry2 = process.env.NODE_V8_COVERAGE ? FakeFinalizationRegistry : global.FinalizationRegistry || FakeFinalizationRegistry; + var WeakRef2 = process.env.NODE_V8_COVERAGE ? FakeWeakRef : global.WeakRef || FakeWeakRef; + var registry2 = new FinalizationRegistry2((worker) => { + if (worker.exited) { + return; + } + worker.terminate(); }); - ["open", "error", "close", "message"].forEach((method) => { - Object.defineProperty(WebSocket3.prototype, `on${method}`, { - enumerable: true, - get() { - for (const listener of this.listeners(method)) { - if (listener[kForOnEventAttribute]) return listener[kListener]; - } - return null; - }, - set(handler) { - for (const listener of this.listeners(method)) { - if (listener[kForOnEventAttribute]) { - this.removeListener(method, listener); - break; - } + function createWorker2(stream, opts) { + const { filename, workerData } = opts; + const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; + const toExecute = bundlerOverrides["thread-stream-worker"] || join10(__dirname, "lib", "worker.js"); + const worker = new Worker2(toExecute, { + ...opts.workerOpts, + trackUnmanagedFds: false, + workerData: { + filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, + dataBuf: stream[kImpl].dataBuf, + stateBuf: stream[kImpl].stateBuf, + workerData: { + $context: { + threadStreamVersion: version3 + }, + ...workerData } - if (typeof handler !== "function") return; - this.addEventListener(method, handler, { - [kForOnEventAttribute]: true - }); } }); - }); - WebSocket3.prototype.addEventListener = addEventListener; - WebSocket3.prototype.removeEventListener = removeEventListener; - module14.exports = WebSocket3; - function initAsClient(websocket, address, protocols, options2) { - const opts = { - protocolVersion: protocolVersions[1], - maxPayload: 100 * 1024 * 1024, - skipUTF8Validation: false, - perMessageDeflate: true, - followRedirects: false, - maxRedirects: 10, - ...options2, - createConnection: void 0, - socketPath: void 0, - hostname: void 0, - protocol: void 0, - timeout: void 0, - method: void 0, - host: void 0, - path: void 0, - port: void 0 - }; - if (!protocolVersions.includes(opts.protocolVersion)) { - throw new RangeError( - `Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` - ); + worker.stream = new FakeWeakRef(stream); + worker.on("message", onWorkerMessage); + worker.on("exit", onWorkerExit); + registry2.register(stream, worker); + return worker; + } + function drain(stream) { + assert2(!stream[kImpl].sync); + if (stream[kImpl].needDrain) { + stream[kImpl].needDrain = false; + stream.emit("drain"); } - let parsedUrl; - if (address instanceof URL2) { - parsedUrl = address; - websocket._url = address.href; - } else { - try { - parsedUrl = new URL2(address); - } catch (e2) { - throw new SyntaxError(`Invalid URL: ${address}`); + } + function nextFlush(stream) { + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let leftover = stream[kImpl].data.length - writeIndex; + if (leftover > 0) { + if (stream[kImpl].buf.length === 0) { + stream[kImpl].flushing = false; + if (stream[kImpl].ending) { + end(stream); + } else if (stream[kImpl].needDrain) { + process.nextTick(drain, stream); + } + return; } - websocket._url = address; - } - const isSecure = parsedUrl.protocol === "wss:"; - const isUnixSocket = parsedUrl.protocol === "ws+unix:"; - let invalidURLMessage; - if (parsedUrl.protocol !== "ws:" && !isSecure && !isUnixSocket) { - invalidURLMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; - } else if (isUnixSocket && !parsedUrl.pathname) { - invalidURLMessage = "The URL's pathname is empty"; - } else if (parsedUrl.hash) { - invalidURLMessage = "The URL contains a fragment identifier"; - } - if (invalidURLMessage) { - const err = new SyntaxError(invalidURLMessage); - if (websocket._redirects === 0) { - throw err; + let toWrite = stream[kImpl].buf.slice(0, leftover); + let toWriteBytes = Buffer.byteLength(toWrite); + if (toWriteBytes <= leftover) { + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, nextFlush.bind(null, stream)); } else { - emitErrorAndClose(websocket, err); + stream.flush(() => { + if (stream.destroyed) { + return; + } + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + while (toWriteBytes > stream[kImpl].data.length) { + leftover = leftover / 2; + toWrite = stream[kImpl].buf.slice(0, leftover); + toWriteBytes = Buffer.byteLength(toWrite); + } + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, nextFlush.bind(null, stream)); + }); + } + } else if (leftover === 0) { + if (writeIndex === 0 && stream[kImpl].buf.length === 0) { return; } - } - const defaultPort = isSecure ? 443 : 80; - const key = randomBytes3(16).toString("base64"); - const get2 = isSecure ? https.get : http.get; - const protocolSet = /* @__PURE__ */ new Set(); - let perMessageDeflate; - opts.createConnection = isSecure ? tlsConnect : netConnect; - opts.defaultPort = opts.defaultPort || defaultPort; - opts.port = parsedUrl.port || defaultPort; - opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; - opts.headers = { - "Sec-WebSocket-Version": opts.protocolVersion, - "Sec-WebSocket-Key": key, - Connection: "Upgrade", - Upgrade: "websocket", - ...opts.headers - }; - opts.path = parsedUrl.pathname + parsedUrl.search; - opts.timeout = opts.handshakeTimeout; - if (opts.perMessageDeflate) { - perMessageDeflate = new PerMessageDeflate( - opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, - false, - opts.maxPayload - ); - opts.headers["Sec-WebSocket-Extensions"] = format52({ - [PerMessageDeflate.extensionName]: perMessageDeflate.offer() + stream.flush(() => { + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + nextFlush(stream); }); + } else { + destroy(stream, new Error("overwritten")); } - if (protocols.length) { - for (const protocol of protocols) { - if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { - throw new SyntaxError( - "An invalid or duplicated subprotocol was specified" - ); - } - protocolSet.add(protocol); - } - opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); - } - if (opts.origin) { - if (opts.protocolVersion < 13) { - opts.headers["Sec-WebSocket-Origin"] = opts.origin; - } else { - opts.headers.Origin = opts.origin; - } + } + function onWorkerMessage(msg) { + const stream = this.stream.deref(); + if (stream === void 0) { + this.exited = true; + this.terminate(); + return; } - if (parsedUrl.username || parsedUrl.password) { - opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + switch (msg.code) { + case "READY": + this.stream = new WeakRef2(stream); + stream.flush(() => { + stream[kImpl].ready = true; + stream.emit("ready"); + }); + break; + case "ERROR": + destroy(stream, msg.err); + break; + case "EVENT": + if (Array.isArray(msg.args)) { + stream.emit(msg.name, ...msg.args); + } else { + stream.emit(msg.name, msg.args); + } + break; + case "WARNING": + process.emitWarning(msg.err); + break; + default: + destroy(stream, new Error("this should not happen: " + msg.code)); } - if (isUnixSocket) { - const parts = opts.path.split(":"); - opts.socketPath = parts[0]; - opts.path = parts[1]; + } + function onWorkerExit(code2) { + const stream = this.stream.deref(); + if (stream === void 0) { + return; } - if (opts.followRedirects) { - if (websocket._redirects === 0) { - websocket._originalHost = parsedUrl.host; - const headers = options2 && options2.headers; - options2 = { ...options2, headers: {} }; - if (headers) { - for (const [key2, value] of Object.entries(headers)) { - options2.headers[key2.toLowerCase()] = value; - } - } - } else if (parsedUrl.host !== websocket._originalHost) { - delete opts.headers.authorization; - delete opts.headers.cookie; - delete opts.headers.host; - opts.auth = void 0; - } - if (opts.auth && !options2.headers.authorization) { - options2.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); + registry2.unregister(stream); + stream.worker.exited = true; + stream.worker.off("exit", onWorkerExit); + destroy(stream, code2 !== 0 ? new Error("the worker thread exited") : null); + } + var ThreadStream = class extends EventEmitter { + constructor(opts = {}) { + super(); + if (opts.bufferSize < 4) { + throw new Error("bufferSize must at least fit a 4-byte utf-8 char"); } - } - let req = websocket._req = get2(opts); - if (opts.timeout) { - req.on("timeout", () => { - abortHandshake(websocket, req, "Opening handshake has timed out"); + this[kImpl] = {}; + this[kImpl].stateBuf = new SharedArrayBuffer(128); + this[kImpl].state = new Int32Array(this[kImpl].stateBuf); + this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024); + this[kImpl].data = Buffer.from(this[kImpl].dataBuf); + this[kImpl].sync = opts.sync || false; + this[kImpl].ending = false; + this[kImpl].ended = false; + this[kImpl].needDrain = false; + this[kImpl].destroyed = false; + this[kImpl].flushing = false; + this[kImpl].ready = false; + this[kImpl].finished = false; + this[kImpl].errored = null; + this[kImpl].closed = false; + this[kImpl].buf = ""; + this.worker = createWorker2(this, opts); + this.on("message", (message, transferList) => { + this.worker.postMessage(message, transferList); }); } - req.on("error", (err) => { - if (req === null || req.aborted) return; - req = websocket._req = null; - emitErrorAndClose(websocket, err); - }); - req.on("response", (res) => { - const location = res.headers.location; - const statusCode = res.statusCode; - if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { - if (++websocket._redirects > opts.maxRedirects) { - abortHandshake(websocket, req, "Maximum redirects exceeded"); - return; + write(data) { + if (this[kImpl].destroyed) { + error2(this, new Error("the worker has exited")); + return false; + } + if (this[kImpl].ending) { + error2(this, new Error("the worker is ending")); + return false; + } + if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) { + try { + writeSync(this); + this[kImpl].flushing = true; + } catch (err) { + destroy(this, err); + return false; } - req.abort(); - let addr; + } + this[kImpl].buf += data; + if (this[kImpl].sync) { try { - addr = new URL2(location, address); - } catch (e2) { - const err = new SyntaxError(`Invalid URL: ${location}`); - emitErrorAndClose(websocket, err); - return; + writeSync(this); + return true; + } catch (err) { + destroy(this, err); + return false; } - initAsClient(websocket, addr, protocols, options2); - } else if (!websocket.emit("unexpected-response", req, res)) { - abortHandshake( - websocket, - req, - `Unexpected server response: ${res.statusCode}` - ); } - }); - req.on("upgrade", (res, socket, head) => { - websocket.emit("upgrade", res); - if (websocket.readyState !== WebSocket3.CONNECTING) return; - req = websocket._req = null; - const digest = createHash("sha1").update(key + GUID).digest("base64"); - if (res.headers["sec-websocket-accept"] !== digest) { - abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header"); + if (!this[kImpl].flushing) { + this[kImpl].flushing = true; + setImmediate(nextFlush, this); + } + this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0; + return !this[kImpl].needDrain; + } + end() { + if (this[kImpl].destroyed) { return; } - const serverProt = res.headers["sec-websocket-protocol"]; - let protError; - if (serverProt !== void 0) { - if (!protocolSet.size) { - protError = "Server sent a subprotocol but none was requested"; - } else if (!protocolSet.has(serverProt)) { - protError = "Server sent an invalid subprotocol"; + this[kImpl].ending = true; + end(this); + } + flush(cb) { + if (this[kImpl].destroyed) { + if (typeof cb === "function") { + process.nextTick(cb, new Error("the worker has exited")); } - } else if (protocolSet.size) { - protError = "Server sent no subprotocol"; - } - if (protError) { - abortHandshake(websocket, socket, protError); return; } - if (serverProt) websocket._protocol = serverProt; - const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; - if (secWebSocketExtensions !== void 0) { - if (!perMessageDeflate) { - const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; - abortHandshake(websocket, socket, message); - return; - } - let extensions; - try { - extensions = parse52(secWebSocketExtensions); - } catch (err) { - const message = "Invalid Sec-WebSocket-Extensions header"; - abortHandshake(websocket, socket, message); - return; - } - const extensionNames = Object.keys(extensions); - if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) { - const message = "Server indicated an extension that was not requested"; - abortHandshake(websocket, socket, message); + const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX); + wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => { + if (err) { + destroy(this, err); + process.nextTick(cb, err); return; } - try { - perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); - } catch (err) { - const message = "Invalid Sec-WebSocket-Extensions header"; - abortHandshake(websocket, socket, message); + if (res === "not-equal") { + this.flush(cb); return; } - websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; - } - websocket.setSocket(socket, head, { - generateMask: opts.generateMask, - maxPayload: opts.maxPayload, - skipUTF8Validation: opts.skipUTF8Validation + process.nextTick(cb); }); - }); - } - function emitErrorAndClose(websocket, err) { - websocket._readyState = WebSocket3.CLOSING; - websocket.emit("error", err); - websocket.emitClose(); - } - function netConnect(options2) { - options2.path = options2.socketPath; - return net.connect(options2); - } - function tlsConnect(options2) { - options2.path = void 0; - if (!options2.servername && options2.servername !== "") { - options2.servername = net.isIP(options2.host) ? "" : options2.host; } - return tls.connect(options2); - } - function abortHandshake(websocket, stream, message) { - websocket._readyState = WebSocket3.CLOSING; - const err = new Error(message); - Error.captureStackTrace(err, abortHandshake); - if (stream.setHeader) { - stream.abort(); - if (stream.socket && !stream.socket.destroyed) { - stream.socket.destroy(); + flushSync() { + if (this[kImpl].destroyed) { + return; } - stream.once("abort", websocket.emitClose.bind(websocket)); - websocket.emit("error", err); - } else { - stream.destroy(err); - stream.once("error", websocket.emit.bind(websocket, "error")); - stream.once("close", websocket.emitClose.bind(websocket)); - } - } - function sendAfterClose(websocket, data, cb) { - if (data) { - const length2 = toBuffer(data).length; - if (websocket._socket) websocket._sender._bufferedBytes += length2; - else websocket._bufferedAmount += length2; + writeSync(this); + flushSync(this); } - if (cb) { - const err = new Error( - `WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})` - ); - cb(err); + unref() { + this.worker.unref(); } - } - function receiverOnConclude(code2, reason) { - const websocket = this[kWebSocket]; - websocket._closeFrameReceived = true; - websocket._closeMessage = reason; - websocket._closeCode = code2; - if (websocket._socket[kWebSocket] === void 0) return; - websocket._socket.removeListener("data", socketOnData); - process.nextTick(resume, websocket._socket); - if (code2 === 1005) websocket.close(); - else websocket.close(code2, reason); - } - function receiverOnDrain() { - const websocket = this[kWebSocket]; - if (!websocket.isPaused) websocket._socket.resume(); - } - function receiverOnError(err) { - const websocket = this[kWebSocket]; - if (websocket._socket[kWebSocket] !== void 0) { - websocket._socket.removeListener("data", socketOnData); - process.nextTick(resume, websocket._socket); - websocket.close(err[kStatusCode]); + ref() { + this.worker.ref(); } - websocket.emit("error", err); - } - function receiverOnFinish() { - this[kWebSocket].emitClose(); - } - function receiverOnMessage(data, isBinary) { - this[kWebSocket].emit("message", data, isBinary); - } - function receiverOnPing(data) { - const websocket = this[kWebSocket]; - websocket.pong(data, !websocket._isServer, NOOP); - websocket.emit("ping", data); - } - function receiverOnPong(data) { - this[kWebSocket].emit("pong", data); - } - function resume(stream) { - stream.resume(); - } - function socketOnClose() { - const websocket = this[kWebSocket]; - this.removeListener("close", socketOnClose); - this.removeListener("data", socketOnData); - this.removeListener("end", socketOnEnd); - websocket._readyState = WebSocket3.CLOSING; - let chunk; - if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && (chunk = websocket._socket.read()) !== null) { - websocket._receiver.write(chunk); + get ready() { + return this[kImpl].ready; } - websocket._receiver.end(); - this[kWebSocket] = void 0; - clearTimeout(websocket._closeTimer); - if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) { - websocket.emitClose(); - } else { - websocket._receiver.on("error", receiverOnFinish); - websocket._receiver.on("finish", receiverOnFinish); + get destroyed() { + return this[kImpl].destroyed; } - } - function socketOnData(chunk) { - if (!this[kWebSocket]._receiver.write(chunk)) { - this.pause(); + get closed() { + return this[kImpl].closed; } - } - function socketOnEnd() { - const websocket = this[kWebSocket]; - websocket._readyState = WebSocket3.CLOSING; - websocket._receiver.end(); - this.end(); - } - function socketOnError() { - const websocket = this[kWebSocket]; - this.removeListener("error", socketOnError); - this.on("error", NOOP); - if (websocket) { - websocket._readyState = WebSocket3.CLOSING; - this.destroy(); + get writable() { + return !this[kImpl].destroyed && !this[kImpl].ending; } - } - } -}); -var require_subprotocol = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/subprotocol.js"(exports2, module14) { - "use strict"; - var { tokenChars } = require_validation2(); - function parse52(header) { - const protocols = /* @__PURE__ */ new Set(); - let start = -1; - let end = -1; - let i2 = 0; - for (i2; i2 < header.length; i2++) { - const code2 = header.charCodeAt(i2); - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - const protocol2 = header.slice(start, end); - if (protocols.has(protocol2)) { - throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); - } - protocols.add(protocol2); - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } + get writableEnded() { + return this[kImpl].ending; } - if (start === -1 || end !== -1) { - throw new SyntaxError("Unexpected end of input"); + get writableFinished() { + return this[kImpl].finished; } - const protocol = header.slice(start, i2); - if (protocols.has(protocol)) { - throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + get writableNeedDrain() { + return this[kImpl].needDrain; } - protocols.add(protocol); - return protocols; - } - module14.exports = { parse: parse52 }; - } -}); -var require_websocket_server = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket-server.js"(exports2, module14) { - "use strict"; - var EventEmitter = __require2("events"); - var http = __require2("http"); - var https = __require2("https"); - var net = __require2("net"); - var tls = __require2("tls"); - var { createHash } = __require2("crypto"); - var extension = require_extension(); - var PerMessageDeflate = require_permessage_deflate(); - var subprotocol = require_subprotocol(); - var WebSocket3 = require_websocket(); - var { GUID, kWebSocket } = require_constants2(); - var keyRegex = /^[+/0-9A-Za-z]{22}==$/; - var RUNNING = 0; - var CLOSING = 1; - var CLOSED = 2; - var WebSocketServer2 = class extends EventEmitter { - /** - * Create a `WebSocketServer` instance. - * - * @param {Object} options Configuration options - * @param {Number} [options.backlog=511] The maximum length of the queue of - * pending connections - * @param {Boolean} [options.clientTracking=true] Specifies whether or not to - * track clients - * @param {Function} [options.handleProtocols] A hook to handle protocols - * @param {String} [options.host] The hostname where to bind the server - * @param {Number} [options.maxPayload=104857600] The maximum allowed message - * size - * @param {Boolean} [options.noServer=false] Enable no server mode - * @param {String} [options.path] Accept only connections matching this path - * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable - * permessage-deflate - * @param {Number} [options.port] The port where to bind the server - * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S - * server to use - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages - * @param {Function} [options.verifyClient] A hook to reject connections - * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` - * class to use. It must be the `WebSocket` class or class that extends it - * @param {Function} [callback] A listener for the `listening` event - */ - constructor(options2, callback) { - super(); - options2 = { - maxPayload: 100 * 1024 * 1024, - skipUTF8Validation: false, - perMessageDeflate: false, - handleProtocols: null, - clientTracking: true, - verifyClient: null, - noServer: false, - backlog: null, - // use default (511 as implemented in net.js) - server: null, - host: null, - path: null, - port: null, - WebSocket: WebSocket3, - ...options2 - }; - if (options2.port == null && !options2.server && !options2.noServer || options2.port != null && (options2.server || options2.noServer) || options2.server && options2.noServer) { - throw new TypeError( - 'One and only one of the "port", "server", or "noServer" options must be specified' - ); - } - if (options2.port != null) { - this._server = http.createServer((req, res) => { - const body = http.STATUS_CODES[426]; - res.writeHead(426, { - "Content-Length": body.length, - "Content-Type": "text/plain" - }); - res.end(body); - }); - this._server.listen( - options2.port, - options2.host, - options2.backlog, - callback - ); - } else if (options2.server) { - this._server = options2.server; - } - if (this._server) { - const emitConnection = this.emit.bind(this, "connection"); - this._removeListeners = addListeners(this._server, { - listening: this.emit.bind(this, "listening"), - error: this.emit.bind(this, "error"), - upgrade: (req, socket, head) => { - this.handleUpgrade(req, socket, head, emitConnection); - } - }); - } - if (options2.perMessageDeflate === true) options2.perMessageDeflate = {}; - if (options2.clientTracking) { - this.clients = /* @__PURE__ */ new Set(); - this._shouldEmitClose = false; - } - this.options = options2; - this._state = RUNNING; + get writableObjectMode() { + return false; } - /** - * Returns the bound address, the address family name, and port of the server - * as reported by the operating system if listening on an IP socket. - * If the server is listening on a pipe or UNIX domain socket, the name is - * returned as a string. - * - * @return {(Object|String|null)} The address of the server - * @public - */ - address() { - if (this.options.noServer) { - throw new Error('The server is operating in "noServer" mode'); - } - if (!this._server) return null; - return this._server.address(); + get writableErrored() { + return this[kImpl].errored; } - /** - * Stop the server from accepting new connections and emit the `'close'` event - * when all existing connections are closed. - * - * @param {Function} [cb] A one-time listener for the `'close'` event - * @public - */ - close(cb) { - if (this._state === CLOSED) { - if (cb) { - this.once("close", () => { - cb(new Error("The server is not running")); - }); - } - process.nextTick(emitClose, this); - return; - } - if (cb) this.once("close", cb); - if (this._state === CLOSING) return; - this._state = CLOSING; - if (this.options.noServer || this.options.server) { - if (this._server) { - this._removeListeners(); - this._removeListeners = this._server = null; - } - if (this.clients) { - if (!this.clients.size) { - process.nextTick(emitClose, this); - } else { - this._shouldEmitClose = true; - } - } else { - process.nextTick(emitClose, this); - } - } else { - const server = this._server; - this._removeListeners(); - this._removeListeners = this._server = null; - server.close(() => { - emitClose(this); - }); - } + }; + function error2(stream, err) { + setImmediate(() => { + stream.emit("error", err); + }); + } + function destroy(stream, err) { + if (stream[kImpl].destroyed) { + return; } - /** - * See if a given request should be handled by this server instance. - * - * @param {http.IncomingMessage} req Request object to inspect - * @return {Boolean} `true` if the request is valid, else `false` - * @public - */ - shouldHandle(req) { - if (this.options.path) { - const index = req.url.indexOf("?"); - const pathname = index !== -1 ? req.url.slice(0, index) : req.url; - if (pathname !== this.options.path) return false; - } - return true; + stream[kImpl].destroyed = true; + if (err) { + stream[kImpl].errored = err; + error2(stream, err); } - /** - * Handle a HTTP Upgrade request. - * - * @param {http.IncomingMessage} req The request object - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Function} cb Callback - * @public - */ - handleUpgrade(req, socket, head, cb) { - socket.on("error", socketOnError); - const key = req.headers["sec-websocket-key"] !== void 0 ? req.headers["sec-websocket-key"] : false; - const version3 = +req.headers["sec-websocket-version"]; - if (req.method !== "GET" || req.headers.upgrade.toLowerCase() !== "websocket" || !key || !keyRegex.test(key) || version3 !== 8 && version3 !== 13 || !this.shouldHandle(req)) { - return abortHandshake(socket, 400); - } - const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; - let protocols = /* @__PURE__ */ new Set(); - if (secWebSocketProtocol !== void 0) { - try { - protocols = subprotocol.parse(secWebSocketProtocol); - } catch (err) { - return abortHandshake(socket, 400); - } - } - const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; - const extensions = {}; - if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { - const perMessageDeflate = new PerMessageDeflate( - this.options.perMessageDeflate, - true, - this.options.maxPayload - ); - try { - const offers = extension.parse(secWebSocketExtensions); - if (offers[PerMessageDeflate.extensionName]) { - perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); - extensions[PerMessageDeflate.extensionName] = perMessageDeflate; - } - } catch (err) { - return abortHandshake(socket, 400); + if (!stream.worker.exited) { + stream.worker.terminate().catch(() => { + }).then(() => { + stream[kImpl].closed = true; + stream.emit("close"); + }); + } else { + setImmediate(() => { + stream[kImpl].closed = true; + stream.emit("close"); + }); + } + } + function write(stream, data, cb) { + const current = Atomics.load(stream[kImpl].state, WRITE_INDEX); + const length2 = Buffer.byteLength(data); + stream[kImpl].data.write(data, current); + Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length2); + Atomics.notify(stream[kImpl].state, WRITE_INDEX); + cb(); + return true; + } + function end(stream) { + if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) { + return; + } + stream[kImpl].ended = true; + try { + stream.flushSync(); + let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + Atomics.store(stream[kImpl].state, WRITE_INDEX, -1); + Atomics.notify(stream[kImpl].state, WRITE_INDEX); + let spins = 0; + while (readIndex !== -1) { + Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); + readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + if (readIndex === -2) { + destroy(stream, new Error("end() failed")); + return; } - } - if (this.options.verifyClient) { - const info = { - origin: req.headers[`${version3 === 8 ? "sec-websocket-origin" : "origin"}`], - secure: !!(req.socket.authorized || req.socket.encrypted), - req - }; - if (this.options.verifyClient.length === 2) { - this.options.verifyClient(info, (verified, code2, message, headers) => { - if (!verified) { - return abortHandshake(socket, code2 || 401, message, headers); - } - this.completeUpgrade( - extensions, - key, - protocols, - req, - socket, - head, - cb - ); - }); + if (++spins === 10) { + destroy(stream, new Error("end() took too long (10s)")); return; } - if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); } - this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); + process.nextTick(() => { + stream[kImpl].finished = true; + stream.emit("finish"); + }); + } catch (err) { + destroy(stream, err); } - /** - * Upgrade the connection to WebSocket. - * - * @param {Object} extensions The accepted extensions - * @param {String} key The value of the `Sec-WebSocket-Key` header - * @param {Set} protocols The subprotocols - * @param {http.IncomingMessage} req The request object - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Function} cb Callback - * @throws {Error} If called more than once with the same socket - * @private - */ - completeUpgrade(extensions, key, protocols, req, socket, head, cb) { - if (!socket.readable || !socket.writable) return socket.destroy(); - if (socket[kWebSocket]) { - throw new Error( - "server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" - ); + } + function writeSync(stream) { + const cb = () => { + if (stream[kImpl].ending) { + end(stream); + } else if (stream[kImpl].needDrain) { + process.nextTick(drain, stream); } - if (this._state > RUNNING) return abortHandshake(socket, 503); - const digest = createHash("sha1").update(key + GUID).digest("base64"); - const headers = [ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - `Sec-WebSocket-Accept: ${digest}` - ]; - const ws = new this.options.WebSocket(null); - if (protocols.size) { - const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; - if (protocol) { - headers.push(`Sec-WebSocket-Protocol: ${protocol}`); - ws._protocol = protocol; + }; + stream[kImpl].flushing = false; + while (stream[kImpl].buf.length !== 0) { + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let leftover = stream[kImpl].data.length - writeIndex; + if (leftover === 0) { + flushSync(stream); + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + continue; + } else if (leftover < 0) { + throw new Error("overwritten"); + } + let toWrite = stream[kImpl].buf.slice(0, leftover); + let toWriteBytes = Buffer.byteLength(toWrite); + if (toWriteBytes <= leftover) { + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, cb); + } else { + flushSync(stream); + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + while (toWriteBytes > stream[kImpl].buf.length) { + leftover = leftover / 2; + toWrite = stream[kImpl].buf.slice(0, leftover); + toWriteBytes = Buffer.byteLength(toWrite); } + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, cb); } - if (extensions[PerMessageDeflate.extensionName]) { - const params = extensions[PerMessageDeflate.extensionName].params; - const value = extension.format({ - [PerMessageDeflate.extensionName]: [params] - }); - headers.push(`Sec-WebSocket-Extensions: ${value}`); - ws._extensions = extensions; + } + } + function flushSync(stream) { + if (stream[kImpl].flushing) { + throw new Error("unable to flush while flushing"); + } + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let spins = 0; + while (true) { + const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + if (readIndex === -2) { + throw Error("_flushSync failed"); } - this.emit("headers", headers, req); - socket.write(headers.concat("\r\n").join("\r\n")); - socket.removeListener("error", socketOnError); - ws.setSocket(socket, head, { - maxPayload: this.options.maxPayload, - skipUTF8Validation: this.options.skipUTF8Validation - }); - if (this.clients) { - this.clients.add(ws); - ws.on("close", () => { - this.clients.delete(ws); - if (this._shouldEmitClose && !this.clients.size) { - process.nextTick(emitClose, this); - } - }); + if (readIndex !== writeIndex) { + Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); + } else { + break; } - cb(ws, req); - } - }; - module14.exports = WebSocketServer2; - function addListeners(server, map) { - for (const event of Object.keys(map)) server.on(event, map[event]); - return function removeListeners() { - for (const event of Object.keys(map)) { - server.removeListener(event, map[event]); + if (++spins === 10) { + throw new Error("_flushSync took too long (10s)"); } - }; - } - function emitClose(server) { - server._state = CLOSED; - server.emit("close"); - } - function socketOnError() { - this.destroy(); - } - function abortHandshake(socket, code2, message, headers) { - if (socket.writable) { - message = message || http.STATUS_CODES[code2]; - headers = { - Connection: "close", - "Content-Type": "text/html", - "Content-Length": Buffer.byteLength(message), - ...headers - }; - socket.write( - `HTTP/1.1 ${code2} ${http.STATUS_CODES[code2]}\r -` + Object.keys(headers).map((h2) => `${h2}: ${headers[h2]}`).join("\r\n") + "\r\n\r\n" + message - ); } - socket.removeListener("error", socketOnError); - socket.destroy(); } + module14.exports = ThreadStream; } }); -var import_stream; -var import_receiver; -var import_sender; -var import_websocket; -var import_websocket_server; -var wrapper_default; -var init_wrapper = __esm({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/wrapper.mjs"() { - import_stream = __toESM(require_stream(), 1); - import_receiver = __toESM(require_receiver(), 1); - import_sender = __toESM(require_sender(), 1); - import_websocket = __toESM(require_websocket(), 1); - import_websocket_server = __toESM(require_websocket_server(), 1); - wrapper_default = import_websocket.default; - } -}); -function createErrorResponse(data) { - return JSON.stringify({ type: ERROR, data }); -} -function createPushErrorResponse(data) { - return JSON.stringify({ - type: ERROR, - data: { - ...data, - type: REQUEST_TYPE.PUSH_ACTION +var require_transport = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports2, module14) { + "use strict"; + var { createRequire } = __require2("module"); + var getCallers = require_caller(); + var { join: join10, isAbsolute: isAbsolute8, sep } = __require2("path"); + var sleep = require_atomic_sleep(); + var onExit = require_on_exit_leak_free(); + var ThreadStream = require_thread_stream(); + function setupOnExit(stream) { + onExit.register(stream, autoEnd); + onExit.registerBeforeExit(stream, flush); + stream.on("close", function() { + onExit.unregister(stream); + }); } - }); -} -function createNotification(type, data) { - return JSON.stringify({ type, data }); -} -function createOkResponse(data) { - return JSON.stringify({ type: OK, data }); -} -function createServer(httpServer, options2 = {}) { - const server = new import_websocket_server.default({ - ...defaultOptions3, - ...options2, - ...{ clientTracking: true }, - server: httpServer - }); - server.channels = /* @__PURE__ */ new Set(); - server.customServerEventHandlers = { ...options2.serverHandlers }; - server.customSocketEventHandlers = { ...options2.socketHandlers }; - server.customMessageHandlers = { ...options2.messageHandlers }; - server.pingIntervalID = void 0; - server.subscribersByChannelID = /* @__PURE__ */ Object.create(null); - server.pushSubscriptions = /* @__PURE__ */ Object.create(null); - const handlers = Object.keys(defaultServerHandlers); - handlers.forEach((name) => { - server.on(name, (...args) => { - try { - ; - defaultServerHandlers[name].apply(server, args); - server.customServerEventHandlers[name]?.apply(server, args); - } catch (error2) { - server.emit("error", error2); - } - }); - }); - if (server.options.pingInterval > 0) { - server.pingIntervalID = setInterval(() => { - if (server.clients.size && server.options.logPingRounds) { - log.debug("Pinging clients"); - } - server.clients.forEach((client) => { - if (isPushSubscriptionInfo(client)) return; - if (client.pinged && !client.activeSinceLastPing) { - log(`Disconnecting irresponsive client ${client.id}`); - return client.terminate(); + function buildStream(filename, workerData, workerOpts) { + const stream = new ThreadStream({ + filename, + workerData, + workerOpts + }); + stream.on("ready", onReady); + stream.on("close", function() { + process.removeListener("exit", onExit2); + }); + process.on("exit", onExit2); + function onReady() { + process.removeListener("exit", onExit2); + stream.unref(); + if (workerOpts.autoEnd !== false) { + setupOnExit(stream); } - if (client.readyState === wrapper_default.OPEN) { - client.send(createMessage(PING, Date.now()), () => { - client.activeSinceLastPing = false; - client.pinged = true; - }); + } + function onExit2() { + if (stream.closed) { + return; } + stream.flushSync(); + sleep(100); + stream.end(); + } + return stream; + } + function autoEnd(stream) { + stream.ref(); + stream.flushSync(); + stream.end(); + stream.once("close", function() { + stream.unref(); }); - }, server.options.pingInterval); - } - return Object.assign(server, publicMethods2); -} -var import_npm_chalk; -var isPushSubscriptionInfo; -var bold; -var PING; -var PONG; -var PUB; -var SUB; -var UNSUB; -var KV_FILTER; -var ERROR; -var OK; -var defaultOptions3; -var tag2; -var generateSocketID; -var log; -var defaultServerHandlers; -var defaultSocketEventHandlers; -var defaultMessageHandlers2; -var publicMethods2; -var init_pubsub2 = __esm({ - "src/serve/pubsub.ts"() { - "use strict"; - init_esm5(); - init_pubsub(); - init_push(); - init_logger(); - import_npm_chalk = __toESM(require_source()); - init_wrapper(); - isPushSubscriptionInfo = (x3) => { - return has(x3, "endpoint"); - }; - ({ bold } = import_npm_chalk.default); - ({ PING, PONG, PUB, SUB, UNSUB, KV_FILTER } = NOTIFICATION_TYPE); - ({ ERROR, OK } = RESPONSE_TYPE); - defaultOptions3 = { - logPingRounds: process8.env.NODE_ENV !== "production" && !process8.env.CI, - logPongMessages: false, - maxPayload: 6 * 1024 * 1024, - pingInterval: 3e4 - }; - tag2 = "[pubsub]"; - generateSocketID = /* @__PURE__ */ (() => { - let counter = 0; - return (debugID) => String(counter++) + (debugID ? "-" + debugID : ""); - })(); - log = logger_default.info.bind(logger_default, tag2); - log.bold = (...args) => logger_default.debug(bold(tag2, ...args)); - log.debug = logger_default.debug.bind(logger_default, tag2); - log.error = (error2, ...args) => logger_default.error(error2, bold.red(tag2, ...args)); - defaultServerHandlers = { - close() { - log("Server closed"); - }, - /** - * Emitted when a connection handshake completes. - * - * @see https://github.com/websockets/ws/blob/master/doc/ws.md#event-connection - * @param {ws.WebSocket} socket - The client socket that connected. - * @param {http.IncomingMessage} request - The underlying Node http GET request. - */ - connection(socket, request) { - const server = this; - const url2 = request.url; - const urlSearch = url2?.includes("?") ? url2.slice(url2.lastIndexOf("?")) : ""; - const debugID = new URLSearchParams(urlSearch).get("debugID") || ""; - const send = socket.send.bind(socket); - socket.id = generateSocketID(debugID); - socket.activeSinceLastPing = true; - socket.pinged = false; - socket.server = server; - socket.subscriptions = /* @__PURE__ */ new Set(); - socket.kvFilter = /* @__PURE__ */ new Map(); - socket.ip = request.headers["x-real-ip"] || request.headers["x-forwarded-for"]?.split(",")[0].trim() || request.socket.remoteAddress; - socket.send = function(data) { - if (typeof data === "object" && data !== null && typeof data[Symbol.toPrimitive] === "function") { - return send(data[Symbol.toPrimitive]()); - } - return send(data); - }; - log.bold(`Socket ${socket.id} connected. Total: ${this.clients.size}`); - ["close", "error", "message", "ping", "pong"].forEach((eventName) => { - socket.on(eventName, (...args) => { - if (eventName !== "message") { - log.debug(`Event '${eventName}' on socket ${socket.id}`, ...args.map((arg) => String(arg))); - } - try { - ; - defaultSocketEventHandlers[eventName]?.call(socket, ...args); - socket.server.customSocketEventHandlers[eventName]?.call(socket, ...args); - } catch (error2) { - socket.server.emit("error", error2); - socket.terminate(); - } - }); - }); - }, - error(error2) { - log.error(error2, "Server error"); - }, - headers() { - }, - listening() { - log("Server listening"); + } + function flush(stream) { + stream.flushSync(); + } + function transport(fullOptions) { + const { pipeline, targets, levels, dedupe, options: options2 = {}, worker = {}, caller = getCallers() } = fullOptions; + const callers = typeof caller === "string" ? [caller] : caller; + const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; + let target = fullOptions.target; + if (target && targets) { + throw new Error("only one of target or targets can be specified"); } - }; - defaultSocketEventHandlers = { - close() { - const socket = this; - const { server } = this; - for (const channelID of socket.subscriptions) { - server.subscribersByChannelID[channelID].delete(socket); - } - socket.subscriptions.clear(); - }, - message(data) { - const socket = this; - const { server } = this; - const text = data.toString(); - let msg = { type: "" }; - try { - msg = messageParser(text); - } catch (error2) { - log.error(error2, `Malformed message: ${error2.message}`); - server.rejectMessageAndTerminateSocket(msg, socket); - return; + if (targets) { + target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js"); + options2.targets = targets.map((dest) => { + return { + ...dest, + target: fixTarget(dest.target) + }; + }); + } else if (pipeline) { + target = bundlerOverrides["pino-pipeline-worker"] || join10(__dirname, "worker-pipeline.js"); + options2.targets = pipeline.map((dest) => { + return { + ...dest, + target: fixTarget(dest.target) + }; + }); + } + if (levels) { + options2.levels = levels; + } + if (dedupe) { + options2.dedupe = dedupe; + } + return buildStream(fixTarget(target), options2, worker); + function fixTarget(origin) { + origin = bundlerOverrides[origin] || origin; + if (isAbsolute8(origin) || origin.indexOf("file://") === 0) { + return origin; } - if (msg.type !== "pong" || server.options.logPongMessages) { - log.debug(`Received '${msg.type}' on socket ${socket.id}`, text); + if (origin === "pino/file") { + return join10(__dirname, "..", "file.js"); } - socket.activeSinceLastPing = true; - const defaultHandler = defaultMessageHandlers2[msg.type]; - const customHandler = server.customMessageHandlers[msg.type]; - if (defaultHandler || customHandler) { + let fixTarget2; + for (const filePath of callers) { try { - ; - defaultHandler?.call(socket, msg); - customHandler?.call(socket, msg); - } catch (error2) { - log.error(error2, "onMessage"); - server.rejectMessageAndTerminateSocket(msg, socket); + const context = filePath === "node:repl" ? process.cwd() + sep : filePath; + fixTarget2 = createRequire(context).resolve(origin); + break; + } catch (err) { + continue; } - } else { - log.error(`Unhandled message type: ${msg.type}`); - server.rejectMessageAndTerminateSocket(msg, socket); } - } - }; - defaultMessageHandlers2 = { - [PONG]() { - const socket = this; - socket.activeSinceLastPing = true; - }, - [PUB](msg) { - const { server } = this; - const subscribers = server.subscribersByChannelID[msg.channelID]; - server.broadcast(msg, { to: subscribers ?? [] }); - }, - [SUB]({ channelID, kvFilter }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); - return; + if (!fixTarget2) { + throw new Error(`unable to determine transport target for "${origin}"`); } - if (!socket.subscriptions.has(channelID)) { - socket.subscriptions.add(channelID); - if (Array.isArray(kvFilter)) { - socket.kvFilter.set(channelID, new Set(kvFilter)); + return fixTarget2; + } + } + module14.exports = transport; + } +}); +var require_tools = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/tools.js"(exports2, module14) { + "use strict"; + var format52 = require_quick_format_unescaped(); + var { mapHttpRequest, mapHttpResponse } = require_pino_std_serializers(); + var SonicBoom = require_sonic_boom(); + var onExit = require_on_exit_leak_free(); + var { + lsCacheSym, + chindingsSym, + writeSym, + serializersSym, + formatOptsSym, + endSym, + stringifiersSym, + stringifySym, + stringifySafeSym, + wildcardFirstSym, + nestedKeySym, + formattersSym, + messageKeySym, + errorKeySym, + nestedKeyStrSym, + msgPrefixSym + } = require_symbols(); + var { isMainThread } = __require2("worker_threads"); + var transport = require_transport(); + function noop() { + } + function genLog(level, hook) { + if (!hook) return LOG; + return function hookWrappedLog(...args) { + hook.call(this, args, LOG, level); + }; + function LOG(o2, ...n) { + if (typeof o2 === "object") { + let msg = o2; + if (o2 !== null) { + if (o2.method && o2.headers && o2.socket) { + o2 = mapHttpRequest(o2); + } else if (typeof o2.setHeader === "function") { + o2 = mapHttpResponse(o2); + } } - if (!server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); + let formatParams; + if (msg === null && n.length === 0) { + formatParams = [null]; + } else { + msg = n.shift(); + formatParams = n; } - server.subscribersByChannelID[channelID].add(socket); + if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { + msg = this[msgPrefixSym] + msg; + } + this[writeSym](o2, format52(msg, formatParams, this[formatOptsSym]), level); } else { - log.debug("Already subscribed to", channelID); + let msg = o2 === void 0 ? n.shift() : o2; + if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { + msg = this[msgPrefixSym] + msg; + } + this[writeSym](null, format52(msg, n, this[formatOptsSym]), level); } - socket.send(createOkResponse({ type: SUB, channelID, kvFilter })); - }, - [KV_FILTER]({ channelID, kvFilter }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); - return; + } + } + function asString(str) { + let result = ""; + let last = 0; + let found = false; + let point = 255; + const l = str.length; + if (l > 100) { + return JSON.stringify(str); + } + for (var i2 = 0; i2 < l && point >= 32; i2++) { + point = str.charCodeAt(i2); + if (point === 34 || point === 92) { + result += str.slice(last, i2) + "\\"; + last = i2; + found = true; } - if (socket.subscriptions.has(channelID)) { - if (Array.isArray(kvFilter)) { - socket.kvFilter.set(channelID, new Set(kvFilter)); - } else { - socket.kvFilter.delete(channelID); + } + if (!found) { + result = str; + } else { + result += str.slice(last); + } + return point < 32 ? JSON.stringify(str) : '"' + result + '"'; + } + function asJson(obj, msg, num, time3) { + const stringify3 = this[stringifySym]; + const stringifySafe = this[stringifySafeSym]; + const stringifiers = this[stringifiersSym]; + const end = this[endSym]; + const chindings = this[chindingsSym]; + const serializers = this[serializersSym]; + const formatters = this[formattersSym]; + const messageKey = this[messageKeySym]; + const errorKey = this[errorKeySym]; + let data = this[lsCacheSym][num] + time3; + data = data + chindings; + let value; + if (formatters.log) { + obj = formatters.log(obj); + } + const wildcardStringifier = stringifiers[wildcardFirstSym]; + let propStr = ""; + for (const key in obj) { + value = obj[key]; + if (Object.prototype.hasOwnProperty.call(obj, key) && value !== void 0) { + if (serializers[key]) { + value = serializers[key](value); + } else if (key === errorKey && serializers.err) { + value = serializers.err(value); } - } else { - log.debug("[KV_FILTER] Not subscribed to", channelID); + const stringifier = stringifiers[key] || wildcardStringifier; + switch (typeof value) { + case "undefined": + case "function": + continue; + case "number": + if (Number.isFinite(value) === false) { + value = null; + } + // this case explicitly falls through to the next one + case "boolean": + if (stringifier) value = stringifier(value); + break; + case "string": + value = (stringifier || asString)(value); + break; + default: + value = (stringifier || stringify3)(value, stringifySafe); + } + if (value === void 0) continue; + const strKey = asString(key); + propStr += "," + strKey + ":" + value; } - socket.send(createOkResponse({ type: KV_FILTER, channelID, kvFilter })); - }, - [UNSUB]({ channelID }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: UNSUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); + } + let msgStr = ""; + if (msg !== void 0) { + value = serializers[messageKey] ? serializers[messageKey](msg) : msg; + const stringifier = stringifiers[messageKey] || wildcardStringifier; + switch (typeof value) { + case "function": + break; + case "number": + if (Number.isFinite(value) === false) { + value = null; + } + // this case explicitly falls through to the next one + case "boolean": + if (stringifier) value = stringifier(value); + msgStr = ',"' + messageKey + '":' + value; + break; + case "string": + value = (stringifier || asString)(value); + msgStr = ',"' + messageKey + '":' + value; + break; + default: + value = (stringifier || stringify3)(value, stringifySafe); + msgStr = ',"' + messageKey + '":' + value; } - if (socket.subscriptions.has(channelID)) { - socket.subscriptions.delete(channelID); - socket.kvFilter.delete(channelID); - if (server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID].delete(socket); - } + } + if (this[nestedKeySym] && propStr) { + return data + this[nestedKeyStrSym] + propStr.slice(1) + "}" + msgStr + end; + } else { + return data + propStr + msgStr + end; + } + } + function asChindings(instance, bindings) { + let value; + let data = instance[chindingsSym]; + const stringify3 = instance[stringifySym]; + const stringifySafe = instance[stringifySafeSym]; + const stringifiers = instance[stringifiersSym]; + const wildcardStringifier = stringifiers[wildcardFirstSym]; + const serializers = instance[serializersSym]; + const formatter = instance[formattersSym].bindings; + bindings = formatter(bindings); + for (const key in bindings) { + value = bindings[key]; + const valid = key !== "level" && key !== "serializers" && key !== "formatters" && key !== "customLevels" && bindings.hasOwnProperty(key) && value !== void 0; + if (valid === true) { + value = serializers[key] ? serializers[key](value) : value; + value = (stringifiers[key] || wildcardStringifier || stringify3)(value, stringifySafe); + if (value === void 0) continue; + data += ',"' + key + '":' + value; } - socket.send(createOkResponse({ type: UNSUB, channelID })); } - }; - publicMethods2 = { - /** - * Broadcasts a message, ignoring clients which are not open. - * - * @param message - * @param to - The intended recipients of the message. Defaults to every open client socket. - * @param except - A recipient to exclude. Optional. - */ - broadcast(message, { to, except, wsOnly } = {}) { - const server = this; - const msg = typeof message === "string" ? message : JSON.stringify(message); - let shortMsg; - const shortenPayload = () => { - if (!shortMsg && (typeof message === "object" && message.type === NOTIFICATION_TYPE.ENTRY && message.data)) { - delete message.data; - shortMsg = JSON.stringify(message); + return data; + } + function hasBeenTampered(stream) { + return stream.write !== stream.constructor.prototype.write; + } + var hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE; + function buildSafeSonicBoom(opts) { + const stream = new SonicBoom(opts); + stream.on("error", filterBrokenPipe); + if (!hasNodeCodeCoverage && !opts.sync && isMainThread) { + onExit.register(stream, autoEnd); + stream.on("close", function() { + onExit.unregister(stream); + }); + } + return stream; + function filterBrokenPipe(err) { + if (err.code === "EPIPE") { + stream.write = noop; + stream.end = noop; + stream.flushSync = noop; + stream.destroy = noop; + return; + } + stream.removeListener("error", filterBrokenPipe); + stream.emit("error", err); + } + } + function autoEnd(stream, eventName) { + if (stream.destroyed) { + return; + } + if (eventName === "beforeExit") { + stream.flush(); + stream.on("drain", function() { + stream.end(); + }); + } else { + stream.flushSync(); + } + } + function createArgsNormalizer(defaultOptions4) { + return function normalizeArgs(instance, caller, opts = {}, stream) { + if (typeof opts === "string") { + stream = buildSafeSonicBoom({ dest: opts }); + opts = {}; + } else if (typeof stream === "string") { + if (opts && opts.transport) { + throw Error("only one of option.transport or stream can be specified"); } - return shortMsg; - }; - for (const client of to || server.clients) { - if (!wsOnly && isPushSubscriptionInfo(client)) { - if (msg.length > 4096 - 86 - 17) { - if (!shortenPayload()) { - console.info("Skipping too large of a payload for", client.id); - continue; - } - } - postEvent(client, shortMsg || msg).catch((e2) => { - if (e2?.message === "Payload too large") { - if (shortMsg || !shortenPayload()) { - console.info("Skipping too large of a payload for", client.id); - return; - } - postEvent(client, shortMsg).catch((e3) => { - console.error(e3, "Error posting push notification"); - }); - return; - } - console.error(e2, "Error posting push notification"); - }); - continue; + stream = buildSafeSonicBoom({ dest: stream }); + } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) { + stream = opts; + opts = {}; + } else if (opts.transport) { + if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) { + throw Error("option.transport do not allow stream, please pass to option directly. e.g. pino(transport)"); } - if (client.readyState === wrapper_default.OPEN && client !== except) { - client.send(msg); + if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === "function") { + throw Error("option.transport.targets do not allow custom level formatters"); + } + let customLevels; + if (opts.customLevels) { + customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels); } + stream = transport({ caller, ...opts.transport, levels: customLevels }); } - }, - // Enumerates the subscribers of a given channel. - *enumerateSubscribers(channelID, kvKey) { - const server = this; - if (channelID in server.subscribersByChannelID) { - const subscribers = server.subscribersByChannelID[channelID]; - if (!kvKey) { - yield* subscribers; + opts = Object.assign({}, defaultOptions4, opts); + opts.serializers = Object.assign({}, defaultOptions4.serializers, opts.serializers); + opts.formatters = Object.assign({}, defaultOptions4.formatters, opts.formatters); + if (opts.prettyPrint) { + throw new Error("prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)"); + } + const { enabled: enabled2, onChild } = opts; + if (enabled2 === false) opts.level = "silent"; + if (!onChild) opts.onChild = noop; + if (!stream) { + if (!hasBeenTampered(process.stdout)) { + stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 }); } else { - for (const subscriber of subscribers) { - const kvFilter = subscriber.kvFilter?.get(channelID); - if (!kvFilter || kvFilter.has(kvKey)) yield subscriber; + stream = process.stdout; + } + } + return { opts, stream }; + }; + } + function stringify2(obj, stringifySafeFn) { + try { + return JSON.stringify(obj); + } catch (_) { + try { + const stringify3 = stringifySafeFn || this[stringifySafeSym]; + return stringify3(obj); + } catch (_2) { + return '"[unable to serialize, circular reference is too complex to analyze]"'; + } + } + } + function buildFormatters(level, bindings, log2) { + return { + level, + bindings, + log: log2 + }; + } + function normalizeDestFileDescriptor(destination) { + const fd = Number(destination); + if (typeof destination === "string" && Number.isFinite(fd)) { + return fd; + } + if (destination === void 0) { + return 1; + } + return destination; + } + module14.exports = { + noop, + buildSafeSonicBoom, + asChindings, + asJson, + genLog, + createArgsNormalizer, + stringify: stringify2, + buildFormatters, + normalizeDestFileDescriptor + }; + } +}); +var require_constants = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/constants.js"(exports2, module14) { + var DEFAULT_LEVELS = { + trace: 10, + debug: 20, + info: 30, + warn: 40, + error: 50, + fatal: 60 + }; + var SORTING_ORDER = { + ASC: "ASC", + DESC: "DESC" + }; + module14.exports = { + DEFAULT_LEVELS, + SORTING_ORDER + }; + } +}); +var require_levels = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/levels.js"(exports2, module14) { + "use strict"; + var { + lsCacheSym, + levelValSym, + useOnlyCustomLevelsSym, + streamSym, + formattersSym, + hooksSym, + levelCompSym + } = require_symbols(); + var { noop, genLog } = require_tools(); + var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); + var levelMethods = { + fatal: (hook) => { + const logFatal = genLog(DEFAULT_LEVELS.fatal, hook); + return function(...args) { + const stream = this[streamSym]; + logFatal.call(this, ...args); + if (typeof stream.flushSync === "function") { + try { + stream.flushSync(); + } catch (e2) { } } - } + }; }, - rejectMessageAndTerminateSocket(request, socket) { - socket.send(createErrorResponse({ ...request }), () => socket.terminate()); - } - }; - } -}); -var require_parser2 = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js"(exports2) { - "use strict"; - exports2.load = function(received, defaults, onto = {}) { - var k, ref, v2; - for (k in defaults) { - v2 = defaults[k]; - onto[k] = (ref = received[k]) != null ? ref : v2; - } - return onto; + error: (hook) => genLog(DEFAULT_LEVELS.error, hook), + warn: (hook) => genLog(DEFAULT_LEVELS.warn, hook), + info: (hook) => genLog(DEFAULT_LEVELS.info, hook), + debug: (hook) => genLog(DEFAULT_LEVELS.debug, hook), + trace: (hook) => genLog(DEFAULT_LEVELS.trace, hook) }; - exports2.overwrite = function(received, defaults, onto = {}) { - var k, v2; - for (k in received) { - v2 = received[k]; - if (defaults[k] !== void 0) { - onto[k] = v2; - } + var nums = Object.keys(DEFAULT_LEVELS).reduce((o2, k) => { + o2[DEFAULT_LEVELS[k]] = k; + return o2; + }, {}); + var initialLsCache = Object.keys(nums).reduce((o2, k) => { + o2[k] = '{"level":' + Number(k); + return o2; + }, {}); + function genLsCache(instance) { + const formatter = instance[formattersSym].level; + const { labels } = instance.levels; + const cache2 = {}; + for (const label in labels) { + const level = formatter(labels[label], Number(label)); + cache2[label] = JSON.stringify(level).slice(0, -1); } - return onto; - }; - } -}); -var require_DLList = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/DLList.js"(exports2, module14) { - "use strict"; - var DLList; - DLList = class DLList { - constructor(incr, decr) { - this.incr = incr; - this.decr = decr; - this._first = null; - this._last = null; - this.length = 0; + instance[lsCacheSym] = cache2; + return instance; + } + function isStandardLevel(level, useOnlyCustomLevels) { + if (useOnlyCustomLevels) { + return false; } - push(value) { - var node; - this.length++; - if (typeof this.incr === "function") { - this.incr(); - } - node = { - value, - prev: this._last, - next: null - }; - if (this._last != null) { - this._last.next = node; - this._last = node; - } else { - this._first = this._last = node; - } - return void 0; + switch (level) { + case "fatal": + case "error": + case "warn": + case "info": + case "debug": + case "trace": + return true; + default: + return false; } - shift() { - var value; - if (this._first == null) { - return; - } else { - this.length--; - if (typeof this.decr === "function") { - this.decr(); - } - } - value = this._first.value; - if ((this._first = this._first.next) != null) { - this._first.prev = null; - } else { - this._last = null; - } - return value; + } + function setLevel(level) { + const { labels, values } = this.levels; + if (typeof level === "number") { + if (labels[level] === void 0) throw Error("unknown level value" + level); + level = labels[level]; } - first() { - if (this._first != null) { - return this._first.value; + if (values[level] === void 0) throw Error("unknown level " + level); + const preLevelVal = this[levelValSym]; + const levelVal = this[levelValSym] = values[level]; + const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]; + const levelComparison = this[levelCompSym]; + const hook = this[hooksSym].logMethod; + for (const key in values) { + if (levelComparison(values[key], levelVal) === false) { + this[key] = noop; + continue; } + this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook); } - getArray() { - var node, ref, results; - node = this._first; - results = []; - while (node != null) { - results.push((ref = node, node = node.next, ref.value)); - } - return results; + this.emit( + "level-change", + level, + levelVal, + labels[preLevelVal], + preLevelVal, + this + ); + } + function getLevel(level) { + const { levels, levelVal } = this; + return levels && levels.labels ? levels.labels[levelVal] : ""; + } + function isLevelEnabled(logLevel2) { + const { values } = this.levels; + const logLevelVal = values[logLevel2]; + return logLevelVal !== void 0 && this[levelCompSym](logLevelVal, this[levelValSym]); + } + function compareLevel(direction, current, expected) { + if (direction === SORTING_ORDER.DESC) { + return current <= expected; } - forEachShift(cb) { - var node; - node = this.shift(); - while (node != null) { - cb(node), node = this.shift(); - } - return void 0; + return current >= expected; + } + function genLevelComparison(levelComparison) { + if (typeof levelComparison === "string") { + return compareLevel.bind(null, levelComparison); } - debug() { - var node, ref, ref1, ref2, results; - node = this._first; - results = []; - while (node != null) { - results.push((ref = node, node = node.next, { - value: ref.value, - prev: (ref1 = ref.prev) != null ? ref1.value : void 0, - next: (ref2 = ref.next) != null ? ref2.value : void 0 - })); + return levelComparison; + } + function mappings(customLevels = null, useOnlyCustomLevels = false) { + const customNums = customLevels ? Object.keys(customLevels).reduce((o2, k) => { + o2[customLevels[k]] = k; + return o2; + }, {}) : null; + const labels = Object.assign( + Object.create(Object.prototype, { Infinity: { value: "silent" } }), + useOnlyCustomLevels ? null : nums, + customNums + ); + const values = Object.assign( + Object.create(Object.prototype, { silent: { value: Infinity } }), + useOnlyCustomLevels ? null : DEFAULT_LEVELS, + customLevels + ); + return { labels, values }; + } + function assertDefaultLevelFound(defaultLevel, customLevels, useOnlyCustomLevels) { + if (typeof defaultLevel === "number") { + const values = [].concat( + Object.keys(customLevels || {}).map((key) => customLevels[key]), + useOnlyCustomLevels ? [] : Object.keys(nums).map((level) => +level), + Infinity + ); + if (!values.includes(defaultLevel)) { + throw Error(`default level:${defaultLevel} must be included in custom levels`); } - return results; - } - }; - module14.exports = DLList; - } -}); -var require_Events = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Events.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); return; } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + const labels = Object.assign( + Object.create(Object.prototype, { silent: { value: Infinity } }), + useOnlyCustomLevels ? null : DEFAULT_LEVELS, + customLevels + ); + if (!(defaultLevel in labels)) { + throw Error(`default level:${defaultLevel} must be included in custom levels`); } } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; - } - var Events2; - Events2 = class Events { - constructor(instance) { - this.instance = instance; - this._events = {}; - if (this.instance.on != null || this.instance.once != null || this.instance.removeAllListeners != null) { - throw new Error("An Emitter already exists for this object"); + function assertNoLevelCollisions(levels, customLevels) { + const { labels, values } = levels; + for (const k in customLevels) { + if (k in values) { + throw Error("levels cannot be overridden"); } - this.instance.on = (name, cb) => { - return this._addListener(name, "many", cb); - }; - this.instance.once = (name, cb) => { - return this._addListener(name, "once", cb); - }; - this.instance.removeAllListeners = (name = null) => { - if (name != null) { - return delete this._events[name]; - } else { - return this._events = {}; - } - }; - } - _addListener(name, status, cb) { - var base2; - if ((base2 = this._events)[name] == null) { - base2[name] = []; + if (customLevels[k] in labels) { + throw Error("pre-existing level values cannot be used for new levels"); } - this._events[name].push({ - cb, - status - }); - return this.instance; } - listenerCount(name) { - if (this._events[name] != null) { - return this._events[name].length; - } else { - return 0; - } + } + function assertLevelComparison(levelComparison) { + if (typeof levelComparison === "function") { + return; } - trigger(name, ...args) { - var _this = this; - return _asyncToGenerator2(function* () { - var e2, promises; - try { - if (name !== "debug") { - _this.trigger("debug", `Event triggered: ${name}`, args); - } - if (_this._events[name] == null) { - return; - } - _this._events[name] = _this._events[name].filter(function(listener) { - return listener.status !== "none"; - }); - promises = _this._events[name].map( - /* @__PURE__ */ function() { - var _ref = _asyncToGenerator2(function* (listener) { - var e3, returned; - if (listener.status === "none") { - return; - } - if (listener.status === "once") { - listener.status = "none"; - } - try { - returned = typeof listener.cb === "function" ? listener.cb(...args) : void 0; - if (typeof (returned != null ? returned.then : void 0) === "function") { - return yield returned; - } else { - return returned; - } - } catch (error2) { - e3 = error2; - if (true) { - _this.trigger("error", e3); - } - return null; - } - }); - return function(_x) { - return _ref.apply(this, arguments); - }; - }() - ); - return (yield Promise.all(promises)).find(function(x3) { - return x3 != null; - }); - } catch (error2) { - e2 = error2; - if (true) { - _this.trigger("error", e2); - } - return null; - } - })(); + if (typeof levelComparison === "string" && Object.values(SORTING_ORDER).includes(levelComparison)) { + return; } + throw new Error('Levels comparison should be one of "ASC", "DESC" or "function" type'); + } + module14.exports = { + initialLsCache, + genLsCache, + levelMethods, + getLevel, + setLevel, + isLevelEnabled, + mappings, + assertNoLevelCollisions, + assertDefaultLevelFound, + genLevelComparison, + assertLevelComparison }; - module14.exports = Events2; } }); -var require_Queues = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Queues.js"(exports2, module14) { +var require_meta = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/meta.js"(exports2, module14) { "use strict"; - var DLList; - var Events2; - var Queues; - DLList = require_DLList(); - Events2 = require_Events(); - Queues = class Queues { - constructor(num_priorities) { - var i2; - this.Events = new Events2(this); - this._length = 0; - this._lists = function() { - var j, ref, results; - results = []; - for (i2 = j = 1, ref = num_priorities; 1 <= ref ? j <= ref : j >= ref; i2 = 1 <= ref ? ++j : --j) { - results.push(new DLList(() => { - return this.incr(); - }, () => { - return this.decr(); - })); - } - return results; - }.call(this); + module14.exports = { version: "8.19.0" }; + } +}); +var require_proto = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports2, module14) { + "use strict"; + var { EventEmitter } = __require2("events"); + var { + lsCacheSym, + levelValSym, + setLevelSym, + getLevelSym, + chindingsSym, + parsedChindingsSym, + mixinSym, + asJsonSym, + writeSym, + mixinMergeStrategySym, + timeSym, + timeSliceIndexSym, + streamSym, + serializersSym, + formattersSym, + errorKeySym, + messageKeySym, + useOnlyCustomLevelsSym, + needsMetadataGsym, + redactFmtSym, + stringifySym, + formatOptsSym, + stringifiersSym, + msgPrefixSym + } = require_symbols(); + var { + getLevel, + setLevel, + isLevelEnabled, + mappings, + initialLsCache, + genLsCache, + assertNoLevelCollisions + } = require_levels(); + var { + asChindings, + asJson, + buildFormatters, + stringify: stringify2 + } = require_tools(); + var { + version: version3 + } = require_meta(); + var redaction = require_redaction(); + var constructor = class Pino { + }; + var prototype = { + constructor, + child, + bindings, + setBindings, + flush, + isLevelEnabled, + version: version3, + get level() { + return this[getLevelSym](); + }, + set level(lvl) { + this[setLevelSym](lvl); + }, + get levelVal() { + return this[levelValSym]; + }, + set levelVal(n) { + throw Error("levelVal is read-only"); + }, + [lsCacheSym]: initialLsCache, + [writeSym]: write, + [asJsonSym]: asJson, + [getLevelSym]: getLevel, + [setLevelSym]: setLevel + }; + Object.setPrototypeOf(prototype, EventEmitter.prototype); + module14.exports = function() { + return Object.create(prototype); + }; + var resetChildingsFormatter = (bindings2) => bindings2; + function child(bindings2, options2) { + if (!bindings2) { + throw Error("missing bindings for child Pino"); + } + options2 = options2 || {}; + const serializers = this[serializersSym]; + const formatters = this[formattersSym]; + const instance = Object.create(this); + if (options2.hasOwnProperty("serializers") === true) { + instance[serializersSym] = /* @__PURE__ */ Object.create(null); + for (const k in serializers) { + instance[serializersSym][k] = serializers[k]; + } + const parentSymbols = Object.getOwnPropertySymbols(serializers); + for (var i2 = 0; i2 < parentSymbols.length; i2++) { + const ks = parentSymbols[i2]; + instance[serializersSym][ks] = serializers[ks]; + } + for (const bk in options2.serializers) { + instance[serializersSym][bk] = options2.serializers[bk]; + } + const bindingsSymbols = Object.getOwnPropertySymbols(options2.serializers); + for (var bi = 0; bi < bindingsSymbols.length; bi++) { + const bks = bindingsSymbols[bi]; + instance[serializersSym][bks] = options2.serializers[bks]; + } + } else instance[serializersSym] = serializers; + if (options2.hasOwnProperty("formatters")) { + const { level, bindings: chindings, log: log2 } = options2.formatters; + instance[formattersSym] = buildFormatters( + level || formatters.level, + chindings || resetChildingsFormatter, + log2 || formatters.log + ); + } else { + instance[formattersSym] = buildFormatters( + formatters.level, + resetChildingsFormatter, + formatters.log + ); } - incr() { - if (this._length++ === 0) { - return this.Events.trigger("leftzero"); - } + if (options2.hasOwnProperty("customLevels") === true) { + assertNoLevelCollisions(this.levels, options2.customLevels); + instance.levels = mappings(options2.customLevels, instance[useOnlyCustomLevelsSym]); + genLsCache(instance); } - decr() { - if (--this._length === 0) { - return this.Events.trigger("zero"); - } + if (typeof options2.redact === "object" && options2.redact !== null || Array.isArray(options2.redact)) { + instance.redact = options2.redact; + const stringifiers = redaction(instance.redact, stringify2); + const formatOpts = { stringify: stringifiers[redactFmtSym] }; + instance[stringifySym] = stringify2; + instance[stringifiersSym] = stringifiers; + instance[formatOptsSym] = formatOpts; } - push(job) { - return this._lists[job.options.priority].push(job); + if (typeof options2.msgPrefix === "string") { + instance[msgPrefixSym] = (this[msgPrefixSym] || "") + options2.msgPrefix; } - queued(priority) { - if (priority != null) { - return this._lists[priority].length; - } else { - return this._length; + instance[chindingsSym] = asChindings(instance, bindings2); + const childLevel = options2.level || this.level; + instance[setLevelSym](childLevel); + this.onChild(instance); + return instance; + } + function bindings() { + const chindings = this[chindingsSym]; + const chindingsJson = `{${chindings.substr(1)}}`; + const bindingsFromJson = JSON.parse(chindingsJson); + delete bindingsFromJson.pid; + delete bindingsFromJson.hostname; + return bindingsFromJson; + } + function setBindings(newBindings) { + const chindings = asChindings(this, newBindings); + this[chindingsSym] = chindings; + delete this[parsedChindingsSym]; + } + function defaultMixinMergeStrategy(mergeObject, mixinObject) { + return Object.assign(mixinObject, mergeObject); + } + function write(_obj, msg, num) { + const t = this[timeSym](); + const mixin3 = this[mixinSym]; + const errorKey = this[errorKeySym]; + const messageKey = this[messageKeySym]; + const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy; + let obj; + if (_obj === void 0 || _obj === null) { + obj = {}; + } else if (_obj instanceof Error) { + obj = { [errorKey]: _obj }; + if (msg === void 0) { + msg = _obj.message; + } + } else { + obj = _obj; + if (msg === void 0 && _obj[messageKey] === void 0 && _obj[errorKey]) { + msg = _obj[errorKey].message; } } - shiftAll(fn) { - return this._lists.forEach(function(list) { - return list.forEachShift(fn); - }); + if (mixin3) { + obj = mixinMergeStrategy(obj, mixin3(obj, num, this)); } - getFirst(arr = this._lists) { - var j, len, list; - for (j = 0, len = arr.length; j < len; j++) { - list = arr[j]; - if (list.length > 0) { - return list; - } - } - return []; + const s = this[asJsonSym](obj, msg, num, t); + const stream = this[streamSym]; + if (stream[needsMetadataGsym] === true) { + stream.lastLevel = num; + stream.lastObj = obj; + stream.lastMsg = msg; + stream.lastTime = t.slice(this[timeSliceIndexSym]); + stream.lastLogger = this; } - shiftLastFrom(priority) { - return this.getFirst(this._lists.slice(priority).reverse()).shift(); + stream.write(s); + } + function noop() { + } + function flush(cb) { + if (cb != null && typeof cb !== "function") { + throw Error("callback must be a function"); } - }; - module14.exports = Queues; - } -}); -var require_BottleneckError = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/BottleneckError.js"(exports2, module14) { - "use strict"; - var BottleneckError; - BottleneckError = class BottleneckError extends Error { - }; - module14.exports = BottleneckError; + const stream = this[streamSym]; + if (typeof stream.flush === "function") { + stream.flush(cb || noop); + } else if (cb) cb(); + } } }); -var require_Job = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Job.js"(exports2, module14) { +var require_safe_stable_stringify = __commonJS({ + "node_modules/.deno/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports2, module14) { "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + var { hasOwnProperty } = Object.prototype; + var stringify2 = configure(); + stringify2.configure = configure; + stringify2.stringify = stringify2; + stringify2.default = stringify2; + exports2.stringify = stringify2; + exports2.configure = configure; + module14.exports = stringify2; + var strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/; + function strEscape(str) { + if (str.length < 5e3 && !strEscapeSequencesRegExp.test(str)) { + return `"${str}"`; } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + return JSON.stringify(str); + } + function sort(array2, comparator) { + if (array2.length > 200 || comparator) { + return array2.sort(comparator); + } + for (let i2 = 1; i2 < array2.length; i2++) { + const currentValue = array2[i2]; + let position = i2; + while (position !== 0 && array2[position - 1] > currentValue) { + array2[position] = array2[position - 1]; + position--; + } + array2[position] = currentValue; } + return array2; } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; + var typedArrayPrototypeGetSymbolToStringTag = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf( + Object.getPrototypeOf( + new Int8Array() + ) + ), + Symbol.toStringTag + ).get; + function isTypedArrayWithEntries(value) { + return typedArrayPrototypeGetSymbolToStringTag.call(value) !== void 0 && value.length !== 0; } - var BottleneckError; - var DEFAULT_PRIORITY; - var Job; - var NUM_PRIORITIES; - var parser3; - NUM_PRIORITIES = 10; - DEFAULT_PRIORITY = 5; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - Job = class Job { - constructor(task, args, options2, jobDefaults, rejectOnDrop, Events2, _states, Promise2) { - this.task = task; - this.args = args; - this.rejectOnDrop = rejectOnDrop; - this.Events = Events2; - this._states = _states; - this.Promise = Promise2; - this.options = parser3.load(options2, jobDefaults); - this.options.priority = this._sanitizePriority(this.options.priority); - if (this.options.id === jobDefaults.id) { - this.options.id = `${this.options.id}-${this._randomIndex()}`; - } - this.promise = new this.Promise((_resolve, _reject) => { - this._resolve = _resolve; - this._reject = _reject; - }); - this.retryCount = 0; + function stringifyTypedArray(array2, separator, maximumBreadth) { + if (array2.length < maximumBreadth) { + maximumBreadth = array2.length; } - _sanitizePriority(priority) { - var sProperty; - sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; - if (sProperty < 0) { - return 0; - } else if (sProperty > NUM_PRIORITIES - 1) { - return NUM_PRIORITIES - 1; - } else { - return sProperty; + const whitespace = separator === "," ? "" : " "; + let res = `"0":${whitespace}${array2[0]}`; + for (let i2 = 1; i2 < maximumBreadth; i2++) { + res += `${separator}"${i2}":${whitespace}${array2[i2]}`; + } + return res; + } + function getCircularValueOption(options2) { + if (hasOwnProperty.call(options2, "circularValue")) { + const circularValue = options2.circularValue; + if (typeof circularValue === "string") { + return `"${circularValue}"`; + } + if (circularValue == null) { + return circularValue; + } + if (circularValue === Error || circularValue === TypeError) { + return { + toString() { + throw new TypeError("Converting circular structure to JSON"); + } + }; } + throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined'); } - _randomIndex() { - return Math.random().toString(36).slice(2); + return '"[Circular]"'; + } + function getDeterministicOption(options2) { + let value; + if (hasOwnProperty.call(options2, "deterministic")) { + value = options2.deterministic; + if (typeof value !== "boolean" && typeof value !== "function") { + throw new TypeError('The "deterministic" argument must be of type boolean or comparator function'); + } } - doDrop({ - error: error2, - message = "This job has been dropped by Bottleneck" - } = {}) { - if (this._states.remove(this.options.id)) { - if (this.rejectOnDrop) { - this._reject(error2 != null ? error2 : new BottleneckError(message)); - } - this.Events.trigger("dropped", { - args: this.args, - options: this.options, - task: this.task, - promise: this.promise - }); - return true; - } else { - return false; + return value === void 0 ? true : value; + } + function getBooleanOption(options2, key) { + let value; + if (hasOwnProperty.call(options2, key)) { + value = options2[key]; + if (typeof value !== "boolean") { + throw new TypeError(`The "${key}" argument must be of type boolean`); } } - _assertStatus(expected) { - var status; - status = this._states.jobStatus(this.options.id); - if (!(status === expected || expected === "DONE" && status === null)) { - throw new BottleneckError(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`); + return value === void 0 ? true : value; + } + function getPositiveIntegerOption(options2, key) { + let value; + if (hasOwnProperty.call(options2, key)) { + value = options2[key]; + if (typeof value !== "number") { + throw new TypeError(`The "${key}" argument must be of type number`); + } + if (!Number.isInteger(value)) { + throw new TypeError(`The "${key}" argument must be an integer`); + } + if (value < 1) { + throw new RangeError(`The "${key}" argument must be >= 1`); } } - doReceive() { - this._states.start(this.options.id); - return this.Events.trigger("received", { - args: this.args, - options: this.options - }); + return value === void 0 ? Infinity : value; + } + function getItemCount(number3) { + if (number3 === 1) { + return "1 item"; } - doQueue(reachedHWM, blocked) { - this._assertStatus("RECEIVED"); - this._states.next(this.options.id); - return this.Events.trigger("queued", { - args: this.args, - options: this.options, - reachedHWM, - blocked - }); + return `${number3} items`; + } + function getUniqueReplacerSet(replacerArray) { + const replacerSet = /* @__PURE__ */ new Set(); + for (const value of replacerArray) { + if (typeof value === "string" || typeof value === "number") { + replacerSet.add(String(value)); + } } - doRun() { - if (this.retryCount === 0) { - this._assertStatus("QUEUED"); - this._states.next(this.options.id); - } else { - this._assertStatus("EXECUTING"); + return replacerSet; + } + function getStrictOption(options2) { + if (hasOwnProperty.call(options2, "strict")) { + const value = options2.strict; + if (typeof value !== "boolean") { + throw new TypeError('The "strict" argument must be of type boolean'); + } + if (value) { + return (value2) => { + let message = `Object can not safely be stringified. Received type ${typeof value2}`; + if (typeof value2 !== "function") message += ` (${value2.toString()})`; + throw new Error(message); + }; } - return this.Events.trigger("scheduled", { - args: this.args, - options: this.options - }); } - doExecute(chained, clearGlobalState, run2, free) { - var _this = this; - return _asyncToGenerator2(function* () { - var error2, eventInfo, passed; - if (_this.retryCount === 0) { - _this._assertStatus("RUNNING"); - _this._states.next(_this.options.id); - } else { - _this._assertStatus("EXECUTING"); + } + function configure(options2) { + options2 = { ...options2 }; + const fail = getStrictOption(options2); + if (fail) { + if (options2.bigint === void 0) { + options2.bigint = false; + } + if (!("circularValue" in options2)) { + options2.circularValue = Error; + } + } + const circularValue = getCircularValueOption(options2); + const bigint2 = getBooleanOption(options2, "bigint"); + const deterministic = getDeterministicOption(options2); + const comparator = typeof deterministic === "function" ? deterministic : void 0; + const maximumDepth = getPositiveIntegerOption(options2, "maximumDepth"); + const maximumBreadth = getPositiveIntegerOption(options2, "maximumBreadth"); + function stringifyFnReplacer(key, parent, stack, replacer, spacer, indentation) { + let value = parent[key]; + if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { + value = value.toJSON(key); + } + value = replacer.call(parent, key, value); + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; + } + if (stack.indexOf(value) !== -1) { + return circularValue; + } + let res = ""; + let join10 = ","; + const originalIndentation = indentation; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + if (spacer !== "") { + indentation += spacer; + res += ` +${indentation}`; + join10 = `, +${indentation}`; + } + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += join10; + } + const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; + } + if (spacer !== "") { + res += ` +${originalIndentation}`; + } + stack.pop(); + return `[${res}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + let whitespace = ""; + let separator = ""; + if (spacer !== "") { + indentation += spacer; + join10 = `, +${indentation}`; + whitespace = " "; + } + const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (deterministic && !isTypedArrayWithEntries(value)) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; + separator = join10; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`; + separator = join10; + } + if (spacer !== "" && separator.length > 1) { + res = ` +${indentation}${res} +${originalIndentation}`; + } + stack.pop(); + return `{${res}}`; } - eventInfo = { - args: _this.args, - options: _this.options, - retryCount: _this.retryCount - }; - _this.Events.trigger("executing", eventInfo); - try { - passed = yield chained != null ? chained.schedule(_this.options, _this.task, ..._this.args) : _this.task(..._this.args); - if (clearGlobalState()) { - _this.doDone(eventInfo); - yield free(_this.options, eventInfo); - _this._assertStatus("DONE"); - return _this._resolve(passed); + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; + } + } + function stringifyArrayReplacer(key, value, stack, replacer, spacer, indentation) { + if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { + value = value.toJSON(key); + } + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; } - } catch (error1) { - error2 = error1; - return _this._onFailure(error2, eventInfo, clearGlobalState, run2, free); + if (stack.indexOf(value) !== -1) { + return circularValue; + } + const originalIndentation = indentation; + let res = ""; + let join10 = ","; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + if (spacer !== "") { + indentation += spacer; + res += ` +${indentation}`; + join10 = `, +${indentation}`; + } + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += join10; + } + const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; + } + if (spacer !== "") { + res += ` +${originalIndentation}`; + } + stack.pop(); + return `[${res}]`; + } + stack.push(value); + let whitespace = ""; + if (spacer !== "") { + indentation += spacer; + join10 = `, +${indentation}`; + whitespace = " "; + } + let separator = ""; + for (const key2 of replacer) { + const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; + separator = join10; + } + } + if (spacer !== "" && separator.length > 1) { + res = ` +${indentation}${res} +${originalIndentation}`; + } + stack.pop(); + return `{${res}}`; } - })(); - } - doExpire(clearGlobalState, run2, free) { - var error2, eventInfo; - if (this._states.jobStatus(this.options.id === "RUNNING")) { - this._states.next(this.options.id); + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; } - this._assertStatus("EXECUTING"); - eventInfo = { - args: this.args, - options: this.options, - retryCount: this.retryCount - }; - error2 = new BottleneckError(`This job timed out after ${this.options.expiration} ms.`); - return this._onFailure(error2, eventInfo, clearGlobalState, run2, free); } - _onFailure(error2, eventInfo, clearGlobalState, run2, free) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var retry, retryAfter; - if (clearGlobalState()) { - retry = yield _this2.Events.trigger("failed", error2, eventInfo); - if (retry != null) { - retryAfter = ~~retry; - _this2.Events.trigger("retry", `Retrying ${_this2.options.id} after ${retryAfter} ms`, eventInfo); - _this2.retryCount++; - return run2(retryAfter); - } else { - _this2.doDone(eventInfo); - yield free(_this2.options, eventInfo); - _this2._assertStatus("DONE"); - return _this2._reject(error2); + function stringifyIndent(key, value, stack, spacer, indentation) { + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; } + if (typeof value.toJSON === "function") { + value = value.toJSON(key); + if (typeof value !== "object") { + return stringifyIndent(key, value, stack, spacer, indentation); + } + if (value === null) { + return "null"; + } + } + if (stack.indexOf(value) !== -1) { + return circularValue; + } + const originalIndentation = indentation; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + indentation += spacer; + let res2 = ` +${indentation}`; + const join11 = `, +${indentation}`; + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); + res2 += tmp2 !== void 0 ? tmp2 : "null"; + res2 += join11; + } + const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); + res2 += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res2 += `${join11}"... ${getItemCount(removedKeys)} not stringified"`; + } + res2 += ` +${originalIndentation}`; + stack.pop(); + return `[${res2}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + indentation += spacer; + const join10 = `, +${indentation}`; + let res = ""; + let separator = ""; + let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (isTypedArrayWithEntries(value)) { + res += stringifyTypedArray(value, join10, maximumBreadth); + keys = keys.slice(value.length); + maximumPropertiesToStringify -= value.length; + separator = join10; + } + if (deterministic) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}: ${tmp}`; + separator = join10; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`; + separator = join10; + } + if (separator !== "") { + res = ` +${indentation}${res} +${originalIndentation}`; + } + stack.pop(); + return `{${res}}`; } - })(); - } - doDone(eventInfo) { - this._assertStatus("EXECUTING"); - this._states.next(this.options.id); - return this.Events.trigger("done", eventInfo); - } - }; - module14.exports = Job; - } -}); -var require_LocalDatastore = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/LocalDatastore.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; - } - var BottleneckError; - var LocalDatastore; - var parser3; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - LocalDatastore = class LocalDatastore { - constructor(instance, storeOptions, storeInstanceOptions) { - this.instance = instance; - this.storeOptions = storeOptions; - this.clientId = this.instance._randomIndex(); - parser3.load(storeInstanceOptions, storeInstanceOptions, this); - this._nextRequest = this._lastReservoirRefresh = this._lastReservoirIncrease = Date.now(); - this._running = 0; - this._done = 0; - this._unblockTime = 0; - this.ready = this.Promise.resolve(); - this.clients = {}; - this._startHeartbeat(); + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; + } } - _startHeartbeat() { - var base2; - if (this.heartbeat == null && (this.storeOptions.reservoirRefreshInterval != null && this.storeOptions.reservoirRefreshAmount != null || this.storeOptions.reservoirIncreaseInterval != null && this.storeOptions.reservoirIncreaseAmount != null)) { - return typeof (base2 = this.heartbeat = setInterval(() => { - var amount, incr, maximum, now, reservoir; - now = Date.now(); - if (this.storeOptions.reservoirRefreshInterval != null && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { - this._lastReservoirRefresh = now; - this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; - this.instance._drainAll(this.computeCapacity()); + function stringifySimple(key, value, stack) { + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; } - if (this.storeOptions.reservoirIncreaseInterval != null && now >= this._lastReservoirIncrease + this.storeOptions.reservoirIncreaseInterval) { - var _this$storeOptions = this.storeOptions; - amount = _this$storeOptions.reservoirIncreaseAmount; - maximum = _this$storeOptions.reservoirIncreaseMaximum; - reservoir = _this$storeOptions.reservoir; - this._lastReservoirIncrease = now; - incr = maximum != null ? Math.min(amount, maximum - reservoir) : amount; - if (incr > 0) { - this.storeOptions.reservoir += incr; - return this.instance._drainAll(this.computeCapacity()); + if (typeof value.toJSON === "function") { + value = value.toJSON(key); + if (typeof value !== "object") { + return stringifySimple(key, value, stack); + } + if (value === null) { + return "null"; } } - }, this.heartbeatInterval)).unref === "function" ? base2.unref() : void 0; - } else { - return clearInterval(this.heartbeat); + if (stack.indexOf(value) !== -1) { + return circularValue; + } + let res = ""; + const hasLength = value.length !== void 0; + if (hasLength && Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifySimple(String(i2), value[i2], stack); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += ","; + } + const tmp = stringifySimple(String(i2), value[i2], stack); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `,"... ${getItemCount(removedKeys)} not stringified"`; + } + stack.pop(); + return `[${res}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + let separator = ""; + let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (hasLength && isTypedArrayWithEntries(value)) { + res += stringifyTypedArray(value, ",", maximumBreadth); + keys = keys.slice(value.length); + maximumPropertiesToStringify -= value.length; + separator = ","; + } + if (deterministic) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifySimple(key2, value[key2], stack); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${tmp}`; + separator = ","; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`; + } + stack.pop(); + return `{${res}}`; + } + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; } } - __publish__(message) { - var _this = this; - return _asyncToGenerator2(function* () { - yield _this.yieldLoop(); - return _this.instance.Events.trigger("message", message.toString()); - })(); - } - __disconnect__(flush) { - var _this2 = this; - return _asyncToGenerator2(function* () { - yield _this2.yieldLoop(); - clearInterval(_this2.heartbeat); - return _this2.Promise.resolve(); - })(); - } - yieldLoop(t = 0) { - return new this.Promise(function(resolve82, reject) { - return setTimeout(resolve82, t); - }); - } - computePenalty() { - var ref; - return (ref = this.storeOptions.penalty) != null ? ref : 15 * this.storeOptions.minTime || 5e3; - } - __updateSettings__(options2) { - var _this3 = this; - return _asyncToGenerator2(function* () { - yield _this3.yieldLoop(); - parser3.overwrite(options2, options2, _this3.storeOptions); - _this3._startHeartbeat(); - _this3.instance._drainAll(_this3.computeCapacity()); - return true; - })(); - } - __running__() { - var _this4 = this; - return _asyncToGenerator2(function* () { - yield _this4.yieldLoop(); - return _this4._running; - })(); - } - __queued__() { - var _this5 = this; - return _asyncToGenerator2(function* () { - yield _this5.yieldLoop(); - return _this5.instance.queued(); - })(); - } - __done__() { - var _this6 = this; - return _asyncToGenerator2(function* () { - yield _this6.yieldLoop(); - return _this6._done; - })(); - } - __groupCheck__(time3) { - var _this7 = this; - return _asyncToGenerator2(function* () { - yield _this7.yieldLoop(); - return _this7._nextRequest + _this7.timeout < time3; - })(); - } - computeCapacity() { - var maxConcurrent, reservoir; - var _this$storeOptions2 = this.storeOptions; - maxConcurrent = _this$storeOptions2.maxConcurrent; - reservoir = _this$storeOptions2.reservoir; - if (maxConcurrent != null && reservoir != null) { - return Math.min(maxConcurrent - this._running, reservoir); - } else if (maxConcurrent != null) { - return maxConcurrent - this._running; - } else if (reservoir != null) { - return reservoir; - } else { - return null; + function stringify3(value, replacer, space) { + if (arguments.length > 1) { + let spacer = ""; + if (typeof space === "number") { + spacer = " ".repeat(Math.min(space, 10)); + } else if (typeof space === "string") { + spacer = space.slice(0, 10); + } + if (replacer != null) { + if (typeof replacer === "function") { + return stringifyFnReplacer("", { "": value }, [], replacer, spacer, ""); + } + if (Array.isArray(replacer)) { + return stringifyArrayReplacer("", value, [], getUniqueReplacerSet(replacer), spacer, ""); + } + } + if (spacer.length !== 0) { + return stringifyIndent("", value, [], spacer, ""); + } } + return stringifySimple("", value, []); } - conditionsCheck(weight) { - var capacity; - capacity = this.computeCapacity(); - return capacity == null || weight <= capacity; - } - __incrementReservoir__(incr) { - var _this8 = this; - return _asyncToGenerator2(function* () { - var reservoir; - yield _this8.yieldLoop(); - reservoir = _this8.storeOptions.reservoir += incr; - _this8.instance._drainAll(_this8.computeCapacity()); - return reservoir; - })(); - } - __currentReservoir__() { - var _this9 = this; - return _asyncToGenerator2(function* () { - yield _this9.yieldLoop(); - return _this9.storeOptions.reservoir; - })(); - } - isBlocked(now) { - return this._unblockTime >= now; - } - check(weight, now) { - return this.conditionsCheck(weight) && this._nextRequest - now <= 0; + return stringify3; + } + } +}); +var require_multistream = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/multistream.js"(exports2, module14) { + "use strict"; + var metadata = Symbol.for("pino.metadata"); + var { DEFAULT_LEVELS } = require_constants(); + var DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info; + function multistream(streamsArray, opts) { + let counter = 0; + streamsArray = streamsArray || []; + opts = opts || { dedupe: false }; + const streamLevels = Object.create(DEFAULT_LEVELS); + streamLevels.silent = Infinity; + if (opts.levels && typeof opts.levels === "object") { + Object.keys(opts.levels).forEach((i2) => { + streamLevels[i2] = opts.levels[i2]; + }); } - __check__(weight) { - var _this10 = this; - return _asyncToGenerator2(function* () { - var now; - yield _this10.yieldLoop(); - now = Date.now(); - return _this10.check(weight, now); - })(); + const res = { + write, + add, + flushSync, + end, + minLevel: 0, + streams: [], + clone: clone2, + [metadata]: true, + streamLevels + }; + if (Array.isArray(streamsArray)) { + streamsArray.forEach(add, res); + } else { + add.call(res, streamsArray); } - __register__(index, weight, expiration) { - var _this11 = this; - return _asyncToGenerator2(function* () { - var now, wait; - yield _this11.yieldLoop(); - now = Date.now(); - if (_this11.conditionsCheck(weight)) { - _this11._running += weight; - if (_this11.storeOptions.reservoir != null) { - _this11.storeOptions.reservoir -= weight; + streamsArray = null; + return res; + function write(data) { + let dest; + const level = this.lastLevel; + const { streams } = this; + let recordedLevel = 0; + let stream; + for (let i2 = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i2, streams.length, opts.dedupe); i2 = adjustLoopVar(i2, opts.dedupe)) { + dest = streams[i2]; + if (dest.level <= level) { + if (recordedLevel !== 0 && recordedLevel !== dest.level) { + break; } - wait = Math.max(_this11._nextRequest - now, 0); - _this11._nextRequest = now + wait + _this11.storeOptions.minTime; - return { - success: true, - wait, - reservoir: _this11.storeOptions.reservoir - }; - } else { - return { - success: false - }; + stream = dest.stream; + if (stream[metadata]) { + const { lastTime, lastMsg, lastObj, lastLogger } = this; + stream.lastLevel = level; + stream.lastTime = lastTime; + stream.lastMsg = lastMsg; + stream.lastObj = lastObj; + stream.lastLogger = lastLogger; + } + stream.write(data); + if (opts.dedupe) { + recordedLevel = dest.level; + } + } else if (!opts.dedupe) { + break; } - })(); - } - strategyIsBlock() { - return this.storeOptions.strategy === 3; + } } - __submit__(queueLength, weight) { - var _this12 = this; - return _asyncToGenerator2(function* () { - var blocked, now, reachedHWM; - yield _this12.yieldLoop(); - if (_this12.storeOptions.maxConcurrent != null && weight > _this12.storeOptions.maxConcurrent) { - throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${_this12.storeOptions.maxConcurrent}`); + function flushSync() { + for (const { stream } of this.streams) { + if (typeof stream.flushSync === "function") { + stream.flushSync(); } - now = Date.now(); - reachedHWM = _this12.storeOptions.highWater != null && queueLength === _this12.storeOptions.highWater && !_this12.check(weight, now); - blocked = _this12.strategyIsBlock() && (reachedHWM || _this12.isBlocked(now)); - if (blocked) { - _this12._unblockTime = now + _this12.computePenalty(); - _this12._nextRequest = _this12._unblockTime + _this12.storeOptions.minTime; - _this12.instance._dropAllQueued(); + } + } + function add(dest) { + if (!dest) { + return res; + } + const isStream = typeof dest.write === "function" || dest.stream; + const stream_ = dest.write ? dest : dest.stream; + if (!isStream) { + throw Error("stream object needs to implement either StreamEntry or DestinationStream interface"); + } + const { streams, streamLevels: streamLevels2 } = this; + let level; + if (typeof dest.levelVal === "number") { + level = dest.levelVal; + } else if (typeof dest.level === "string") { + level = streamLevels2[dest.level]; + } else if (typeof dest.level === "number") { + level = dest.level; + } else { + level = DEFAULT_INFO_LEVEL; + } + const dest_ = { + stream: stream_, + level, + levelVal: void 0, + id: counter++ + }; + streams.unshift(dest_); + streams.sort(compareByLevel); + this.minLevel = streams[0].level; + return res; + } + function end() { + for (const { stream } of this.streams) { + if (typeof stream.flushSync === "function") { + stream.flushSync(); } - return { - reachedHWM, - blocked, - strategy: _this12.storeOptions.strategy - }; - })(); + stream.end(); + } } - __free__(index, weight) { - var _this13 = this; - return _asyncToGenerator2(function* () { - yield _this13.yieldLoop(); - _this13._running -= weight; - _this13._done += weight; - _this13.instance._drainAll(_this13.computeCapacity()); - return { - running: _this13._running + function clone2(level) { + const streams = new Array(this.streams.length); + for (let i2 = 0; i2 < streams.length; i2++) { + streams[i2] = { + level, + stream: this.streams[i2].stream }; - })(); + } + return { + write, + add, + minLevel: level, + streams, + clone: clone2, + flushSync, + [metadata]: true + }; } - }; - module14.exports = LocalDatastore; + } + function compareByLevel(a, b) { + return a.level - b.level; + } + function initLoopVar(length2, dedupe) { + return dedupe ? length2 - 1 : 0; + } + function adjustLoopVar(i2, dedupe) { + return dedupe ? i2 - 1 : i2 + 1; + } + function checkLoopVar(i2, length2, dedupe) { + return dedupe ? i2 >= 0 : i2 < length2; + } + module14.exports = multistream; } }); -var require_lua = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/lua.json"(exports2, module14) { - module14.exports = { - "blacklist_client.lua": "local blacklist = ARGV[num_static_argv + 1]\n\nif redis.call('zscore', client_last_seen_key, blacklist) then\n redis.call('zadd', client_last_seen_key, 0, blacklist)\nend\n\n\nreturn {}\n", - "check.lua": "local weight = tonumber(ARGV[num_static_argv + 1])\n\nlocal capacity = process_tick(now, false)['capacity']\nlocal nextRequest = tonumber(redis.call('hget', settings_key, 'nextRequest'))\n\nreturn conditions_check(capacity, weight) and nextRequest - now <= 0\n", - "conditions_check.lua": "local conditions_check = function (capacity, weight)\n return capacity == nil or weight <= capacity\nend\n", - "current_reservoir.lua": "return process_tick(now, false)['reservoir']\n", - "done.lua": "process_tick(now, false)\n\nreturn tonumber(redis.call('hget', settings_key, 'done'))\n", - "free.lua": "local index = ARGV[num_static_argv + 1]\n\nredis.call('zadd', job_expirations_key, 0, index)\n\nreturn process_tick(now, false)['running']\n", - "get_time.lua": "redis.replicate_commands()\n\nlocal get_time = function ()\n local time = redis.call('time')\n\n return tonumber(time[1]..string.sub(time[2], 1, 3))\nend\n", - "group_check.lua": "return not (redis.call('exists', settings_key) == 1)\n", - "heartbeat.lua": "process_tick(now, true)\n", - "increment_reservoir.lua": "local incr = tonumber(ARGV[num_static_argv + 1])\n\nredis.call('hincrby', settings_key, 'reservoir', incr)\n\nlocal reservoir = process_tick(now, true)['reservoir']\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn reservoir\n", - "init.lua": `local clear = tonumber(ARGV[num_static_argv + 1]) -local limiter_version = ARGV[num_static_argv + 2] -local num_local_argv = num_static_argv + 2 - -if clear == 1 then - redis.call('del', unpack(KEYS)) -end - -if redis.call('exists', settings_key) == 0 then - -- Create - local args = {'hmset', settings_key} - - for i = num_local_argv + 1, #ARGV do - table.insert(args, ARGV[i]) - end - - redis.call(unpack(args)) - redis.call('hmset', settings_key, - 'nextRequest', now, - 'lastReservoirRefresh', now, - 'lastReservoirIncrease', now, - 'running', 0, - 'done', 0, - 'unblockTime', 0, - 'capacityPriorityCounter', 0 - ) - -else - -- Apply migrations - local settings = redis.call('hmget', settings_key, - 'id', - 'version' - ) - local id = settings[1] - local current_version = settings[2] - - if current_version ~= limiter_version then - local version_digits = {} - for k, v in string.gmatch(current_version, "([^.]+)") do - table.insert(version_digits, tonumber(k)) - end - - -- 2.10.0 - if version_digits[2] < 10 then - redis.call('hsetnx', settings_key, 'reservoirRefreshInterval', '') - redis.call('hsetnx', settings_key, 'reservoirRefreshAmount', '') - redis.call('hsetnx', settings_key, 'lastReservoirRefresh', '') - redis.call('hsetnx', settings_key, 'done', 0) - redis.call('hset', settings_key, 'version', '2.10.0') - end - - -- 2.11.1 - if version_digits[2] < 11 or (version_digits[2] == 11 and version_digits[3] < 1) then - if redis.call('hstrlen', settings_key, 'lastReservoirRefresh') == 0 then - redis.call('hmset', settings_key, - 'lastReservoirRefresh', now, - 'version', '2.11.1' - ) - end - end - - -- 2.14.0 - if version_digits[2] < 14 then - local old_running_key = 'b_'..id..'_running' - local old_executing_key = 'b_'..id..'_executing' - - if redis.call('exists', old_running_key) == 1 then - redis.call('rename', old_running_key, job_weights_key) - end - if redis.call('exists', old_executing_key) == 1 then - redis.call('rename', old_executing_key, job_expirations_key) - end - redis.call('hset', settings_key, 'version', '2.14.0') - end - - -- 2.15.2 - if version_digits[2] < 15 or (version_digits[2] == 15 and version_digits[3] < 2) then - redis.call('hsetnx', settings_key, 'capacityPriorityCounter', 0) - redis.call('hset', settings_key, 'version', '2.15.2') - end - - -- 2.17.0 - if version_digits[2] < 17 then - redis.call('hsetnx', settings_key, 'clientTimeout', 10000) - redis.call('hset', settings_key, 'version', '2.17.0') - end - - -- 2.18.0 - if version_digits[2] < 18 then - redis.call('hsetnx', settings_key, 'reservoirIncreaseInterval', '') - redis.call('hsetnx', settings_key, 'reservoirIncreaseAmount', '') - redis.call('hsetnx', settings_key, 'reservoirIncreaseMaximum', '') - redis.call('hsetnx', settings_key, 'lastReservoirIncrease', now) - redis.call('hset', settings_key, 'version', '2.18.0') - end - - end - - process_tick(now, false) -end - -local groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout')) -refresh_expiration(0, 0, groupTimeout) - -return {} -`, - "process_tick.lua": "local process_tick = function (now, always_publish)\n\n local compute_capacity = function (maxConcurrent, running, reservoir)\n if maxConcurrent ~= nil and reservoir ~= nil then\n return math.min((maxConcurrent - running), reservoir)\n elseif maxConcurrent ~= nil then\n return maxConcurrent - running\n elseif reservoir ~= nil then\n return reservoir\n else\n return nil\n end\n end\n\n local settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'running',\n 'reservoir',\n 'reservoirRefreshInterval',\n 'reservoirRefreshAmount',\n 'lastReservoirRefresh',\n 'reservoirIncreaseInterval',\n 'reservoirIncreaseAmount',\n 'reservoirIncreaseMaximum',\n 'lastReservoirIncrease',\n 'capacityPriorityCounter',\n 'clientTimeout'\n )\n local id = settings[1]\n local maxConcurrent = tonumber(settings[2])\n local running = tonumber(settings[3])\n local reservoir = tonumber(settings[4])\n local reservoirRefreshInterval = tonumber(settings[5])\n local reservoirRefreshAmount = tonumber(settings[6])\n local lastReservoirRefresh = tonumber(settings[7])\n local reservoirIncreaseInterval = tonumber(settings[8])\n local reservoirIncreaseAmount = tonumber(settings[9])\n local reservoirIncreaseMaximum = tonumber(settings[10])\n local lastReservoirIncrease = tonumber(settings[11])\n local capacityPriorityCounter = tonumber(settings[12])\n local clientTimeout = tonumber(settings[13])\n\n local initial_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n --\n -- Process 'running' changes\n --\n local expired = redis.call('zrangebyscore', job_expirations_key, '-inf', '('..now)\n\n if #expired > 0 then\n redis.call('zremrangebyscore', job_expirations_key, '-inf', '('..now)\n\n local flush_batch = function (batch, acc)\n local weights = redis.call('hmget', job_weights_key, unpack(batch))\n redis.call('hdel', job_weights_key, unpack(batch))\n local clients = redis.call('hmget', job_clients_key, unpack(batch))\n redis.call('hdel', job_clients_key, unpack(batch))\n\n -- Calculate sum of removed weights\n for i = 1, #weights do\n acc['total'] = acc['total'] + (tonumber(weights[i]) or 0)\n end\n\n -- Calculate sum of removed weights by client\n local client_weights = {}\n for i = 1, #clients do\n local removed = tonumber(weights[i]) or 0\n if removed > 0 then\n acc['client_weights'][clients[i]] = (acc['client_weights'][clients[i]] or 0) + removed\n end\n end\n end\n\n local acc = {\n ['total'] = 0,\n ['client_weights'] = {}\n }\n local batch_size = 1000\n\n -- Compute changes to Zsets and apply changes to Hashes\n for i = 1, #expired, batch_size do\n local batch = {}\n for j = i, math.min(i + batch_size - 1, #expired) do\n table.insert(batch, expired[j])\n end\n\n flush_batch(batch, acc)\n end\n\n -- Apply changes to Zsets\n if acc['total'] > 0 then\n redis.call('hincrby', settings_key, 'done', acc['total'])\n running = tonumber(redis.call('hincrby', settings_key, 'running', -acc['total']))\n end\n\n for client, weight in pairs(acc['client_weights']) do\n redis.call('zincrby', client_running_key, -weight, client)\n end\n end\n\n --\n -- Process 'reservoir' changes\n --\n local reservoirRefreshActive = reservoirRefreshInterval ~= nil and reservoirRefreshAmount ~= nil\n if reservoirRefreshActive and now >= lastReservoirRefresh + reservoirRefreshInterval then\n reservoir = reservoirRefreshAmount\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirRefresh', now\n )\n end\n\n local reservoirIncreaseActive = reservoirIncreaseInterval ~= nil and reservoirIncreaseAmount ~= nil\n if reservoirIncreaseActive and now >= lastReservoirIncrease + reservoirIncreaseInterval then\n local num_intervals = math.floor((now - lastReservoirIncrease) / reservoirIncreaseInterval)\n local incr = reservoirIncreaseAmount * num_intervals\n if reservoirIncreaseMaximum ~= nil then\n incr = math.min(incr, reservoirIncreaseMaximum - (reservoir or 0))\n end\n if incr > 0 then\n reservoir = (reservoir or 0) + incr\n end\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirIncrease', lastReservoirIncrease + (num_intervals * reservoirIncreaseInterval)\n )\n end\n\n --\n -- Clear unresponsive clients\n --\n local unresponsive = redis.call('zrangebyscore', client_last_seen_key, '-inf', (now - clientTimeout))\n local unresponsive_lookup = {}\n local terminated_clients = {}\n for i = 1, #unresponsive do\n unresponsive_lookup[unresponsive[i]] = true\n if tonumber(redis.call('zscore', client_running_key, unresponsive[i])) == 0 then\n table.insert(terminated_clients, unresponsive[i])\n end\n end\n if #terminated_clients > 0 then\n redis.call('zrem', client_running_key, unpack(terminated_clients))\n redis.call('hdel', client_num_queued_key, unpack(terminated_clients))\n redis.call('zrem', client_last_registered_key, unpack(terminated_clients))\n redis.call('zrem', client_last_seen_key, unpack(terminated_clients))\n end\n\n --\n -- Broadcast capacity changes\n --\n local final_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n if always_publish or (initial_capacity ~= nil and final_capacity == nil) then\n -- always_publish or was not unlimited, now unlimited\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n\n elseif initial_capacity ~= nil and final_capacity ~= nil and final_capacity > initial_capacity then\n -- capacity was increased\n -- send the capacity message to the limiter having the lowest number of running jobs\n -- the tiebreaker is the limiter having not registered a job in the longest time\n\n local lowest_concurrency_value = nil\n local lowest_concurrency_clients = {}\n local lowest_concurrency_last_registered = {}\n local client_concurrencies = redis.call('zrange', client_running_key, 0, -1, 'withscores')\n\n for i = 1, #client_concurrencies, 2 do\n local client = client_concurrencies[i]\n local concurrency = tonumber(client_concurrencies[i+1])\n\n if (\n lowest_concurrency_value == nil or lowest_concurrency_value == concurrency\n ) and (\n not unresponsive_lookup[client]\n ) and (\n tonumber(redis.call('hget', client_num_queued_key, client)) > 0\n ) then\n lowest_concurrency_value = concurrency\n table.insert(lowest_concurrency_clients, client)\n local last_registered = tonumber(redis.call('zscore', client_last_registered_key, client))\n table.insert(lowest_concurrency_last_registered, last_registered)\n end\n end\n\n if #lowest_concurrency_clients > 0 then\n local position = 1\n local earliest = lowest_concurrency_last_registered[1]\n\n for i,v in ipairs(lowest_concurrency_last_registered) do\n if v < earliest then\n position = i\n earliest = v\n end\n end\n\n local next_client = lowest_concurrency_clients[position]\n redis.call('publish', 'b_'..id,\n 'capacity-priority:'..(final_capacity or '')..\n ':'..next_client..\n ':'..capacityPriorityCounter\n )\n redis.call('hincrby', settings_key, 'capacityPriorityCounter', '1')\n else\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n end\n end\n\n return {\n ['capacity'] = final_capacity,\n ['running'] = running,\n ['reservoir'] = reservoir\n }\nend\n", - "queued.lua": "local clientTimeout = tonumber(redis.call('hget', settings_key, 'clientTimeout'))\nlocal valid_clients = redis.call('zrangebyscore', client_last_seen_key, (now - clientTimeout), 'inf')\nlocal client_queued = redis.call('hmget', client_num_queued_key, unpack(valid_clients))\n\nlocal sum = 0\nfor i = 1, #client_queued do\n sum = sum + tonumber(client_queued[i])\nend\n\nreturn sum\n", - "refresh_expiration.lua": "local refresh_expiration = function (now, nextRequest, groupTimeout)\n\n if groupTimeout ~= nil then\n local ttl = (nextRequest + groupTimeout) - now\n\n for i = 1, #KEYS do\n redis.call('pexpire', KEYS[i], ttl)\n end\n end\n\nend\n", - "refs.lua": "local settings_key = KEYS[1]\nlocal job_weights_key = KEYS[2]\nlocal job_expirations_key = KEYS[3]\nlocal job_clients_key = KEYS[4]\nlocal client_running_key = KEYS[5]\nlocal client_num_queued_key = KEYS[6]\nlocal client_last_registered_key = KEYS[7]\nlocal client_last_seen_key = KEYS[8]\n\nlocal now = tonumber(ARGV[1])\nlocal client = ARGV[2]\n\nlocal num_static_argv = 2\n", - "register.lua": "local index = ARGV[num_static_argv + 1]\nlocal weight = tonumber(ARGV[num_static_argv + 2])\nlocal expiration = tonumber(ARGV[num_static_argv + 3])\n\nlocal state = process_tick(now, false)\nlocal capacity = state['capacity']\nlocal reservoir = state['reservoir']\n\nlocal settings = redis.call('hmget', settings_key,\n 'nextRequest',\n 'minTime',\n 'groupTimeout'\n)\nlocal nextRequest = tonumber(settings[1])\nlocal minTime = tonumber(settings[2])\nlocal groupTimeout = tonumber(settings[3])\n\nif conditions_check(capacity, weight) then\n\n redis.call('hincrby', settings_key, 'running', weight)\n redis.call('hset', job_weights_key, index, weight)\n if expiration ~= nil then\n redis.call('zadd', job_expirations_key, now + expiration, index)\n end\n redis.call('hset', job_clients_key, index, client)\n redis.call('zincrby', client_running_key, weight, client)\n redis.call('hincrby', client_num_queued_key, client, -1)\n redis.call('zadd', client_last_registered_key, now, client)\n\n local wait = math.max(nextRequest - now, 0)\n local newNextRequest = now + wait + minTime\n\n if reservoir == nil then\n redis.call('hset', settings_key,\n 'nextRequest', newNextRequest\n )\n else\n reservoir = reservoir - weight\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'nextRequest', newNextRequest\n )\n end\n\n refresh_expiration(now, newNextRequest, groupTimeout)\n\n return {true, wait, reservoir}\n\nelse\n return {false}\nend\n", - "register_client.lua": "local queued = tonumber(ARGV[num_static_argv + 1])\n\n-- Could have been re-registered concurrently\nif not redis.call('zscore', client_last_seen_key, client) then\n redis.call('zadd', client_running_key, 0, client)\n redis.call('hset', client_num_queued_key, client, queued)\n redis.call('zadd', client_last_registered_key, 0, client)\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n\nreturn {}\n", - "running.lua": "return process_tick(now, false)['running']\n", - "submit.lua": "local queueLength = tonumber(ARGV[num_static_argv + 1])\nlocal weight = tonumber(ARGV[num_static_argv + 2])\n\nlocal capacity = process_tick(now, false)['capacity']\n\nlocal settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'highWater',\n 'nextRequest',\n 'strategy',\n 'unblockTime',\n 'penalty',\n 'minTime',\n 'groupTimeout'\n)\nlocal id = settings[1]\nlocal maxConcurrent = tonumber(settings[2])\nlocal highWater = tonumber(settings[3])\nlocal nextRequest = tonumber(settings[4])\nlocal strategy = tonumber(settings[5])\nlocal unblockTime = tonumber(settings[6])\nlocal penalty = tonumber(settings[7])\nlocal minTime = tonumber(settings[8])\nlocal groupTimeout = tonumber(settings[9])\n\nif maxConcurrent ~= nil and weight > maxConcurrent then\n return redis.error_reply('OVERWEIGHT:'..weight..':'..maxConcurrent)\nend\n\nlocal reachedHWM = (highWater ~= nil and queueLength == highWater\n and not (\n conditions_check(capacity, weight)\n and nextRequest - now <= 0\n )\n)\n\nlocal blocked = strategy == 3 and (reachedHWM or unblockTime >= now)\n\nif blocked then\n local computedPenalty = penalty\n if computedPenalty == nil then\n if minTime == 0 then\n computedPenalty = 5000\n else\n computedPenalty = 15 * minTime\n end\n end\n\n local newNextRequest = now + computedPenalty + minTime\n\n redis.call('hmset', settings_key,\n 'unblockTime', now + computedPenalty,\n 'nextRequest', newNextRequest\n )\n\n local clients_queued_reset = redis.call('hkeys', client_num_queued_key)\n local queued_reset = {}\n for i = 1, #clients_queued_reset do\n table.insert(queued_reset, clients_queued_reset[i])\n table.insert(queued_reset, 0)\n end\n redis.call('hmset', client_num_queued_key, unpack(queued_reset))\n\n redis.call('publish', 'b_'..id, 'blocked:')\n\n refresh_expiration(now, newNextRequest, groupTimeout)\nend\n\nif not blocked and not reachedHWM then\n redis.call('hincrby', client_num_queued_key, client, 1)\nend\n\nreturn {reachedHWM, blocked, strategy}\n", - "update_settings.lua": "local args = {'hmset', settings_key}\n\nfor i = num_static_argv + 1, #ARGV do\n table.insert(args, ARGV[i])\nend\n\nredis.call(unpack(args))\n\nprocess_tick(now, true)\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn {}\n", - "validate_client.lua": "if not redis.call('zscore', client_last_seen_key, client) then\n return redis.error_reply('UNKNOWN_CLIENT')\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n", - "validate_keys.lua": "if not (redis.call('exists', settings_key) == 1) then\n return redis.error_reply('SETTINGS_KEY_NOT_FOUND')\nend\n" +var require_pino = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports2, module14) { + "use strict"; + var os = __require2("os"); + var stdSerializers = require_pino_std_serializers(); + var caller = require_caller(); + var redaction = require_redaction(); + var time3 = require_time(); + var proto3 = require_proto(); + var symbols2 = require_symbols(); + var { configure } = require_safe_stable_stringify(); + var { assertDefaultLevelFound, mappings, genLsCache, genLevelComparison, assertLevelComparison } = require_levels(); + var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); + var { + createArgsNormalizer, + asChindings, + buildSafeSonicBoom, + buildFormatters, + stringify: stringify2, + normalizeDestFileDescriptor, + noop + } = require_tools(); + var { version: version3 } = require_meta(); + var { + chindingsSym, + redactFmtSym, + serializersSym, + timeSym, + timeSliceIndexSym, + streamSym, + stringifySym, + stringifySafeSym, + stringifiersSym, + setLevelSym, + endSym, + formatOptsSym, + messageKeySym, + errorKeySym, + nestedKeySym, + mixinSym, + levelCompSym, + useOnlyCustomLevelsSym, + formattersSym, + hooksSym, + nestedKeyStrSym, + mixinMergeStrategySym, + msgPrefixSym + } = symbols2; + var { epochTime, nullTime } = time3; + var { pid } = process; + var hostname2 = os.hostname(); + var defaultErrorSerializer = stdSerializers.err; + var defaultOptions4 = { + level: "info", + levelComparison: SORTING_ORDER.ASC, + levels: DEFAULT_LEVELS, + messageKey: "msg", + errorKey: "err", + nestedKey: null, + enabled: true, + base: { pid, hostname: hostname2 }, + serializers: Object.assign(/* @__PURE__ */ Object.create(null), { + err: defaultErrorSerializer + }), + formatters: Object.assign(/* @__PURE__ */ Object.create(null), { + bindings(bindings) { + return bindings; + }, + level(label, number3) { + return { level: number3 }; + } + }), + hooks: { + logMethod: void 0 + }, + timestamp: epochTime, + name: void 0, + redact: null, + customLevels: null, + useOnlyCustomLevels: false, + depthLimit: 5, + edgeLimit: 100 + }; + var normalize32 = createArgsNormalizer(defaultOptions4); + var serializers = Object.assign(/* @__PURE__ */ Object.create(null), stdSerializers); + function pino2(...args) { + const instance = {}; + const { opts, stream } = normalize32(instance, caller(), ...args); + const { + redact, + crlf, + serializers: serializers2, + timestamp, + messageKey, + errorKey, + nestedKey, + base: base2, + name, + level, + customLevels, + levelComparison, + mixin: mixin3, + mixinMergeStrategy, + useOnlyCustomLevels, + formatters, + hooks, + depthLimit, + edgeLimit, + onChild, + msgPrefix + } = opts; + const stringifySafe = configure({ + maximumDepth: depthLimit, + maximumBreadth: edgeLimit + }); + const allFormatters = buildFormatters( + formatters.level, + formatters.bindings, + formatters.log + ); + const stringifyFn = stringify2.bind({ + [stringifySafeSym]: stringifySafe + }); + const stringifiers = redact ? redaction(redact, stringifyFn) : {}; + const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn }; + const end = "}" + (crlf ? "\r\n" : "\n"); + const coreChindings = asChindings.bind(null, { + [chindingsSym]: "", + [serializersSym]: serializers2, + [stringifiersSym]: stringifiers, + [stringifySym]: stringify2, + [stringifySafeSym]: stringifySafe, + [formattersSym]: allFormatters + }); + let chindings = ""; + if (base2 !== null) { + if (name === void 0) { + chindings = coreChindings(base2); + } else { + chindings = coreChindings(Object.assign({}, base2, { name })); + } + } + const time4 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime; + const timeSliceIndex = time4().indexOf(":") + 1; + if (useOnlyCustomLevels && !customLevels) throw Error("customLevels is required if useOnlyCustomLevels is set true"); + if (mixin3 && typeof mixin3 !== "function") throw Error(`Unknown mixin type "${typeof mixin3}" - expected "function"`); + if (msgPrefix && typeof msgPrefix !== "string") throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`); + assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels); + const levels = mappings(customLevels, useOnlyCustomLevels); + assertLevelComparison(levelComparison); + const levelCompFunc = genLevelComparison(levelComparison); + Object.assign(instance, { + levels, + [levelCompSym]: levelCompFunc, + [useOnlyCustomLevelsSym]: useOnlyCustomLevels, + [streamSym]: stream, + [timeSym]: time4, + [timeSliceIndexSym]: timeSliceIndex, + [stringifySym]: stringify2, + [stringifySafeSym]: stringifySafe, + [stringifiersSym]: stringifiers, + [endSym]: end, + [formatOptsSym]: formatOpts, + [messageKeySym]: messageKey, + [errorKeySym]: errorKey, + [nestedKeySym]: nestedKey, + // protect against injection + [nestedKeyStrSym]: nestedKey ? `,${JSON.stringify(nestedKey)}:{` : "", + [serializersSym]: serializers2, + [mixinSym]: mixin3, + [mixinMergeStrategySym]: mixinMergeStrategy, + [chindingsSym]: chindings, + [formattersSym]: allFormatters, + [hooksSym]: hooks, + silent: noop, + onChild, + [msgPrefixSym]: msgPrefix + }); + Object.setPrototypeOf(instance, proto3()); + genLsCache(instance); + instance[setLevelSym](level); + return instance; + } + module14.exports = pino2; + module14.exports.destination = (dest = process.stdout.fd) => { + if (typeof dest === "object") { + dest.dest = normalizeDestFileDescriptor(dest.dest || process.stdout.fd); + return buildSafeSonicBoom(dest); + } else { + return buildSafeSonicBoom({ dest: normalizeDestFileDescriptor(dest), minLength: 0 }); + } }; + module14.exports.transport = require_transport(); + module14.exports.multistream = require_multistream(); + module14.exports.levels = mappings(); + module14.exports.stdSerializers = serializers; + module14.exports.stdTimeFunctions = Object.assign({}, time3); + module14.exports.symbols = symbols2; + module14.exports.version = version3; + module14.exports.default = pino2; + module14.exports.pino = pino2; } }); -var require_Scripts = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Scripts.js"(exports2) { +function logMethod(args, method) { + const stringIdx = typeof args[0] === "string" ? 0 : 1; + if (args.length > 1) { + for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { + args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; + } + } + method.apply(this, args); +} +var import_npm_pino; +var prettyPrint; +var logger; +var logLevel; +var logger_default; +var init_logger = __esm({ + "src/serve/logger.ts"() { "use strict"; - var headers; - var lua; - var templates; - lua = require_lua(); - headers = { - refs: lua["refs.lua"], - validate_keys: lua["validate_keys.lua"], - validate_client: lua["validate_client.lua"], - refresh_expiration: lua["refresh_expiration.lua"], - process_tick: lua["process_tick.lua"], - conditions_check: lua["conditions_check.lua"], - get_time: lua["get_time.lua"] + import_npm_pino = __toESM(require_pino()); + prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; + if (prettyPrint) { + try { + logger = (0, import_npm_pino.default)({ + hooks: { logMethod }, + transport: { + target: "pino-pretty", + options: { + colorize: true + } + } + }); + } catch (e2) { + console.warn("pino-pretty transport unavailable, using basic logging", e2); + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); + } + } else { + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); + } + logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); + if (Object.keys(logger.levels.values).includes(logLevel)) { + logger.level = logLevel; + } else { + logger.warn(`Unknown log level: ${logLevel}`); + } + console.debug = logger.debug.bind(logger); + console.info = logger.info.bind(logger); + console.log = logger.info.bind(logger); + console.warn = logger.warn.bind(logger); + console.error = logger.error.bind(logger); + logger_default = logger; + } +}); +var timer; +var coerceToError; +var defaultOptions2; +var tag; +var PersistentAction; +var persistent_actions_default; +var init_persistent_actions = __esm({ + "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/persistent-actions.mjs"() { + init_esm4(); + init_esm(); + init_events(); + timer = Symbol("timer"); + coerceToError = (arg) => { + if (arg && arg instanceof Error) + return arg; + console.warn(tag, "Please use Error objects when throwing or rejecting"); + return new Error((typeof arg === "string" ? arg : JSON.stringify(arg)) ?? "undefined"); }; - exports2.allKeys = function(id) { - return [ - /* - HASH - */ - `b_${id}_settings`, - /* - HASH - job index -> weight - */ - `b_${id}_job_weights`, - /* - ZSET - job index -> expiration - */ - `b_${id}_job_expirations`, - /* - HASH - job index -> client - */ - `b_${id}_job_clients`, - /* - ZSET - client -> sum running - */ - `b_${id}_client_running`, - /* - HASH - client -> num queued - */ - `b_${id}_client_num_queued`, - /* - ZSET - client -> last job registered - */ - `b_${id}_client_last_registered`, - /* - ZSET - client -> last seen - */ - `b_${id}_client_last_seen` - ]; + defaultOptions2 = { + maxAttempts: Number.POSITIVE_INFINITY, + retrySeconds: 30 }; - templates = { - init: { - keys: exports2.allKeys, - headers: ["process_tick"], - refresh_expiration: true, - code: lua["init.lua"] - }, - group_check: { - keys: exports2.allKeys, - headers: [], - refresh_expiration: false, - code: lua["group_check.lua"] - }, - register_client: { - keys: exports2.allKeys, - headers: ["validate_keys"], - refresh_expiration: false, - code: lua["register_client.lua"] - }, - blacklist_client: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client"], - refresh_expiration: false, - code: lua["blacklist_client.lua"] - }, - heartbeat: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["heartbeat.lua"] - }, - update_settings: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["update_settings.lua"] + tag = "[chelonia.persistentActions]"; + PersistentAction = class { + id; + invocation; + options; + status; + [timer]; + constructor(invocation, options2 = {}) { + this.id = crypto.randomUUID(); + this.invocation = invocation; + this.options = { ...defaultOptions2, ...options2 }; + this.status = { + attempting: false, + failedAttemptsSoFar: 0, + lastError: "", + nextRetry: "", + resolved: false + }; + } + async attempt() { + if (this.status.attempting || this.status.resolved) + return; + if (await this.trySBP(this.options.skipCondition)) + this.cancel(); + if (this.status.resolved) + return; + try { + this.status.attempting = true; + const result = await esm_default(...this.invocation); + this.status.attempting = false; + this.handleSuccess(result); + } catch (error2) { + this.status.attempting = false; + await this.handleError(coerceToError(error2)); + } + } + cancel() { + if (this[timer]) + clearTimeout(this[timer]); + this.status.nextRetry = ""; + this.status.resolved = true; + } + async handleError(error2) { + const { id, options: options2, status } = this; + status.failedAttemptsSoFar++; + status.lastError = error2.message; + const anyAttemptLeft = options2.maxAttempts > status.failedAttemptsSoFar; + if (!anyAttemptLeft) + status.resolved = true; + status.nextRetry = anyAttemptLeft && !status.resolved ? new Date(Date.now() + options2.retrySeconds * 1e3).toISOString() : ""; + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_FAILURE, { error: error2, id }); + await this.trySBP(options2.errorInvocation); + if (!anyAttemptLeft) { + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_TOTAL_FAILURE, { error: error2, id }); + await this.trySBP(options2.totalFailureInvocation); + } + if (status.nextRetry) { + this[timer] = setTimeout(() => { + this.attempt().catch((e2) => { + console.error("Error attempting persistent action", id, e2); + }); + }, this.options.retrySeconds * 1e3); + } + } + handleSuccess(result) { + const { id, status } = this; + status.lastError = ""; + status.nextRetry = ""; + status.resolved = true; + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_SUCCESS, { id, result }); + } + async trySBP(invocation) { + try { + return invocation ? await esm_default(...invocation) : void 0; + } catch (error2) { + console.error(tag, coerceToError(error2).message); + } + } + }; + persistent_actions_default = esm_default("sbp/selectors/register", { + "chelonia.persistentActions/_init"() { + this.actionsByID = /* @__PURE__ */ Object.create(null); + this.checkDatabaseKey = () => { + if (!this.databaseKey) + throw new TypeError(`${tag} No database key configured`); + }; + esm_default("okTurtles.events/on", PERSISTENT_ACTION_SUCCESS, ({ id }) => { + esm_default("chelonia.persistentActions/cancel", id); + }); + esm_default("okTurtles.events/on", PERSISTENT_ACTION_TOTAL_FAILURE, ({ id }) => { + esm_default("chelonia.persistentActions/cancel", id); + }); }, - running: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["running.lua"] + // Cancels a specific action by its ID. + // The action won't be retried again, but an async action cannot be aborted if its promise is stil attempting. + async "chelonia.persistentActions/cancel"(id) { + if (id in this.actionsByID) { + this.actionsByID[id].cancel(); + delete this.actionsByID[id]; + return await esm_default("chelonia.persistentActions/save"); + } }, - queued: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client"], - refresh_expiration: false, - code: lua["queued.lua"] + // TODO: validation + "chelonia.persistentActions/configure"({ databaseKey, options: options2 = {} }) { + this.databaseKey = databaseKey; + for (const key in options2) { + if (key in defaultOptions2) { + defaultOptions2[key] = options2[key]; + } else { + throw new TypeError(`${tag} Unknown option: ${key}`); + } + } }, - done: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["done.lua"] + "chelonia.persistentActions/enqueue"(...args) { + const ids = []; + for (const arg of args) { + const action = Array.isArray(arg) ? new PersistentAction(arg) : new PersistentAction(arg.invocation, arg); + this.actionsByID[action.id] = action; + ids.push(action.id); + } + esm_default("chelonia.persistentActions/save").catch((e2) => { + console.error("Error saving persistent actions", e2); + }); + for (const id of ids) { + this.actionsByID[id].attempt().catch((e2) => { + console.error("Error attempting persistent action", id, e2); + }); + } + return ids; }, - check: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: false, - code: lua["check.lua"] + // Forces retrying a given persisted action immediately, rather than waiting for the scheduled retry. + // - 'status.failedAttemptsSoFar' will still be increased upon failure. + // - Does nothing if a retry is already running. + // - Does nothing if the action has already been resolved, rejected or cancelled. + "chelonia.persistentActions/forceRetry"(id) { + if (id in this.actionsByID) { + return this.actionsByID[id].attempt(); + } }, - submit: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: true, - code: lua["submit.lua"] + // Loads and tries every stored persistent action under the configured database key. + async "chelonia.persistentActions/load"() { + this.checkDatabaseKey(); + const storedActions = JSON.parse(await esm_default("chelonia.db/get", this.databaseKey) ?? "[]"); + for (const { id, invocation, options: options2 } of storedActions) { + this.actionsByID[id] = new PersistentAction(invocation, options2); + this.actionsByID[id].id = id; + } + return esm_default("chelonia.persistentActions/retryAll"); }, - register: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: true, - code: lua["register.lua"] + // Retry all existing persisted actions. + // TODO: add some delay between actions so as not to spam the server, + // or have a way to issue them all at once in a single network call. + "chelonia.persistentActions/retryAll"() { + return Promise.allSettled(Object.keys(this.actionsByID).map((id) => esm_default("chelonia.persistentActions/forceRetry", id))); }, - free: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["free.lua"] + // Updates the database version of the attempting action list. + "chelonia.persistentActions/save"() { + this.checkDatabaseKey(); + return esm_default("chelonia.db/set", this.databaseKey, JSON.stringify(Object.values(this.actionsByID))); }, - current_reservoir: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["current_reservoir.lua"] + "chelonia.persistentActions/status"() { + return Object.values(this.actionsByID).map((action) => ({ + id: action.id, + invocation: action.invocation, + ...action.status + })); }, - increment_reservoir: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["increment_reservoir.lua"] + // Pauses every currently loaded action, and removes them from memory. + // Note: persistent storage is not affected, so that these actions can be later loaded again and retried. + "chelonia.persistentActions/unload"() { + for (const id in this.actionsByID) { + if (this.actionsByID[id][timer]) { + clearTimeout(this.actionsByID[id][timer]); + } + delete this.actionsByID[id]; + } } - }; - exports2.names = Object.keys(templates); - exports2.keys = function(name, id) { - return templates[name].keys(id); - }; - exports2.payload = function(name) { - var template; - template = templates[name]; - return Array.prototype.concat(headers.refs, template.headers.map(function(h2) { - return headers[h2]; - }), template.refresh_expiration ? headers.refresh_expiration : "", template.code).join("\n"); - }; + }); } }); -var require_RedisConnection = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisConnection.js"(exports, module) { - "use strict"; - function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - function _asyncToGenerator(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; - } - var Events; - var RedisConnection; - var Scripts; - var parser; - parser = require_parser2(); - Events = require_Events(); - Scripts = require_Scripts(); - RedisConnection = function() { - class RedisConnection { - constructor(options = {}) { - parser.load(options, this.defaults, this); - if (this.Redis == null) { - this.Redis = eval("require")("redis"); - } - if (this.Events == null) { - this.Events = new Events(this); - } - this.terminated = false; - if (this.client == null) { - this.client = this.Redis.createClient(this.clientOptions); - } - this.subscriber = this.client.duplicate(); - this.limiters = {}; - this.shas = {}; - this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { - return this._loadScripts(); - }).then(() => { - return { - client: this.client, - subscriber: this.subscriber - }; - }); - } - _setup(client, sub) { - client.setMaxListeners(0); - return new this.Promise((resolve82, reject) => { - client.on("error", (e2) => { - return this.Events.trigger("error", e2); - }); - if (sub) { - client.on("message", (channel, message) => { - var ref; - return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; - }); - } - if (client.ready) { - return resolve82(); - } else { - return client.once("ready", resolve82); - } - }); - } - _loadScript(name) { - return new this.Promise((resolve82, reject) => { - var payload; - payload = Scripts.payload(name); - return this.client.multi([["script", "load", payload]]).exec((err, replies) => { - if (err != null) { - return reject(err); - } - this.shas[name] = replies[0]; - return resolve82(replies[0]); - }); - }); - } - _loadScripts() { - return this.Promise.all(Scripts.names.map((k) => { - return this._loadScript(k); - })); - } - __runCommand__(cmd) { - var _this = this; - return _asyncToGenerator(function* () { - yield _this.ready; - return new _this.Promise((resolve82, reject) => { - return _this.client.multi([cmd]).exec_atomic(function(err, replies) { - if (err != null) { - return reject(err); - } else { - return resolve82(replies[0]); - } - }); - }); - })(); +var SERVER; +var init_presets = __esm({ + "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/presets.mjs"() { + SERVER = { + // We don't check the subscriptionSet in the server because we accpt new + // contract registrations, and are also not subcribed to contracts the same + // way clients are + acceptAllMessages: true, + // The server also doesn't process actions + skipActionProcessing: true, + // The previous setting implies this one, which we set to be on the safe side + skipSideEffects: true, + // Changes the behaviour of unwrapMaybeEncryptedData so that it never decrypts. + // Mostly useful for the server, to avoid filling up the logs and for faster + // execution. + skipDecryptionAttempts: true, + // If an error occurs during processing, the message is rejected rather than + // ignored + strictProcessing: true, + // The server expects events to be received in order (no past or future events) + strictOrdering: true + }; + } +}); +var cors; +var init_cors = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/cors/index.js"() { + cors = (options2) => { + const defaults = { + origin: "*", + allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"], + allowHeaders: [], + exposeHeaders: [] + }; + const opts = { + ...defaults, + ...options2 + }; + const findAllowOrigin = ((optsOrigin) => { + if (typeof optsOrigin === "string") { + if (optsOrigin === "*") { + if (opts.credentials) { + return (origin) => origin || null; + } + return () => optsOrigin; + } else { + return (origin) => optsOrigin === origin ? origin : null; + } + } else if (typeof optsOrigin === "function") { + return optsOrigin; + } else { + return (origin) => optsOrigin.includes(origin) ? origin : null; + } + })(opts.origin); + const findAllowMethods = ((optsAllowMethods) => { + if (typeof optsAllowMethods === "function") { + return optsAllowMethods; + } else if (Array.isArray(optsAllowMethods)) { + return () => optsAllowMethods; + } else { + return () => []; } - __addLimiter__(instance) { - return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { - return new this.Promise((resolve82, reject) => { - var handler; - handler = (chan) => { - if (chan === channel) { - this.subscriber.removeListener("subscribe", handler); - this.limiters[channel] = instance; - return resolve82(); - } - }; - this.subscriber.on("subscribe", handler); - return this.subscriber.subscribe(channel); - }); - })); + })(opts.allowMethods); + return async function cors2(c, next) { + function set(key, value) { + c.res.headers.set(key, value); } - __removeLimiter__(instance) { - var _this2 = this; - return this.Promise.all([instance.channel(), instance.channel_client()].map( - /* @__PURE__ */ function() { - var _ref = _asyncToGenerator(function* (channel) { - if (!_this2.terminated) { - yield new _this2.Promise((resolve82, reject) => { - return _this2.subscriber.unsubscribe(channel, function(err, chan) { - if (err != null) { - return reject(err); - } - if (chan === channel) { - return resolve82(); - } - }); - }); - } - return delete _this2.limiters[channel]; - }); - return function(_x) { - return _ref.apply(this, arguments); - }; - }() - )); + const allowOrigin = await findAllowOrigin(c.req.header("origin") || "", c); + if (allowOrigin) { + set("Access-Control-Allow-Origin", allowOrigin); } - __scriptArgs__(name, id, args, cb) { - var keys; - keys = Scripts.keys(name, id); - return [this.shas[name], keys.length].concat(keys, args, cb); + if (opts.credentials) { + set("Access-Control-Allow-Credentials", "true"); } - __scriptFn__(name) { - return this.client.evalsha.bind(this.client); + if (opts.exposeHeaders?.length) { + set("Access-Control-Expose-Headers", opts.exposeHeaders.join(",")); } - disconnect(flush = true) { - var i2, k, len, ref; - ref = Object.keys(this.limiters); - for (i2 = 0, len = ref.length; i2 < len; i2++) { - k = ref[i2]; - clearInterval(this.limiters[k]._store.heartbeat); + if (c.req.method === "OPTIONS") { + if (opts.origin !== "*" || opts.credentials) { + set("Vary", "Origin"); } - this.limiters = {}; - this.terminated = true; - this.client.end(flush); - this.subscriber.end(flush); - return this.Promise.resolve(); + if (opts.maxAge != null) { + set("Access-Control-Max-Age", opts.maxAge.toString()); + } + const allowMethods = await findAllowMethods(c.req.header("origin") || "", c); + if (allowMethods.length) { + set("Access-Control-Allow-Methods", allowMethods.join(",")); + } + let headers = opts.allowHeaders; + if (!headers?.length) { + const requestHeaders = c.req.header("Access-Control-Request-Headers"); + if (requestHeaders) { + headers = requestHeaders.split(/\s*,\s*/); + } + } + if (headers?.length) { + set("Access-Control-Allow-Headers", headers.join(",")); + c.res.headers.append("Vary", "Access-Control-Request-Headers"); + } + c.res.headers.delete("Content-Length"); + c.res.headers.delete("Content-Type"); + return new Response(null, { + headers: c.res.headers, + status: 204, + statusText: "No Content" + }); + } + await next(); + if (opts.origin !== "*" || opts.credentials) { + c.header("Vary", "Origin", { append: true }); } - } - ; - RedisConnection.prototype.datastore = "redis"; - RedisConnection.prototype.defaults = { - Redis: null, - clientOptions: {}, - client: null, - Promise, - Events: null }; - return RedisConnection; - }.call(void 0); - module.exports = RedisConnection; + }; } }); -var require_IORedisConnection = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/IORedisConnection.js"(exports, module) { - "use strict"; - function _slicedToArray(arr, i2) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i2) || _nonIterableRest(); - } - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); +async function readWithoutBlocking(readPromise) { + return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]); +} +function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) { + const cancel = (error2) => { + reader.cancel(error2).catch(() => { + }); + }; + writable.on("close", cancel); + writable.on("error", cancel); + (currentReadPromise ?? reader.read()).then(flow, handleStreamError); + return reader.closed.finally(() => { + writable.off("close", cancel); + writable.off("error", cancel); + }); + function handleStreamError(error2) { + if (error2) { + writable.destroy(error2); } - function _iterableToArrayLimit(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } + } + function onDrain() { + reader.read().then(flow, handleStreamError); + } + function flow({ done, value }) { + try { + if (done) { + writable.end(); + } else if (!writable.write(value)) { + writable.once("drain", onDrain); + } else { + return reader.read().then(flow, handleStreamError); } - return _arr; - } - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; + } catch (e2) { + handleStreamError(e2); } - function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + } +} +function writeFromReadableStream(stream, writable) { + if (stream.locked) { + throw new TypeError("ReadableStream is locked."); + } else if (writable.destroyed) { + return; + } + return writeFromReadableStreamDefaultReader(stream.getReader(), writable); +} +var RequestError; +var toRequestError; +var GlobalRequest; +var Request2; +var newHeadersFromIncoming; +var wrapBodyStream; +var newRequestFromIncoming; +var getRequestCache; +var requestCache; +var incomingKey; +var urlKey; +var headersKey; +var abortControllerKey; +var getAbortController; +var requestPrototype; +var newRequest; +var responseCache; +var getResponseCache; +var cacheKey; +var GlobalResponse; +var Response2; +var buildOutgoingHttpHeaders; +var X_ALREADY_SENT; +var outgoingEnded; +var incomingDraining; +var DRAIN_TIMEOUT_MS; +var MAX_DRAIN_BYTES; +var drainIncoming; +var handleRequestError; +var handleFetchError; +var handleResponseError; +var flushHeaders; +var responseViaCache; +var isPromise; +var responseViaResponseObject; +var getRequestListener; +var createAdaptorServer; +var init_dist2 = __esm({ + "node_modules/.deno/@hono+node-server@1.19.14/node_modules/@hono/node-server/dist/index.mjs"() { + RequestError = class extends Error { + constructor(message, options2) { + super(message, options2); + this.name = "RequestError"; + } + }; + toRequestError = (e2) => { + if (e2 instanceof RequestError) { + return e2; + } + return new RequestError(e2.message, { cause: e2 }); + }; + GlobalRequest = global.Request; + Request2 = class extends GlobalRequest { + constructor(input, options2) { + if (typeof input === "object" && getRequestCache in input) { + input = input[getRequestCache](); + } + if (typeof options2?.body?.getReader !== "undefined") { + ; + options2.duplex ??= "half"; + } + super(input, options2); } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + }; + newHeadersFromIncoming = (incoming) => { + const headerRecord = []; + const rawHeaders = incoming.rawHeaders; + for (let i2 = 0; i2 < rawHeaders.length; i2 += 2) { + const { [i2]: key, [i2 + 1]: value } = rawHeaders; + if (key.charCodeAt(0) !== /*:*/ + 58) { + headerRecord.push([key, value]); + } } - } - function _asyncToGenerator(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); + return new Headers(headerRecord); + }; + wrapBodyStream = Symbol("wrapBodyStream"); + newRequestFromIncoming = (method, url2, headers, incoming, abortController) => { + const init2 = { + method, + headers, + signal: abortController.signal }; - } - var Events; - var IORedisConnection; - var Scripts; - var parser; - parser = require_parser2(); - Events = require_Events(); - Scripts = require_Scripts(); - IORedisConnection = function() { - class IORedisConnection { - constructor(options = {}) { - parser.load(options, this.defaults, this); - if (this.Redis == null) { - this.Redis = eval("require")("ioredis"); - } - if (this.Events == null) { - this.Events = new Events(this); + if (method === "TRACE") { + init2.method = "GET"; + const req = new Request2(url2, init2); + Object.defineProperty(req, "method", { + get() { + return "TRACE"; } - this.terminated = false; - if (this.clusterNodes != null) { - this.client = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); - this.subscriber = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); - } else if (this.client != null && this.client.duplicate == null) { - this.subscriber = new this.Redis.Cluster(this.client.startupNodes, this.client.options); - } else { - if (this.client == null) { - this.client = new this.Redis(this.clientOptions); + }); + return req; + } + if (!(method === "GET" || method === "HEAD")) { + if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) { + init2.body = new ReadableStream({ + start(controller) { + controller.enqueue(incoming.rawBody); + controller.close(); } - this.subscriber = this.client.duplicate(); - } - this.limiters = {}; - this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { - this._loadScripts(); - return { - client: this.client, - subscriber: this.subscriber - }; }); - } - _setup(client, sub) { - client.setMaxListeners(0); - return new this.Promise((resolve82, reject) => { - client.on("error", (e2) => { - return this.Events.trigger("error", e2); - }); - if (sub) { - client.on("message", (channel, message) => { - var ref; - return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; - }); - } - if (client.status === "ready") { - return resolve82(); - } else { - return client.once("ready", resolve82); + } else if (incoming[wrapBodyStream]) { + let reader; + init2.body = new ReadableStream({ + async pull(controller) { + try { + reader ||= Readable2.toWeb(incoming).getReader(); + const { done, value } = await reader.read(); + if (done) { + controller.close(); + } else { + controller.enqueue(value); + } + } catch (error2) { + controller.error(error2); + } } }); + } else { + init2.body = Readable2.toWeb(incoming); } - _loadScripts() { - return Scripts.names.forEach((name) => { - return this.client.defineCommand(name, { - lua: Scripts.payload(name) - }); - }); - } - __runCommand__(cmd) { - var _this = this; - return _asyncToGenerator(function* () { - var _, deleted; - yield _this.ready; - var _ref = yield _this.client.pipeline([cmd]).exec(); - var _ref2 = _slicedToArray(_ref, 1); - var _ref2$ = _slicedToArray(_ref2[0], 2); - _ = _ref2$[0]; - deleted = _ref2$[1]; - return deleted; - })(); + } + return new Request2(url2, init2); + }; + getRequestCache = Symbol("getRequestCache"); + requestCache = Symbol("requestCache"); + incomingKey = Symbol("incomingKey"); + urlKey = Symbol("urlKey"); + headersKey = Symbol("headersKey"); + abortControllerKey = Symbol("abortControllerKey"); + getAbortController = Symbol("getAbortController"); + requestPrototype = { + get method() { + return this[incomingKey].method || "GET"; + }, + get url() { + return this[urlKey]; + }, + get headers() { + return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]); + }, + [getAbortController]() { + this[getRequestCache](); + return this[abortControllerKey]; + }, + [getRequestCache]() { + this[abortControllerKey] ||= new AbortController(); + return this[requestCache] ||= newRequestFromIncoming( + this.method, + this[urlKey], + this.headers, + this[incomingKey], + this[abortControllerKey] + ); + } + }; + [ + "body", + "bodyUsed", + "cache", + "credentials", + "destination", + "integrity", + "mode", + "redirect", + "referrer", + "referrerPolicy", + "signal", + "keepalive" + ].forEach((k) => { + Object.defineProperty(requestPrototype, k, { + get() { + return this[getRequestCache]()[k]; } - __addLimiter__(instance) { - return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { - return new this.Promise((resolve82, reject) => { - return this.subscriber.subscribe(channel, () => { - this.limiters[channel] = instance; - return resolve82(); - }); - }); - })); + }); + }); + ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { + Object.defineProperty(requestPrototype, k, { + value: function() { + return this[getRequestCache]()[k](); } - __removeLimiter__(instance) { - var _this2 = this; - return [instance.channel(), instance.channel_client()].forEach( - /* @__PURE__ */ function() { - var _ref3 = _asyncToGenerator(function* (channel) { - if (!_this2.terminated) { - yield _this2.subscriber.unsubscribe(channel); - } - return delete _this2.limiters[channel]; - }); - return function(_x) { - return _ref3.apply(this, arguments); - }; - }() - ); + }); + }); + Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { + value: function(depth, options2, inspectFn) { + const props = { + method: this.method, + url: this.url, + headers: this.headers, + nativeRequest: this[requestCache] + }; + return `Request (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; + } + }); + Object.setPrototypeOf(requestPrototype, Request2.prototype); + newRequest = (incoming, defaultHostname) => { + const req = Object.create(requestPrototype); + req[incomingKey] = incoming; + const incomingUrl = incoming.url || ""; + if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL. + (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) { + if (incoming instanceof Http2ServerRequest) { + throw new RequestError("Absolute URL for :path is not allowed in HTTP/2"); } - __scriptArgs__(name, id, args, cb) { - var keys; - keys = Scripts.keys(name, id); - return [keys.length].concat(keys, args, cb); + try { + const url22 = new URL(incomingUrl); + req[urlKey] = url22.href; + } catch (e2) { + throw new RequestError("Invalid absolute URL", { cause: e2 }); } - __scriptFn__(name) { - return this.client[name].bind(this.client); + return req; + } + const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname; + if (!host) { + throw new RequestError("Missing host header"); + } + let scheme; + if (incoming instanceof Http2ServerRequest) { + scheme = incoming.scheme; + if (!(scheme === "http" || scheme === "https")) { + throw new RequestError("Unsupported scheme"); } - disconnect(flush = true) { - var i2, k, len, ref; - ref = Object.keys(this.limiters); - for (i2 = 0, len = ref.length; i2 < len; i2++) { - k = ref[i2]; - clearInterval(this.limiters[k]._store.heartbeat); - } - this.limiters = {}; - this.terminated = true; - if (flush) { - return this.Promise.all([this.client.quit(), this.subscriber.quit()]); + } else { + scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http"; + } + const url2 = new URL(`${scheme}://${host}${incomingUrl}`); + if (url2.hostname.length !== host.length && url2.hostname !== host.replace(/:\d+$/, "")) { + throw new RequestError("Invalid host header"); + } + req[urlKey] = url2.href; + return req; + }; + responseCache = Symbol("responseCache"); + getResponseCache = Symbol("getResponseCache"); + cacheKey = Symbol("cache"); + GlobalResponse = global.Response; + Response2 = class _Response { + #body; + #init; + [getResponseCache]() { + delete this[cacheKey]; + return this[responseCache] ||= new GlobalResponse(this.#body, this.#init); + } + constructor(body, init2) { + let headers; + this.#body = body; + if (init2 instanceof _Response) { + const cachedGlobalResponse = init2[responseCache]; + if (cachedGlobalResponse) { + this.#init = cachedGlobalResponse; + this[getResponseCache](); + return; } else { - this.client.disconnect(); - this.subscriber.disconnect(); - return this.Promise.resolve(); + this.#init = init2.#init; + headers = new Headers(init2.#init.headers); } + } else { + this.#init = init2; + } + if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) { + ; + this[cacheKey] = [init2?.status || 200, body, headers || init2?.headers]; } } - ; - IORedisConnection.prototype.datastore = "ioredis"; - IORedisConnection.prototype.defaults = { - Redis: null, - clientOptions: {}, - clusterNodes: null, - client: null, - Promise, - Events: null - }; - return IORedisConnection; - }.call(void 0); - module.exports = IORedisConnection; - } -}); -var require_RedisDatastore = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisDatastore.js"(exports2, module14) { - "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); - } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; + get headers() { + const cache2 = this[cacheKey]; + if (cache2) { + if (!(cache2[2] instanceof Headers)) { + cache2[2] = new Headers( + cache2[2] || { "content-type": "text/plain; charset=UTF-8" } + ); + } + return cache2[2]; } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + return this[getResponseCache]().headers; + } + get status() { + return this[cacheKey]?.[0] ?? this[getResponseCache]().status; + } + get ok() { + const status = this.status; + return status >= 200 && status < 300; + } + }; + ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => { + Object.defineProperty(Response2.prototype, k, { + get() { + return this[getResponseCache]()[k]; + } + }); + }); + ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { + Object.defineProperty(Response2.prototype, k, { + value: function() { + return this[getResponseCache]()[k](); } + }); + }); + Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), { + value: function(depth, options2, inspectFn) { + const props = { + status: this.status, + headers: this.headers, + ok: this.ok, + nativeResponse: this[responseCache] + }; + return `Response (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; } - return _arr; - } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; - } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); + }); + Object.setPrototypeOf(Response2, GlobalResponse); + Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype); + buildOutgoingHttpHeaders = (headers) => { + const res = {}; + if (!(headers instanceof Headers)) { + headers = new Headers(headers ?? void 0); + } + const cookies = []; + for (const [k, v2] of headers) { + if (k === "set-cookie") { + cookies.push(v2); + } else { + res[k] = v2; + } + } + if (cookies.length > 0) { + res["set-cookie"] = cookies; + } + res["content-type"] ??= "text/plain; charset=UTF-8"; + return res; + }; + X_ALREADY_SENT = "x-hono-already-sent"; + if (typeof global.crypto === "undefined") { + global.crypto = crypto2; + } + outgoingEnded = Symbol("outgoingEnded"); + incomingDraining = Symbol("incomingDraining"); + DRAIN_TIMEOUT_MS = 500; + MAX_DRAIN_BYTES = 64 * 1024 * 1024; + drainIncoming = (incoming) => { + const incomingWithDrainState = incoming; + if (incoming.destroyed || incomingWithDrainState[incomingDraining]) { return; } - if (info.done) { - resolve82(value); + incomingWithDrainState[incomingDraining] = true; + if (incoming instanceof Http2ServerRequest2) { + try { + ; + incoming.stream?.close?.(h2constants.NGHTTP2_NO_ERROR); + } catch { + } + return; + } + let bytesRead = 0; + const cleanup = () => { + clearTimeout(timer2); + incoming.off("data", onData); + incoming.off("end", cleanup); + incoming.off("error", cleanup); + }; + const forceClose = () => { + cleanup(); + const socket = incoming.socket; + if (socket && !socket.destroyed) { + socket.destroySoon(); + } + }; + const timer2 = setTimeout(forceClose, DRAIN_TIMEOUT_MS); + timer2.unref?.(); + const onData = (chunk) => { + bytesRead += chunk.length; + if (bytesRead > MAX_DRAIN_BYTES) { + forceClose(); + } + }; + incoming.on("data", onData); + incoming.on("end", cleanup); + incoming.on("error", cleanup); + incoming.resume(); + }; + handleRequestError = () => new Response(null, { + status: 400 + }); + handleFetchError = (e2) => new Response(null, { + status: e2 instanceof Error && (e2.name === "TimeoutError" || e2.constructor.name === "TimeoutError") ? 504 : 500 + }); + handleResponseError = (e2, outgoing) => { + const err = e2 instanceof Error ? e2 : new Error("unknown error", { cause: e2 }); + if (err.code === "ERR_STREAM_PREMATURE_CLOSE") { + console.info("The user aborted a request."); } else { - Promise.resolve(value).then(_next, _throw); + console.error(e2); + if (!outgoing.headersSent) { + outgoing.writeHead(500, { "Content-Type": "text/plain" }); + } + outgoing.end(`Error: ${err.message}`); + outgoing.destroy(err); } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + }; + flushHeaders = (outgoing) => { + if ("flushHeaders" in outgoing && outgoing.writable) { + outgoing.flushHeaders(); + } + }; + responseViaCache = async (res, outgoing) => { + let [status, body, header] = res[cacheKey]; + let hasContentLength = false; + if (!header) { + header = { "content-type": "text/plain; charset=UTF-8" }; + } else if (header instanceof Headers) { + hasContentLength = header.has("content-length"); + header = buildOutgoingHttpHeaders(header); + } else if (Array.isArray(header)) { + const headerObj = new Headers(header); + hasContentLength = headerObj.has("content-length"); + header = buildOutgoingHttpHeaders(headerObj); + } else { + for (const key in header) { + if (key.length === 14 && key.toLowerCase() === "content-length") { + hasContentLength = true; + break; } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + } + if (!hasContentLength) { + if (typeof body === "string") { + header["Content-Length"] = Buffer.byteLength(body); + } else if (body instanceof Uint8Array) { + header["Content-Length"] = body.byteLength; + } else if (body instanceof Blob) { + header["Content-Length"] = body.size; + } + } + outgoing.writeHead(status, header); + if (typeof body === "string" || body instanceof Uint8Array) { + outgoing.end(body); + } else if (body instanceof Blob) { + outgoing.end(new Uint8Array(await body.arrayBuffer())); + } else { + flushHeaders(outgoing); + await writeFromReadableStream(body, outgoing)?.catch( + (e2) => handleResponseError(e2, outgoing) + ); + } + ; + outgoing[outgoingEnded]?.(); + }; + isPromise = (res) => typeof res.then === "function"; + responseViaResponseObject = async (res, outgoing, options2 = {}) => { + if (isPromise(res)) { + if (options2.errorHandler) { + try { + res = await res; + } catch (err) { + const errRes = await options2.errorHandler(err); + if (!errRes) { + return; + } + res = errRes; } - _next(void 0); - }); - }; - } - var BottleneckError; - var IORedisConnection2; - var RedisConnection2; - var RedisDatastore; - var parser3; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - RedisConnection2 = require_RedisConnection(); - IORedisConnection2 = require_IORedisConnection(); - RedisDatastore = class RedisDatastore { - constructor(instance, storeOptions, storeInstanceOptions) { - this.instance = instance; - this.storeOptions = storeOptions; - this.originalId = this.instance.id; - this.clientId = this.instance._randomIndex(); - parser3.load(storeInstanceOptions, storeInstanceOptions, this); - this.clients = {}; - this.capacityPriorityCounters = {}; - this.sharedConnection = this.connection != null; - if (this.connection == null) { - this.connection = this.instance.datastore === "redis" ? new RedisConnection2({ - Redis: this.Redis, - clientOptions: this.clientOptions, - Promise: this.Promise, - Events: this.instance.Events - }) : this.instance.datastore === "ioredis" ? new IORedisConnection2({ - Redis: this.Redis, - clientOptions: this.clientOptions, - clusterNodes: this.clusterNodes, - Promise: this.Promise, - Events: this.instance.Events - }) : void 0; + } else { + res = await res.catch(handleFetchError); } - this.instance.connection = this.connection; - this.instance.datastore = this.connection.datastore; - this.ready = this.connection.ready.then((clients) => { - this.clients = clients; - return this.runScript("init", this.prepareInitSettings(this.clearDatastore)); - }).then(() => { - return this.connection.__addLimiter__(this.instance); - }).then(() => { - return this.runScript("register_client", [this.instance.queued()]); - }).then(() => { - var base2; - if (typeof (base2 = this.heartbeat = setInterval(() => { - return this.runScript("heartbeat", []).catch((e2) => { - return this.instance.Events.trigger("error", e2); + } + if (cacheKey in res) { + return responseViaCache(res, outgoing); + } + const resHeaderRecord = buildOutgoingHttpHeaders(res.headers); + if (res.body) { + const reader = res.body.getReader(); + const values = []; + let done = false; + let currentReadPromise = void 0; + if (resHeaderRecord["transfer-encoding"] !== "chunked") { + let maxReadCount = 2; + for (let i2 = 0; i2 < maxReadCount; i2++) { + currentReadPromise ||= reader.read(); + const chunk = await readWithoutBlocking(currentReadPromise).catch((e2) => { + console.error(e2); + done = true; }); - }, this.heartbeatInterval)).unref === "function") { - base2.unref(); + if (!chunk) { + if (i2 === 1) { + await new Promise((resolve82) => setTimeout(resolve82)); + maxReadCount = 3; + continue; + } + break; + } + currentReadPromise = void 0; + if (chunk.value) { + values.push(chunk.value); + } + if (chunk.done) { + done = true; + break; + } } - return this.clients; + if (done && !("content-length" in resHeaderRecord)) { + resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0); + } + } + outgoing.writeHead(res.status, resHeaderRecord); + values.forEach((value) => { + ; + outgoing.write(value); }); + if (done) { + outgoing.end(); + } else { + if (values.length === 0) { + flushHeaders(outgoing); + } + await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise); + } + } else if (resHeaderRecord[X_ALREADY_SENT]) { + } else { + outgoing.writeHead(res.status, resHeaderRecord); + outgoing.end(); } - __publish__(message) { - var _this = this; - return _asyncToGenerator2(function* () { - var client; - var _ref = yield _this.ready; - client = _ref.client; - return client.publish(_this.instance.channel(), `message:${message.toString()}`); - })(); + ; + outgoing[outgoingEnded]?.(); + }; + getRequestListener = (fetchCallback, options2 = {}) => { + const autoCleanupIncoming = options2.autoCleanupIncoming ?? true; + if (options2.overrideGlobalObjects !== false && global.Request !== Request2) { + Object.defineProperty(global, "Request", { + value: Request2 + }); + Object.defineProperty(global, "Response", { + value: Response2 + }); } - onMessage(channel, message) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var capacity, counter, data, drained, e2, newCapacity, pos, priorityClient, rawCapacity, type; - try { - pos = message.indexOf(":"); - var _ref2 = [message.slice(0, pos), message.slice(pos + 1)]; - type = _ref2[0]; - data = _ref2[1]; - if (type === "capacity") { - return yield _this2.instance._drainAll(data.length > 0 ? ~~data : void 0); - } else if (type === "capacity-priority") { - var _data$split = data.split(":"); - var _data$split2 = _slicedToArray2(_data$split, 3); - rawCapacity = _data$split2[0]; - priorityClient = _data$split2[1]; - counter = _data$split2[2]; - capacity = rawCapacity.length > 0 ? ~~rawCapacity : void 0; - if (priorityClient === _this2.clientId) { - drained = yield _this2.instance._drainAll(capacity); - newCapacity = capacity != null ? capacity - (drained || 0) : ""; - return yield _this2.clients.client.publish(_this2.instance.channel(), `capacity-priority:${newCapacity}::${counter}`); - } else if (priorityClient === "") { - clearTimeout(_this2.capacityPriorityCounters[counter]); - delete _this2.capacityPriorityCounters[counter]; - return _this2.instance._drainAll(capacity); - } else { - return _this2.capacityPriorityCounters[counter] = setTimeout( - /* @__PURE__ */ _asyncToGenerator2(function* () { - var e3; - try { - delete _this2.capacityPriorityCounters[counter]; - yield _this2.runScript("blacklist_client", [priorityClient]); - return yield _this2.instance._drainAll(capacity); - } catch (error2) { - e3 = error2; - return _this2.instance.Events.trigger("error", e3); + return async (incoming, outgoing) => { + let res, req; + try { + req = newRequest(incoming, options2.hostname); + let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD"; + if (!incomingEnded) { + ; + incoming[wrapBodyStream] = true; + incoming.on("end", () => { + incomingEnded = true; + }); + if (incoming instanceof Http2ServerRequest2) { + ; + outgoing[outgoingEnded] = () => { + if (!incomingEnded) { + setTimeout(() => { + if (!incomingEnded) { + setTimeout(() => { + drainIncoming(incoming); + }); } - }), - 1e3 - ); + }); + } + }; + } + outgoing.on("finish", () => { + if (!incomingEnded) { + drainIncoming(incoming); + } + }); + } + outgoing.on("close", () => { + const abortController = req[abortControllerKey]; + if (abortController) { + if (incoming.errored) { + req[abortControllerKey].abort(incoming.errored.toString()); + } else if (!outgoing.writableFinished) { + req[abortControllerKey].abort("Client connection prematurely closed."); } - } else if (type === "message") { - return _this2.instance.Events.trigger("message", data); - } else if (type === "blocked") { - return yield _this2.instance._dropAllQueued(); } - } catch (error2) { - e2 = error2; - return _this2.instance.Events.trigger("error", e2); + if (!incomingEnded) { + setTimeout(() => { + if (!incomingEnded) { + setTimeout(() => { + drainIncoming(incoming); + }); + } + }); + } + }); + res = fetchCallback(req, { incoming, outgoing }); + if (cacheKey in res) { + return responseViaCache(res, outgoing); } - })(); + } catch (e2) { + if (!res) { + if (options2.errorHandler) { + res = await options2.errorHandler(req ? e2 : toRequestError(e2)); + if (!res) { + return; + } + } else if (!req) { + res = handleRequestError(); + } else { + res = handleFetchError(e2); + } + } else { + return handleResponseError(e2, outgoing); + } + } + try { + return await responseViaResponseObject(res, outgoing, options2); + } catch (e2) { + return handleResponseError(e2, outgoing); + } + }; + }; + createAdaptorServer = (options2) => { + const fetchCallback = options2.fetch; + const requestListener = getRequestListener(fetchCallback, { + hostname: options2.hostname, + overrideGlobalObjects: options2.overrideGlobalObjects, + autoCleanupIncoming: options2.autoCleanupIncoming + }); + const createServer2 = options2.createServer || createServerHTTP; + const server = createServer2(options2.serverOptions || {}, requestListener); + return server; + }; + } +}); +var createWorker; +var createWorker_default; +var init_createWorker = __esm({ + "src/serve/createWorker.ts"() { + "use strict"; + init_esm8(); + init_esm(); + Object.defineProperties(Buffer13, { + [serdesDeserializeSymbol]: { + value(buf2) { + return Buffer13.from(buf2); + } + }, + [serdesSerializeSymbol]: { + value(buf2) { + return new Uint8Array(buf2.buffer, buf2.byteOffset, buf2.byteLength); + } + }, + [serdesTagSymbol]: { + value: "node:buffer" } - __disconnect__(flush) { - clearInterval(this.heartbeat); - if (this.sharedConnection) { - return this.connection.__removeLimiter__(this.instance); + }); + deserializer.register(Buffer13); + createWorker = (path8) => { + let worker; + let ready; + const launchWorker = () => { + worker = new Worker(new URL(path8, import.meta.url), { type: "module" }); + return new Promise((resolve82, reject) => { + const msgHandler = (event) => { + const msg = event.data; + if (msg === "ready") { + worker.removeEventListener("error", reject, { capture: false }); + worker.addEventListener("error", (ev) => { + const e2 = ev.error; + console.error(e2, `Running worker ${basename52(path8)} terminated. Attempting relaunch...`); + worker.removeEventListener("message", msgHandler, false); + ready = launchWorker().catch((e3) => { + console.error(e3, `Error on worker ${basename52(path8)} relaunch`); + process7.exit(1); + }); + }, false); + resolve82(); + } else if (msg && typeof msg === "object" && msg.type === "sbp" && Array.isArray(msg.data) && String(msg.data[0]).startsWith("chelonia.db/")) { + const port = msg.port; + Promise.try(() => esm_default(...deserializer(msg.data))).then((r) => { + const { data, transferables } = serializer(r); + port.postMessage([true, data], transferables); + }).catch((e2) => { + const { data, transferables } = serializer(e2); + port.postMessage([false, data], transferables); + }).finally(() => { + port.close(); + }); + } + }; + worker.addEventListener("message", msgHandler, false); + worker.addEventListener("error", reject, { capture: false, once: true }); + }); + }; + ready = launchWorker(); + const rpcSbp = (...args) => { + return ready.then(() => new Promise((resolve82, reject) => { + const mc = new MessageChannel(); + const cleanup = /* @__PURE__ */ ((worker2) => () => { + worker2.removeEventListener("error", reject, { capture: true }); + mc.port2.close(); + mc.port2.onmessage = null; + mc.port2.onmessageerror = null; + })(worker); + mc.port2.onmessage = (event) => { + cleanup(); + const [success, result] = event.data; + if (success) return resolve82(result); + reject(result); + }; + mc.port2.onmessageerror = () => { + cleanup(); + reject(new Error("Message error")); + }; + worker.postMessage([mc.port1, ...args], [mc.port1]); + worker.addEventListener("error", reject, { capture: false, once: true }); + })); + }; + return { + ready, + rpcSbp, + terminate: () => worker.terminate() + }; + }; + createWorker_default = createWorker; + } +}); +var CREDITS_WORKER_TASK_TIME_INTERVAL; +var OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL; +var init_constants4 = __esm({ + "src/serve/constants.ts"() { + "use strict"; + CREDITS_WORKER_TASK_TIME_INTERVAL = 3e5; + OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL = 3e4; + } +}); +var rfc8291Ikm_default; +var init_rfc8291Ikm = __esm({ + "src/serve/rfc8291Ikm.ts"() { + "use strict"; + rfc8291Ikm_default = async (uaPublic, salt) => { + const [[asPrivateKey, asPublic], uaPublicKey] = await Promise.all([ + crypto.subtle.generateKey( + { + name: "ECDH", + namedCurve: "P-256" + }, + false, + ["deriveKey"] + ).then(async (asKeyPair) => { + const asPublic2 = await crypto.subtle.exportKey( + "raw", + asKeyPair.publicKey + ); + return [asKeyPair.privateKey, asPublic2]; + }), + crypto.subtle.importKey( + "raw", + uaPublic, + { name: "ECDH", namedCurve: "P-256" }, + false, + [] + ) + ]); + const ecdhSecret = await crypto.subtle.deriveKey( + { + name: "ECDH", + public: uaPublicKey + }, + asPrivateKey, + { + name: "HKDF", + hash: "SHA-256" + }, + false, + ["deriveBits"] + ); + const infoString = new Uint8Array([ + 87, + 101, + 98, + 80, + 117, + 115, + 104, + 58, + 32, + 105, + 110, + 102, + 111, + 0 + ]); + const info = new Uint8Array(infoString.byteLength + uaPublic.byteLength + asPublic.byteLength); + info.set(infoString, 0); + info.set(uaPublic, infoString.byteLength); + info.set( + new Uint8Array(asPublic), + infoString.byteLength + uaPublic.byteLength + ); + const IKM = await crypto.subtle.deriveBits( + { + name: "HKDF", + hash: "SHA-256", + salt, + info + }, + ecdhSecret, + 32 << 3 + ); + return [asPublic, IKM]; + }; + } +}); +var addSubscriptionToIndex; +var deleteSubscriptionFromIndex; +var saveSubscription; +var addChannelToSubscription; +var deleteChannelFromSubscription; +var removeSubscription; +var subscriptionInfoWrapper; +var encryptPayload; +var postEvent; +var pushServerActionhandlers; +var init_push = __esm({ + "src/serve/push.ts"() { + "use strict"; + init_encodings(); + init_encrypt(); + init_functions(); + init_pubsub(); + init_esm(); + init_database(); + init_instance_keys(); + init_rfc8291Ikm(); + init_vapid(); + addSubscriptionToIndex = appendToIndexFactory("_private_webpush_index"); + deleteSubscriptionFromIndex = removeFromIndexFactory("_private_webpush_index"); + saveSubscription = (server, subscriptionId) => { + return esm_default("chelonia.db/set", `_private_webpush_${subscriptionId}`, JSON.stringify({ + settings: server.pushSubscriptions[subscriptionId].settings, + subscriptionInfo: server.pushSubscriptions[subscriptionId], + channelIDs: [...server.pushSubscriptions[subscriptionId].subscriptions] + })).catch((e2) => { + console.error(e2, "Error saving subscription", subscriptionId); + throw e2; + }); + }; + addChannelToSubscription = (server, subscriptionId, channelID) => { + server.pushSubscriptions[subscriptionId].subscriptions.add(channelID); + return saveSubscription(server, subscriptionId); + }; + deleteChannelFromSubscription = (server, subscriptionId, channelID) => { + server.pushSubscriptions[subscriptionId].subscriptions.delete(channelID); + return saveSubscription(server, subscriptionId); + }; + removeSubscription = async (subscriptionId) => { + try { + const server = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const subscription = server.pushSubscriptions[subscriptionId]; + if (subscription) { + delete server.pushSubscriptions[subscriptionId]; + if (server.subscribersByChannelID) { + subscription.subscriptions.forEach((channelID) => { + server.subscribersByChannelID[channelID]?.delete(subscription); + }); + } } else { - return this.connection.disconnect(flush); } + await esm_default("chelonia.db/delete", `_private_webpush_${subscriptionId}`); + await deleteSubscriptionFromIndex(subscriptionId); + } catch (e2) { + console.error(e2, "Error removing subscription", subscriptionId); } - runScript(name, args) { - var _this3 = this; - return _asyncToGenerator2(function* () { - if (!(name === "init" || name === "register_client")) { - yield _this3.ready; + }; + subscriptionInfoWrapper = (subscriptionId, subscriptionInfo, extra) => { + subscriptionInfo.endpoint = new URL(subscriptionInfo.endpoint); + Object.defineProperties(subscriptionInfo, { + "id": { + get() { + return subscriptionId; } - return new _this3.Promise((resolve82, reject) => { - var all_args, arr; - all_args = [Date.now(), _this3.clientId].concat(args); - _this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args); - arr = _this3.connection.__scriptArgs__(name, _this3.originalId, all_args, function(err, replies) { - if (err != null) { - return reject(err); - } - return resolve82(replies); - }); - return _this3.connection.__scriptFn__(name)(...arr); - }).catch((e2) => { - if (e2.message === "SETTINGS_KEY_NOT_FOUND") { - if (name === "heartbeat") { - return _this3.Promise.resolve(); + }, + // These encryption keys are used for encrypting push notification bodies + // and are unrelated to VAPID, which is used for provenance. + "encryptionKeys": { + get: /* @__PURE__ */ (() => { + let count = 0; + let resultPromise; + let salt; + let uaPublic; + return function() { + if ((count | 0) === 0) { + if (!salt) { + salt = Buffer14.from(this.keys.auth, "base64url"); + } + if (!uaPublic) { + uaPublic = Buffer14.from(this.keys.p256dh, "base64url"); + } + resultPromise = rfc8291Ikm_default(uaPublic, salt); + count = 1; } else { - return _this3.runScript("init", _this3.prepareInitSettings(false)).then(() => { - return _this3.runScript(name, args); - }); + count++; } - } else if (e2.message === "UNKNOWN_CLIENT") { - return _this3.runScript("register_client", [_this3.instance.queued()]).then(() => { - return _this3.runScript(name, args); - }); - } else { - return _this3.Promise.reject(e2); + return resultPromise; + }; + })() + }, + "settings": { + value: extra.settings || {} + }, + "sockets": { + value: /* @__PURE__ */ new Set() + }, + "subscriptions": { + value: new Set(extra.channelIDs) + } + }); + Object.freeze(subscriptionInfo); + return subscriptionInfo; + }; + encryptPayload = async (subscription, data) => { + const readableStream = new Response(data).body; + if (!readableStream) throw new Error("Failed to create readable stream"); + const [asPublic, IKM] = await subscription.encryptionKeys; + return K(x2, readableStream, 32768, asPublic, IKM).then(async (bodyStream) => { + const chunks = []; + const reader = bodyStream.getReader(); + for (; ; ) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(new Uint8Array(value)); + } + return Buffer14.concat(chunks); + }); + }; + postEvent = async (subscription, event) => { + const authorization = await vapidAuthorization(subscription.endpoint); + const body = event ? await encryptPayload(subscription, event) : void 0; + const req = await fetch(subscription.endpoint, { + method: "POST", + headers: [ + ["authorization", authorization], + ...body ? [ + ["content-encoding", "aes128gcm"], + [ + "content-type", + "application/octet-stream" + ] + ] : [], + // ['push-receipt', ''], + ["ttl", "60"] + ], + body + }); + if (!req.ok) { + const endpointHost = new URL(subscription.endpoint).host; + console.info( + await req.text().then((response) => ({ response })).catch((e2) => `ERR: ${e2?.message}`), + `Error ${req.status} sending push notification to '${subscription.id}' via ${endpointHost}` + ); + if ([401, 404, 410].includes(req.status)) { + removeSubscription(subscription.id); + throw new Error(`Error sending push: ${req.status}`); + } + if (req.status === 413) { + throw new Error("Payload too large"); + } + } + }; + pushServerActionhandlers = { + [PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY]() { + const socket = this; + socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); + }, + async [PUSH_SERVER_ACTION_TYPE.STORE_SUBSCRIPTION](payload) { + const socket = this; + const { server } = socket; + const { applicationServerKey, settings, subscriptionInfo } = payload; + if (applicationServerKey) { + const ourVapidPublicKey = getVapidPublicKey(); + const theirVapidPublicKey = Buffer14.from(applicationServerKey, "base64").toString("base64url"); + if (ourVapidPublicKey !== theirVapidPublicKey) { + socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); + console.warn({ ourVapidPublicKey, theirVapidPublicKey }, "Refusing to store subscription because the associated public VAPID key does not match ours"); + return; + } + } + let subscriptionId = null; + let host = ""; + let subscriptionWrapper = null; + try { + subscriptionId = await getSubscriptionId(subscriptionInfo); + subscriptionWrapper = server.pushSubscriptions[subscriptionId]; + if (!subscriptionWrapper) { + console.debug(`saving new push subscription '${subscriptionId}':`, subscriptionInfo); + server.pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { settings }); + subscriptionWrapper = server.pushSubscriptions[subscriptionId]; + host = subscriptionWrapper.endpoint.host; + await addSubscriptionToIndex(subscriptionId); + await saveSubscription(server, subscriptionId); + await postEvent(subscriptionWrapper, JSON.stringify({ type: "initial" })); + } else { + host = subscriptionWrapper.endpoint.host; + if (subscriptionWrapper.sockets.size === 0) { + subscriptionWrapper.subscriptions.forEach((channelID) => { + if (!server.subscribersByChannelID[channelID]) return; + server.subscribersByChannelID[channelID].delete(subscriptionWrapper); + }); } + } + if (socket.pushSubscriptionId) { + if (socket.pushSubscriptionId === subscriptionId) return; + await removeSubscription(socket.pushSubscriptionId); + } + socket.pushSubscriptionId = subscriptionId; + subscriptionWrapper.subscriptions.forEach((channelID) => { + server.subscribersByChannelID[channelID]?.delete(subscriptionWrapper); }); - })(); - } - prepareArray(arr) { - var i2, len, results, x3; - results = []; - for (i2 = 0, len = arr.length; i2 < len; i2++) { - x3 = arr[i2]; - results.push(x3 != null ? x3.toString() : ""); + subscriptionWrapper.sockets.add(socket); + socket.subscriptions?.forEach((channelID) => { + subscriptionWrapper.subscriptions.add(channelID); + }); + await saveSubscription(server, subscriptionId); + } catch (e2) { + console.error(e2, `[${socket.ip}] Failed to store subscription '${subscriptionId || "??"}' (${host}), removing it!`); + subscriptionId && removeSubscription(subscriptionId); + throw e2; } - return results; - } - prepareObject(obj) { - var arr, k, v2; - arr = []; - for (k in obj) { - v2 = obj[k]; - arr.push(k, v2 != null ? v2.toString() : ""); + }, + [PUSH_SERVER_ACTION_TYPE.DELETE_SUBSCRIPTION]() { + const socket = this; + const { pushSubscriptionId: subscriptionId } = socket; + if (subscriptionId) { + return removeSubscription(subscriptionId); } - return arr; - } - prepareInitSettings(clear) { - var args; - args = this.prepareObject(Object.assign({}, this.storeOptions, { - id: this.originalId, - version: this.instance.version, - groupTimeout: this.timeout, - clientTimeout: this.clientTimeout - })); - args.unshift(clear ? 1 : 0, this.instance.version); - return args; } - convertBool(b) { - return !!b; - } - __updateSettings__(options2) { - var _this4 = this; - return _asyncToGenerator2(function* () { - yield _this4.runScript("update_settings", _this4.prepareObject(options2)); - return parser3.overwrite(options2, options2, _this4.storeOptions); - })(); + }; + } +}); +var require_stream = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/stream.js"(exports2, module14) { + "use strict"; + var { Duplex } = __require2("stream"); + function emitClose(stream) { + stream.emit("close"); + } + function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); } - __running__() { - return this.runScript("running", []); + } + function duplexOnError(err) { + this.removeListener("error", duplexOnError); + this.destroy(); + if (this.listenerCount("error") === 0) { + this.emit("error", err); } - __queued__() { - return this.runScript("queued", []); + } + function createWebSocketStream2(ws, options2) { + let terminateOnDestroy = true; + const duplex = new Duplex({ + ...options2, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + ws.on("message", function message(msg, isBinary) { + const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + if (!duplex.push(data)) ws.pause(); + }); + ws.once("error", function error2(err) { + if (duplex.destroyed) return; + terminateOnDestroy = false; + duplex.destroy(err); + }); + ws.once("close", function close() { + if (duplex.destroyed) return; + duplex.push(null); + }); + duplex._destroy = function(err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose, duplex); + return; + } + let called = false; + ws.once("error", function error2(err2) { + called = true; + callback(err2); + }); + ws.once("close", function close() { + if (!called) callback(err); + process.nextTick(emitClose, duplex); + }); + if (terminateOnDestroy) ws.terminate(); + }; + duplex._final = function(callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open2() { + duplex._final(callback); + }); + return; + } + if (ws._socket === null) return; + if (ws._socket._writableState.finished) { + callback(); + if (duplex._readableState.endEmitted) duplex.destroy(); + } else { + ws._socket.once("finish", function finish() { + callback(); + }); + ws.close(); + } + }; + duplex._read = function() { + if (ws.isPaused) ws.resume(); + }; + duplex._write = function(chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open2() { + duplex._write(chunk, encoding, callback); + }); + return; + } + ws.send(chunk, callback); + }; + duplex.on("end", duplexOnEnd); + duplex.on("error", duplexOnError); + return duplex; + } + module14.exports = createWebSocketStream2; + } +}); +var require_constants2 = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/constants.js"(exports2, module14) { + "use strict"; + module14.exports = { + BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], + EMPTY_BUFFER: Buffer.alloc(0), + GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), + kListener: Symbol("kListener"), + kStatusCode: Symbol("status-code"), + kWebSocket: Symbol("websocket"), + NOOP: () => { } - __done__() { - return this.runScript("done", []); + }; + } +}); +var require_buffer_util = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/buffer-util.js"(exports2, module14) { + "use strict"; + var { EMPTY_BUFFER } = require_constants2(); + function concat2(list, totalLength) { + if (list.length === 0) return EMPTY_BUFFER; + if (list.length === 1) return list[0]; + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + for (let i2 = 0; i2 < list.length; i2++) { + const buf2 = list[i2]; + target.set(buf2, offset); + offset += buf2.length; } - __groupCheck__() { - var _this5 = this; - return _asyncToGenerator2(function* () { - return _this5.convertBool(yield _this5.runScript("group_check", [])); - })(); + if (offset < totalLength) return target.slice(0, offset); + return target; + } + function _mask(source, mask, output, offset, length2) { + for (let i2 = 0; i2 < length2; i2++) { + output[offset + i2] = source[i2] ^ mask[i2 & 3]; } - __incrementReservoir__(incr) { - return this.runScript("increment_reservoir", [incr]); + } + function _unmask(buffer, mask) { + for (let i2 = 0; i2 < buffer.length; i2++) { + buffer[i2] ^= mask[i2 & 3]; } - __currentReservoir__() { - return this.runScript("current_reservoir", []); + } + function toArrayBuffer(buf2) { + if (buf2.byteLength === buf2.buffer.byteLength) { + return buf2.buffer; } - __check__(weight) { - var _this6 = this; - return _asyncToGenerator2(function* () { - return _this6.convertBool(yield _this6.runScript("check", _this6.prepareArray([weight]))); - })(); + return buf2.buffer.slice(buf2.byteOffset, buf2.byteOffset + buf2.byteLength); + } + function toBuffer(data) { + toBuffer.readOnly = true; + if (Buffer.isBuffer(data)) return data; + let buf2; + if (data instanceof ArrayBuffer) { + buf2 = Buffer.from(data); + } else if (ArrayBuffer.isView(data)) { + buf2 = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } else { + buf2 = Buffer.from(data); + toBuffer.readOnly = false; } - __register__(index, weight, expiration) { - var _this7 = this; - return _asyncToGenerator2(function* () { - var reservoir, success, wait; - var _ref4 = yield _this7.runScript("register", _this7.prepareArray([index, weight, expiration])); - var _ref5 = _slicedToArray2(_ref4, 3); - success = _ref5[0]; - wait = _ref5[1]; - reservoir = _ref5[2]; - return { - success: _this7.convertBool(success), - wait, - reservoir - }; - })(); + return buf2; + } + try { + const bufferUtil = __require2("bufferutil"); + module14.exports = { + concat: concat2, + mask(source, mask, output, offset, length2) { + if (length2 < 48) _mask(source, mask, output, offset, length2); + else bufferUtil.mask(source, mask, output, offset, length2); + }, + toArrayBuffer, + toBuffer, + unmask(buffer, mask) { + if (buffer.length < 32) _unmask(buffer, mask); + else bufferUtil.unmask(buffer, mask); + } + }; + } catch (e2) { + module14.exports = { + concat: concat2, + mask: _mask, + toArrayBuffer, + toBuffer, + unmask: _unmask + }; + } + } +}); +var require_limiter = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/limiter.js"(exports2, module14) { + "use strict"; + var kDone = Symbol("kDone"); + var kRun = Symbol("kRun"); + var Limiter = class { + /** + * Creates a new `Limiter`. + * + * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed + * to run concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; } - __submit__(queueLength, weight) { - var _this8 = this; - return _asyncToGenerator2(function* () { - var blocked, e2, maxConcurrent, overweight, reachedHWM, strategy; - try { - var _ref6 = yield _this8.runScript("submit", _this8.prepareArray([queueLength, weight])); - var _ref7 = _slicedToArray2(_ref6, 3); - reachedHWM = _ref7[0]; - blocked = _ref7[1]; - strategy = _ref7[2]; - return { - reachedHWM: _this8.convertBool(reachedHWM), - blocked: _this8.convertBool(blocked), - strategy - }; - } catch (error2) { - e2 = error2; - if (e2.message.indexOf("OVERWEIGHT") === 0) { - var _e$message$split = e2.message.split(":"); - var _e$message$split2 = _slicedToArray2(_e$message$split, 3); - overweight = _e$message$split2[0]; - weight = _e$message$split2[1]; - maxConcurrent = _e$message$split2[2]; - throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${maxConcurrent}`); - } else { - throw e2; - } - } - })(); + /** + * Adds a job to the queue. + * + * @param {Function} job The job to run + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); } - __free__(index, weight) { - var _this9 = this; - return _asyncToGenerator2(function* () { - var running; - running = yield _this9.runScript("free", _this9.prepareArray([index])); - return { - running - }; - })(); + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) return; + if (this.jobs.length) { + const job = this.jobs.shift(); + this.pending++; + job(this[kDone]); + } } }; - module14.exports = RedisDatastore; + module14.exports = Limiter; } }); -var require_States = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/States.js"(exports2, module14) { +var require_permessage_deflate = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module14) { "use strict"; - var BottleneckError; - var States; - BottleneckError = require_BottleneckError(); - States = class States { - constructor(status1) { - this.status = status1; - this._jobs = {}; - this.counts = this.status.map(function() { - return 0; - }); + var zlib = __require2("zlib"); + var bufferUtil = require_buffer_util(); + var Limiter = require_limiter(); + var { kStatusCode } = require_constants2(); + var TRAILER = Buffer.from([0, 0, 255, 255]); + var kPerMessageDeflate = Symbol("permessage-deflate"); + var kTotalLength = Symbol("total-length"); + var kCallback = Symbol("callback"); + var kBuffers = Symbol("buffers"); + var kError = Symbol("error"); + var zlibLimiter; + var PerMessageDeflate = class { + /** + * Creates a PerMessageDeflate instance. + * + * @param {Object} [options] Configuration options + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size + * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ + * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib + * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the + * use of a custom server window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled + * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on + * deflate + * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on + * inflate + * @param {Boolean} [isServer=false] Create the instance in either server or + * client mode + * @param {Number} [maxPayload=0] The maximum allowed message length + */ + constructor(options2, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; + this._options = options2 || {}; + this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; + this._isServer = !!isServer; + this._deflate = null; + this._inflate = null; + this.params = null; + if (!zlibLimiter) { + const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; + zlibLimiter = new Limiter(concurrency); + } } - next(id) { - var current, next; - current = this._jobs[id]; - next = current + 1; - if (current != null && next < this.status.length) { - this.counts[current]--; - this.counts[next]++; - return this._jobs[id]++; - } else if (current != null) { - this.counts[current]--; - return delete this._jobs[id]; + /** + * @type {String} + */ + static get extensionName() { + return "permessage-deflate"; + } + /** + * Create an extension negotiation offer. + * + * @return {Object} Extension parameters + * @public + */ + offer() { + const params = {}; + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + return params; + } + /** + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public + */ + accept(configurations) { + configurations = this.normalizeParams(configurations); + this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); + return this.params; + } + /** + * Releases all resources used by the extension. + * + * @public + */ + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + if (this._deflate) { + const callback = this._deflate[kCallback]; + this._deflate.close(); + this._deflate = null; + if (callback) { + callback( + new Error( + "The deflate stream was closed while data was being processed" + ) + ); + } + } + } + /** + * Accept an extension negotiation offer. + * + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private + */ + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { + return false; + } + return true; + }); + if (!accepted) { + throw new Error("None of the extension offers can be accepted"); + } + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; } - } - start(id) { - var initial; - initial = 0; - this._jobs[id] = initial; - return this.counts[initial]++; - } - remove(id) { - var current; - current = this._jobs[id]; - if (current != null) { - this.counts[current]--; - delete this._jobs[id]; + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; } - return current != null; - } - jobStatus(id) { - var ref; - return (ref = this.status[this._jobs[id]]) != null ? ref : null; + if (typeof opts.serverMaxWindowBits === "number") { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === "number") { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { + delete accepted.client_max_window_bits; + } + return accepted; } - statusJobs(status) { - var k, pos, ref, results, v2; - if (status != null) { - pos = this.status.indexOf(status); - if (pos < 0) { - throw new BottleneckError(`status must be one of ${this.status.join(", ")}`); - } - ref = this._jobs; - results = []; - for (k in ref) { - v2 = ref[k]; - if (v2 === pos) { - results.push(k); - } + /** + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private + */ + acceptAsClient(response) { + const params = response[0]; + if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === "number") { + params.client_max_window_bits = this._options.clientMaxWindowBits; } - return results; - } else { - return Object.keys(this._jobs); + } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); } + return params; } - statusCounts() { - return this.counts.reduce((acc, v2, i2) => { - acc[this.status[i2]] = v2; - return acc; - }, {}); + /** + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private + */ + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + value = value[0]; + if (key === "client_max_window_bits") { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === "server_max_window_bits") { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + params[key] = value; + }); + }); + return configurations; } - }; - module14.exports = States; - } -}); -var require_Sync = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Sync.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + /** + * Decompress data. Concurrency limited. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + /** + * Compress data. Concurrency limited. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + /** + * Decompress data. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _decompress(data, fin, callback) { + const endpoint = this._isServer ? "client" : "server"; + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on("error", inflateOnError); + this._inflate.on("data", inflateOnData); + } + this._inflate[kCallback] = callback; + this._inflate.write(data); + if (fin) this._inflate.write(TRAILER); + this._inflate.flush(() => { + const err = this._inflate[kError]; + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + const data2 = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + if (this._inflate._readableState.endEmitted) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.reset(); + } } - _next(void 0); + callback(null, data2); }); - }; - } - var DLList; - var Sync; - DLList = require_DLList(); - Sync = class Sync { - constructor(name, Promise2) { - this.schedule = this.schedule.bind(this); - this.name = name; - this.Promise = Promise2; - this._running = 0; - this._queue = new DLList(); - } - isEmpty() { - return this._queue.length === 0; } - _tryToRun() { - var _this = this; - return _asyncToGenerator2(function* () { - var args, cb, error2, reject, resolve82, returned, task; - if (_this._running < 1 && _this._queue.length > 0) { - _this._running++; - var _this$_queue$shift = _this._queue.shift(); - task = _this$_queue$shift.task; - args = _this$_queue$shift.args; - resolve82 = _this$_queue$shift.resolve; - reject = _this$_queue$shift.reject; - cb = yield _asyncToGenerator2(function* () { - try { - returned = yield task(...args); - return function() { - return resolve82(returned); - }; - } catch (error1) { - error2 = error1; - return function() { - return reject(error2); - }; - } - })(); - _this._running--; - _this._tryToRun(); - return cb(); + /** + * Compress data. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _compress(data, fin, callback) { + const endpoint = this._isServer ? "server" : "client"; + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + this._deflate.on("data", deflateOnData); + } + this._deflate[kCallback] = callback; + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + return; } - })(); - } - schedule(task, ...args) { - var promise, reject, resolve82; - resolve82 = reject = null; - promise = new this.Promise(function(_resolve, _reject) { - resolve82 = _resolve; - return reject = _reject; - }); - this._queue.push({ - task, - args, - resolve: resolve82, - reject + let data2 = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + if (fin) data2 = data2.slice(0, data2.length - 4); + this._deflate[kCallback] = null; + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.reset(); + } + callback(null, data2); }); - this._tryToRun(); - return promise; } }; - module14.exports = Sync; - } -}); -var require_version = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/version.json"(exports2, module14) { - module14.exports = { version: "2.19.5" }; + module14.exports = PerMessageDeflate; + function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; + } + function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { + this[kBuffers].push(chunk); + return; + } + this[kError] = new RangeError("Max payload size exceeded"); + this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; + this[kError][kStatusCode] = 1009; + this.removeListener("data", inflateOnData); + this.reset(); + } + function inflateOnError(err) { + this[kPerMessageDeflate]._inflate = null; + err[kStatusCode] = 1007; + this[kCallback](err); + } } }); -var require_Group = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Group.js"(exports2, module14) { +var require_validation = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/validation.js"(exports2, module14) { "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); - } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + var tokenChars = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 0 - 15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 16 - 31 + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + // 32 - 47 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // 48 - 63 + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 64 - 79 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + // 80 - 95 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 96 - 111 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0 + // 112 - 127 + ]; + function isValidStatusCode(code2) { + return code2 >= 1e3 && code2 <= 1014 && code2 !== 1004 && code2 !== 1005 && code2 !== 1006 || code2 >= 3e3 && code2 <= 4999; + } + function _isValidUTF8(buf2) { + const len = buf2.length; + let i2 = 0; + while (i2 < len) { + if ((buf2[i2] & 128) === 0) { + i2++; + } else if ((buf2[i2] & 224) === 192) { + if (i2 + 1 === len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2] & 254) === 192) { + return false; + } + i2 += 2; + } else if ((buf2[i2] & 240) === 224) { + if (i2 + 2 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || buf2[i2] === 224 && (buf2[i2 + 1] & 224) === 128 || // Overlong + buf2[i2] === 237 && (buf2[i2 + 1] & 224) === 160) { + return false; + } + i2 += 3; + } else if ((buf2[i2] & 248) === 240) { + if (i2 + 3 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || (buf2[i2 + 3] & 192) !== 128 || buf2[i2] === 240 && (buf2[i2 + 1] & 240) === 128 || // Overlong + buf2[i2] === 244 && buf2[i2 + 1] > 143 || buf2[i2] > 244) { + return false; + } + i2 += 4; + } else { + return false; } } - return _arr; + return true; } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; + try { + const isValidUTF8 = __require2("utf-8-validate"); + module14.exports = { + isValidStatusCode, + isValidUTF8(buf2) { + return buf2.length < 150 ? _isValidUTF8(buf2) : isValidUTF8(buf2); + }, + tokenChars + }; + } catch (e2) { + module14.exports = { + isValidStatusCode, + isValidUTF8: _isValidUTF8, + tokenChars + }; } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + } +}); +var require_receiver = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/receiver.js"(exports2, module14) { + "use strict"; + var { Writable } = __require2("stream"); + var PerMessageDeflate = require_permessage_deflate(); + var { + BINARY_TYPES, + EMPTY_BUFFER, + kStatusCode, + kWebSocket + } = require_constants2(); + var { concat: concat2, toArrayBuffer, unmask } = require_buffer_util(); + var { isValidStatusCode, isValidUTF8 } = require_validation(); + var GET_INFO = 0; + var GET_PAYLOAD_LENGTH_16 = 1; + var GET_PAYLOAD_LENGTH_64 = 2; + var GET_MASK = 3; + var GET_DATA = 4; + var INFLATING = 5; + var Receiver2 = class extends Writable { + /** + * Creates a Receiver instance. + * + * @param {Object} [options] Options object + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + */ + constructor(options2 = {}) { + super(); + this._binaryType = options2.binaryType || BINARY_TYPES[0]; + this._extensions = options2.extensions || {}; + this._isServer = !!options2.isServer; + this._maxPayload = options2.maxPayload | 0; + this._skipUTF8Validation = !!options2.skipUTF8Validation; + this[kWebSocket] = void 0; + this._bufferedBytes = 0; + this._buffers = []; + this._compressed = false; + this._payloadLength = 0; + this._mask = void 0; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragments = []; + this._state = GET_INFO; + this._loop = false; } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + /** + * Implements `Writable.prototype._write()`. + * + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + * @private + */ + _write(chunk, encoding, cb) { + if (this._opcode === 8 && this._state == GET_INFO) return cb(); + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + /** + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private + */ + consume(n) { + this._bufferedBytes -= n; + if (n === this._buffers[0].length) return this._buffers.shift(); + if (n < this._buffers[0].length) { + const buf2 = this._buffers[0]; + this._buffers[0] = buf2.slice(n); + return buf2.slice(0, n); + } + const dst = Buffer.allocUnsafe(n); + do { + const buf2 = this._buffers[0]; + const offset = dst.length - n; + if (n >= buf2.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf2.buffer, buf2.byteOffset, n), offset); + this._buffers[0] = buf2.slice(n); } - _next(void 0); - }); - }; - } - var Events2; - var Group; - var IORedisConnection2; - var RedisConnection2; - var Scripts2; - var parser3; - parser3 = require_parser2(); - Events2 = require_Events(); - RedisConnection2 = require_RedisConnection(); - IORedisConnection2 = require_IORedisConnection(); - Scripts2 = require_Scripts(); - Group = function() { - class Group2 { - constructor(limiterOptions = {}) { - this.deleteKey = this.deleteKey.bind(this); - this.limiterOptions = limiterOptions; - parser3.load(this.limiterOptions, this.defaults, this); - this.Events = new Events2(this); - this.instances = {}; - this.Bottleneck = require_Bottleneck(); - this._startAutoCleanup(); - this.sharedConnection = this.connection != null; - if (this.connection == null) { - if (this.limiterOptions.datastore === "redis") { - this.connection = new RedisConnection2(Object.assign({}, this.limiterOptions, { - Events: this.Events - })); - } else if (this.limiterOptions.datastore === "ioredis") { - this.connection = new IORedisConnection2(Object.assign({}, this.limiterOptions, { - Events: this.Events - })); - } + n -= buf2.length; + } while (n > 0); + return dst; + } + /** + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private + */ + startLoop(cb) { + let err; + this._loop = true; + do { + switch (this._state) { + case GET_INFO: + err = this.getInfo(); + break; + case GET_PAYLOAD_LENGTH_16: + err = this.getPayloadLength16(); + break; + case GET_PAYLOAD_LENGTH_64: + err = this.getPayloadLength64(); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + err = this.getData(cb); + break; + default: + this._loop = false; + return; } + } while (this._loop); + cb(err); + } + /** + * Reads the first two bytes of a frame. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getInfo() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; } - key(key = "") { - var ref; - return (ref = this.instances[key]) != null ? ref : (() => { - var limiter; - limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { - id: `${this.id}-${key}`, - timeout: this.timeout, - connection: this.connection - })); - this.Events.trigger("created", limiter, key); - return limiter; - })(); + const buf2 = this.consume(2); + if ((buf2[0] & 48) !== 0) { + this._loop = false; + return error2( + RangeError, + "RSV2 and RSV3 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_2_3" + ); } - deleteKey(key = "") { - var _this = this; - return _asyncToGenerator2(function* () { - var deleted, instance; - instance = _this.instances[key]; - if (_this.connection) { - deleted = yield _this.connection.__runCommand__(["del", ...Scripts2.allKeys(`${_this.id}-${key}`)]); - } - if (instance != null) { - delete _this.instances[key]; - yield instance.disconnect(); - } - return instance != null || deleted > 0; - })(); + const compressed = (buf2[0] & 64) === 64; + if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); } - limiters() { - var k, ref, results, v2; - ref = this.instances; - results = []; - for (k in ref) { - v2 = ref[k]; - results.push({ - key: k, - limiter: v2 - }); + this._fin = (buf2[0] & 128) === 128; + this._opcode = buf2[0] & 15; + this._payloadLength = buf2[1] & 127; + if (this._opcode === 0) { + if (compressed) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); } - return results; - } - keys() { - return Object.keys(this.instances); - } - clusterKeys() { - var _this2 = this; - return _asyncToGenerator2(function* () { - var cursor, end, found, i2, k, keys, len, next, start; - if (_this2.connection == null) { - return _this2.Promise.resolve(_this2.keys()); - } - keys = []; - cursor = null; - start = `b_${_this2.id}-`.length; - end = "_settings".length; - while (cursor !== 0) { - var _ref = yield _this2.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${_this2.id}-*_settings`, "count", 1e4]); - var _ref2 = _slicedToArray2(_ref, 2); - next = _ref2[0]; - found = _ref2[1]; - cursor = ~~next; - for (i2 = 0, len = found.length; i2 < len; i2++) { - k = found[i2]; - keys.push(k.slice(start, -end)); - } - } - return keys; - })(); - } - _startAutoCleanup() { - var _this3 = this; - var base2; - clearInterval(this.interval); - return typeof (base2 = this.interval = setInterval( - /* @__PURE__ */ _asyncToGenerator2(function* () { - var e2, k, ref, results, time3, v2; - time3 = Date.now(); - ref = _this3.instances; - results = []; - for (k in ref) { - v2 = ref[k]; - try { - if (yield v2._store.__groupCheck__(time3)) { - results.push(_this3.deleteKey(k)); - } else { - results.push(void 0); - } - } catch (error2) { - e2 = error2; - results.push(v2.Events.trigger("error", e2)); - } - } - return results; - }), - this.timeout / 2 - )).unref === "function" ? base2.unref() : void 0; - } - updateSettings(options2 = {}) { - parser3.overwrite(options2, this.defaults, this); - parser3.overwrite(options2, options2, this.limiterOptions); - if (options2.timeout != null) { - return this._startAutoCleanup(); + if (!this._fragmented) { + this._loop = false; + return error2( + RangeError, + "invalid opcode 0", + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); } - } - disconnect(flush = true) { - var ref; - if (!this.sharedConnection) { - return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; + this._opcode = this._fragmented; + } else if (this._opcode === 1 || this._opcode === 2) { + if (this._fragmented) { + this._loop = false; + return error2( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); } + this._compressed = compressed; + } else if (this._opcode > 7 && this._opcode < 11) { + if (!this._fin) { + this._loop = false; + return error2( + RangeError, + "FIN must be set", + true, + 1002, + "WS_ERR_EXPECTED_FIN" + ); + } + if (compressed) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + if (this._payloadLength > 125) { + this._loop = false; + return error2( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + } + } else { + this._loop = false; + return error2( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); } - } - ; - Group2.prototype.defaults = { - timeout: 1e3 * 60 * 5, - connection: null, - Promise, - id: "group-key" - }; - return Group2; - }.call(void 0); - module14.exports = Group; - } -}); -var require_Batcher = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Batcher.js"(exports2, module14) { - "use strict"; - var Batcher; - var Events2; - var parser3; - parser3 = require_parser2(); - Events2 = require_Events(); - Batcher = function() { - class Batcher2 { - constructor(options2 = {}) { - this.options = options2; - parser3.load(this.options, this.defaults, this); - this.Events = new Events2(this); - this._arr = []; - this._resetPromise(); - this._lastFlush = Date.now(); - } - _resetPromise() { - return this._promise = new this.Promise((res, rej) => { - return this._resolve = res; - }); - } - _flush() { - clearTimeout(this._timeout); - this._lastFlush = Date.now(); - this._resolve(); - this.Events.trigger("batch", this._arr); - this._arr = []; - return this._resetPromise(); - } - add(data) { - var ret; - this._arr.push(data); - ret = this._promise; - if (this._arr.length === this.maxSize) { - this._flush(); - } else if (this.maxTime != null && this._arr.length === 1) { - this._timeout = setTimeout(() => { - return this._flush(); - }, this.maxTime); + if (!this._fin && !this._fragmented) this._fragmented = this._opcode; + this._masked = (buf2[1] & 128) === 128; + if (this._isServer) { + if (!this._masked) { + this._loop = false; + return error2( + RangeError, + "MASK must be set", + true, + 1002, + "WS_ERR_EXPECTED_MASK" + ); } - return ret; + } else if (this._masked) { + this._loop = false; + return error2( + RangeError, + "MASK must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_MASK" + ); } + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; + else return this.haveLength(); } - ; - Batcher2.prototype.defaults = { - maxTime: null, - maxSize: null, - Promise - }; - return Batcher2; - }.call(void 0); - module14.exports = Batcher; - } -}); -var require_Bottleneck = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Bottleneck.js"(exports2, module14) { - "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); - } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; + /** + * Gets extended payload length (7+16). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength16() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + this._payloadLength = this.consume(2).readUInt16BE(0); + return this.haveLength(); + } + /** + * Gets extended payload length (7+64). + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + getPayloadLength64() { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + const buf2 = this.consume(8); + const num = buf2.readUInt32BE(0); + if (num > Math.pow(2, 53 - 32) - 1) { + this._loop = false; + return error2( + RangeError, + "Unsupported WebSocket frame: payload length > 2^53 - 1", + false, + 1009, + "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" + ); } + this._payloadLength = num * Math.pow(2, 32) + buf2.readUInt32BE(4); + return this.haveLength(); } - return _arr; - } - function _toArray(arr) { - return _arrayWithHoles2(arr) || _iterableToArray(arr) || _nonIterableRest2(); - } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - function _iterableToArray(iter) { - if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); - } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; - } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + /** + * Payload length has been read. + * + * @return {(RangeError|undefined)} A possible error + * @private + */ + haveLength() { + if (this._payloadLength && this._opcode < 8) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + this._loop = false; + return error2( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ); + } + } + if (this._masked) this._state = GET_MASK; + else this._state = GET_DATA; } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + /** + * Reads mask bytes. + * + * @private + */ + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + this._mask = this.consume(4); + this._state = GET_DATA; } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + /** + * Reads data bytes. + * + * @param {Function} cb Callback + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + getData(cb) { + let data = EMPTY_BUFFER; + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + data = this.consume(this._payloadLength); + if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { + unmask(data, this._mask); } - _next(void 0); + } + if (this._opcode > 7) return this.controlMessage(data); + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + if (data.length) { + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + return this.dataMessage(); + } + /** + * Decompresses data. + * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback + * @private + */ + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + perMessageDeflate.decompress(data, this._fin, (err, buf2) => { + if (err) return cb(err); + if (buf2.length) { + this._messageLength += buf2.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + return cb( + error2( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ) + ); + } + this._fragments.push(buf2); + } + const er = this.dataMessage(); + if (er) return cb(er); + this.startLoop(cb); }); - }; - } - var Bottleneck2; - var DEFAULT_PRIORITY; - var Events2; - var Job; - var LocalDatastore; - var NUM_PRIORITIES; - var Queues; - var RedisDatastore; - var States; - var Sync; - var parser3; - var splice = [].splice; - NUM_PRIORITIES = 10; - DEFAULT_PRIORITY = 5; - parser3 = require_parser2(); - Queues = require_Queues(); - Job = require_Job(); - LocalDatastore = require_LocalDatastore(); - RedisDatastore = require_RedisDatastore(); - Events2 = require_Events(); - States = require_States(); - Sync = require_Sync(); - Bottleneck2 = function() { - class Bottleneck3 { - constructor(options2 = {}, ...invalid) { - var storeInstanceOptions, storeOptions; - this._addToQueue = this._addToQueue.bind(this); - this._validateOptions(options2, invalid); - parser3.load(options2, this.instanceDefaults, this); - this._queues = new Queues(NUM_PRIORITIES); - this._scheduled = {}; - this._states = new States(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); - this._limiter = null; - this.Events = new Events2(this); - this._submitLock = new Sync("submit", this.Promise); - this._registerLock = new Sync("register", this.Promise); - storeOptions = parser3.load(options2, this.storeDefaults, {}); - this._store = function() { - if (this.datastore === "redis" || this.datastore === "ioredis" || this.connection != null) { - storeInstanceOptions = parser3.load(options2, this.redisStoreDefaults, {}); - return new RedisDatastore(this, storeOptions, storeInstanceOptions); - } else if (this.datastore === "local") { - storeInstanceOptions = parser3.load(options2, this.localStoreDefaults, {}); - return new LocalDatastore(this, storeOptions, storeInstanceOptions); + } + /** + * Handles a data message. + * + * @return {(Error|undefined)} A possible error + * @private + */ + dataMessage() { + if (this._fin) { + const messageLength = this._messageLength; + const fragments = this._fragments; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._fragments = []; + if (this._opcode === 2) { + let data; + if (this._binaryType === "nodebuffer") { + data = concat2(fragments, messageLength); + } else if (this._binaryType === "arraybuffer") { + data = toArrayBuffer(concat2(fragments, messageLength)); } else { - throw new Bottleneck3.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); + data = fragments; } - }.call(this); - this._queues.on("leftzero", () => { - var ref; - return (ref = this._store.heartbeat) != null ? typeof ref.ref === "function" ? ref.ref() : void 0 : void 0; - }); - this._queues.on("zero", () => { - var ref; - return (ref = this._store.heartbeat) != null ? typeof ref.unref === "function" ? ref.unref() : void 0 : void 0; - }); - } - _validateOptions(options2, invalid) { - if (!(options2 != null && typeof options2 === "object" && invalid.length === 0)) { - throw new Bottleneck3.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); + this.emit("message", data, true); + } else { + const buf2 = concat2(fragments, messageLength); + if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { + this._loop = false; + return error2( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("message", buf2, false); } } - ready() { - return this._store.ready; - } - clients() { - return this._store.clients; + this._state = GET_INFO; + } + /** + * Handles a control message. + * + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + controlMessage(data) { + if (this._opcode === 8) { + this._loop = false; + if (data.length === 0) { + this.emit("conclude", 1005, EMPTY_BUFFER); + this.end(); + } else if (data.length === 1) { + return error2( + RangeError, + "invalid payload length 1", + true, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + } else { + const code2 = data.readUInt16BE(0); + if (!isValidStatusCode(code2)) { + return error2( + RangeError, + `invalid status code ${code2}`, + true, + 1002, + "WS_ERR_INVALID_CLOSE_CODE" + ); + } + const buf2 = data.slice(2); + if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { + return error2( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("conclude", code2, buf2); + this.end(); + } + } else if (this._opcode === 9) { + this.emit("ping", data); + } else { + this.emit("pong", data); } - channel() { - return `b_${this.id}`; + this._state = GET_INFO; + } + }; + module14.exports = Receiver2; + function error2(ErrorCtor, message, prefix, statusCode, errorCode) { + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + Error.captureStackTrace(err, error2); + err.code = errorCode; + err[kStatusCode] = statusCode; + return err; + } + } +}); +var require_sender = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/sender.js"(exports2, module14) { + "use strict"; + var net = __require2("net"); + var tls = __require2("tls"); + var { randomFillSync } = __require2("crypto"); + var PerMessageDeflate = require_permessage_deflate(); + var { EMPTY_BUFFER } = require_constants2(); + var { isValidStatusCode } = require_validation(); + var { mask: applyMask, toBuffer } = require_buffer_util(); + var kByteLength = Symbol("kByteLength"); + var maskBuffer = Buffer.alloc(4); + var Sender2 = class _Sender { + /** + * Creates a Sender instance. + * + * @param {(net.Socket|tls.Socket)} socket The connection socket + * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key + */ + constructor(socket, extensions, generateMask) { + this._extensions = extensions || {}; + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); } - channel_client() { - return `b_${this.id}_${this._store.clientId}`; + this._socket = socket; + this._firstFragment = true; + this._compress = false; + this._bufferedBytes = 0; + this._deflating = false; + this._queue = []; + } + /** + * Frames a piece of data according to the HyBi WebSocket protocol. + * + * @param {(Buffer|String)} data The data to frame + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @return {(Buffer|String)[]} The framed data + * @public + */ + static frame(data, options2) { + let mask; + let merge3 = false; + let offset = 2; + let skipMasking = false; + if (options2.mask) { + mask = options2.maskBuffer || maskBuffer; + if (options2.generateMask) { + options2.generateMask(mask); + } else { + randomFillSync(mask, 0, 4); + } + skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; + offset = 6; } - publish(message) { - return this._store.__publish__(message); + let dataLength; + if (typeof data === "string") { + if ((!options2.mask || skipMasking) && options2[kByteLength] !== void 0) { + dataLength = options2[kByteLength]; + } else { + data = Buffer.from(data); + dataLength = data.length; + } + } else { + dataLength = data.length; + merge3 = options2.mask && options2.readOnly && !skipMasking; } - disconnect(flush = true) { - return this._store.__disconnect__(flush); + let payloadLength = dataLength; + if (dataLength >= 65536) { + offset += 8; + payloadLength = 127; + } else if (dataLength > 125) { + offset += 2; + payloadLength = 126; } - chain(_limiter) { - this._limiter = _limiter; - return this; + const target = Buffer.allocUnsafe(merge3 ? dataLength + offset : offset); + target[0] = options2.fin ? options2.opcode | 128 : options2.opcode; + if (options2.rsv1) target[0] |= 64; + target[1] = payloadLength; + if (payloadLength === 126) { + target.writeUInt16BE(dataLength, 2); + } else if (payloadLength === 127) { + target[2] = target[3] = 0; + target.writeUIntBE(dataLength, 4, 6); } - queued(priority) { - return this._queues.queued(priority); + if (!options2.mask) return [target, data]; + target[1] |= 128; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + if (skipMasking) return [target, data]; + if (merge3) { + applyMask(data, mask, target, offset, dataLength); + return [target]; } - clusterQueued() { - return this._store.__queued__(); + applyMask(data, mask, data, 0, dataLength); + return [target, data]; + } + /** + * Sends a close message to the other peer. + * + * @param {Number} [code] The status code component of the body + * @param {(String|Buffer)} [data] The message component of the body + * @param {Boolean} [mask=false] Specifies whether or not to mask the message + * @param {Function} [cb] Callback + * @public + */ + close(code2, data, mask, cb) { + let buf2; + if (code2 === void 0) { + buf2 = EMPTY_BUFFER; + } else if (typeof code2 !== "number" || !isValidStatusCode(code2)) { + throw new TypeError("First argument must be a valid error code number"); + } else if (data === void 0 || !data.length) { + buf2 = Buffer.allocUnsafe(2); + buf2.writeUInt16BE(code2, 0); + } else { + const length2 = Buffer.byteLength(data); + if (length2 > 123) { + throw new RangeError("The message must not be greater than 123 bytes"); + } + buf2 = Buffer.allocUnsafe(2 + length2); + buf2.writeUInt16BE(code2, 0); + if (typeof data === "string") { + buf2.write(data, 2); + } else { + buf2.set(data, 2); + } } - empty() { - return this.queued() === 0 && this._submitLock.isEmpty(); + const options2 = { + [kByteLength]: buf2.length, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 8, + readOnly: false, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, buf2, false, options2, cb]); + } else { + this.sendFrame(_Sender.frame(buf2, options2), cb); } - running() { - return this._store.__running__(); + } + /** + * Sends a ping message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + ping(data, mask, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - done() { - return this._store.__done__(); + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); } - jobStatus(id) { - return this._states.jobStatus(id); + const options2 = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 9, + readOnly, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options2, cb]); + } else { + this.sendFrame(_Sender.frame(data, options2), cb); } - jobs(status) { - return this._states.statusJobs(status); + } + /** + * Sends a pong message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + pong(data, mask, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - counts() { - return this._states.statusCounts(); + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); } - _randomIndex() { - return Math.random().toString(36).slice(2); + const options2 = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 10, + readOnly, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options2, cb]); + } else { + this.sendFrame(_Sender.frame(data, options2), cb); } - check(weight = 1) { - return this._store.__check__(weight); + } + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} [options.binary=false] Specifies whether `data` is binary + * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` + * @param {Boolean} [options.fin=false] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Function} [cb] Callback + * @public + */ + send(data, options2, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + let opcode = options2.binary ? 2 : 1; + let rsv1 = options2.compress; + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - _clearGlobalState(index) { - if (this._scheduled[index] != null) { - clearTimeout(this._scheduled[index].expiration); - delete this._scheduled[index]; - return true; - } else { - return false; + if (this._firstFragment) { + this._firstFragment = false; + if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { + rsv1 = byteLength >= perMessageDeflate._threshold; } + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; } - _free(index, job, options2, eventInfo) { - var _this = this; - return _asyncToGenerator2(function* () { - var e2, running; - try { - var _ref = yield _this._store.__free__(index, options2.weight); - running = _ref.running; - _this.Events.trigger("debug", `Freed ${options2.id}`, eventInfo); - if (running === 0 && _this.empty()) { - return _this.Events.trigger("idle"); - } - } catch (error1) { - e2 = error1; - return _this.Events.trigger("error", e2); - } - })(); - } - _run(index, job, wait) { - var clearGlobalState, free, run2; - job.doRun(); - clearGlobalState = this._clearGlobalState.bind(this, index); - run2 = this._run.bind(this, index, job); - free = this._free.bind(this, index, job); - return this._scheduled[index] = { - timeout: setTimeout(() => { - return job.doExecute(this._limiter, clearGlobalState, run2, free); - }, wait), - expiration: job.options.expiration != null ? setTimeout(function() { - return job.doExpire(clearGlobalState, run2, free); - }, wait + job.options.expiration) : void 0, - job + if (options2.fin) this._firstFragment = true; + if (perMessageDeflate) { + const opts = { + [kByteLength]: byteLength, + fin: options2.fin, + generateMask: this._generateMask, + mask: options2.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1 }; + if (this._deflating) { + this.enqueue([this.dispatch, data, this._compress, opts, cb]); + } else { + this.dispatch(data, this._compress, opts, cb); + } + } else { + this.sendFrame( + _Sender.frame(data, { + [kByteLength]: byteLength, + fin: options2.fin, + generateMask: this._generateMask, + mask: options2.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1: false + }), + cb + ); } - _drainOne(capacity) { - return this._registerLock.schedule(() => { - var args, index, next, options2, queue; - if (this.queued() === 0) { - return this.Promise.resolve(null); - } - queue = this._queues.getFirst(); - var _next2 = next = queue.first(); - options2 = _next2.options; - args = _next2.args; - if (capacity != null && options2.weight > capacity) { - return this.Promise.resolve(null); - } - this.Events.trigger("debug", `Draining ${options2.id}`, { - args, - options: options2 - }); - index = this._randomIndex(); - return this._store.__register__(index, options2.weight, options2.expiration).then(({ - success, - wait, - reservoir - }) => { - var empty2; - this.Events.trigger("debug", `Drained ${options2.id}`, { - success, - args, - options: options2 - }); - if (success) { - queue.shift(); - empty2 = this.empty(); - if (empty2) { - this.Events.trigger("empty"); - } - if (reservoir === 0) { - this.Events.trigger("depleted", empty2); - } - this._run(index, next, wait); - return this.Promise.resolve(options2.weight); - } else { - return this.Promise.resolve(null); - } - }); - }); + } + /** + * Dispatches a message. + * + * @param {(Buffer|String)} data The message to send + * @param {Boolean} [compress=false] Specifies whether or not to compress + * `data` + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + dispatch(data, compress, options2, cb) { + if (!compress) { + this.sendFrame(_Sender.frame(data, options2), cb); + return; } - _drainAll(capacity, total = 0) { - return this._drainOne(capacity).then((drained) => { - var newCapacity; - if (drained != null) { - newCapacity = capacity != null ? capacity - drained : capacity; - return this._drainAll(newCapacity, total + drained); - } else { - return this.Promise.resolve(total); + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + this._bufferedBytes += options2[kByteLength]; + this._deflating = true; + perMessageDeflate.compress(data, options2.fin, (_, buf2) => { + if (this._socket.destroyed) { + const err = new Error( + "The socket was closed while data was being compressed" + ); + if (typeof cb === "function") cb(err); + for (let i2 = 0; i2 < this._queue.length; i2++) { + const params = this._queue[i2]; + const callback = params[params.length - 1]; + if (typeof callback === "function") callback(err); } - }).catch((e2) => { - return this.Events.trigger("error", e2); - }); + return; + } + this._bufferedBytes -= options2[kByteLength]; + this._deflating = false; + options2.readOnly = false; + this.sendFrame(_Sender.frame(buf2, options2), cb); + this.dequeue(); + }); + } + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (!this._deflating && this._queue.length) { + const params = this._queue.shift(); + this._bufferedBytes -= params[3][kByteLength]; + Reflect.apply(params[0], this, params.slice(1)); } - _dropAllQueued(message) { - return this._queues.shiftAll(function(job) { - return job.doDrop({ - message - }); - }); + } + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[3][kByteLength]; + this._queue.push(params); + } + /** + * Sends a frame. + * + * @param {Buffer[]} list The frame to send + * @param {Function} [cb] Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); } - stop(options2 = {}) { - var done, waitForExecuting; - options2 = parser3.load(options2, this.stopDefaults); - waitForExecuting = (at) => { - var finished; - finished = () => { - var counts; - counts = this._states.counts; - return counts[0] + counts[1] + counts[2] + counts[3] === at; - }; - return new this.Promise((resolve82, reject) => { - if (finished()) { - return resolve82(); - } else { - return this.on("done", () => { - if (finished()) { - this.removeAllListeners("done"); - return resolve82(); - } - }); - } + } + }; + module14.exports = Sender2; + } +}); +var require_event_target = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/event-target.js"(exports2, module14) { + "use strict"; + var { kForOnEventAttribute, kListener } = require_constants2(); + var kCode = Symbol("kCode"); + var kData = Symbol("kData"); + var kError = Symbol("kError"); + var kMessage = Symbol("kMessage"); + var kReason = Symbol("kReason"); + var kTarget = Symbol("kTarget"); + var kType = Symbol("kType"); + var kWasClean = Symbol("kWasClean"); + var Event = class { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @throws {TypeError} If the `type` argument is not specified + */ + constructor(type) { + this[kTarget] = null; + this[kType] = type; + } + /** + * @type {*} + */ + get target() { + return this[kTarget]; + } + /** + * @type {String} + */ + get type() { + return this[kType]; + } + }; + Object.defineProperty(Event.prototype, "target", { enumerable: true }); + Object.defineProperty(Event.prototype, "type", { enumerable: true }); + var CloseEvent = class extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options2 = {}) { + super(type); + this[kCode] = options2.code === void 0 ? 0 : options2.code; + this[kReason] = options2.reason === void 0 ? "" : options2.reason; + this[kWasClean] = options2.wasClean === void 0 ? false : options2.wasClean; + } + /** + * @type {Number} + */ + get code() { + return this[kCode]; + } + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; + } + }; + Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); + Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); + Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); + var ErrorEvent = class extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message + */ + constructor(type, options2 = {}) { + super(type); + this[kError] = options2.error === void 0 ? null : options2.error; + this[kMessage] = options2.message === void 0 ? "" : options2.message; + } + /** + * @type {*} + */ + get error() { + return this[kError]; + } + /** + * @type {String} + */ + get message() { + return this[kMessage]; + } + }; + Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); + Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); + var MessageEvent2 = class extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content + */ + constructor(type, options2 = {}) { + super(type); + this[kData] = options2.data === void 0 ? null : options2.data; + } + /** + * @type {*} + */ + get data() { + return this[kData]; + } + }; + Object.defineProperty(MessageEvent2.prototype, "data", { enumerable: true }); + var EventTarget2 = { + /** + * Register an event listener. + * + * @param {String} type A string representing the event type to listen for + * @param {Function} listener The listener to add + * @param {Object} [options] An options object specifies characteristics about + * the event listener + * @param {Boolean} [options.once=false] A `Boolean` indicating that the + * listener should be invoked at most once after being added. If `true`, + * the listener would be automatically removed when invoked. + * @public + */ + addEventListener(type, listener, options2 = {}) { + let wrapper3; + if (type === "message") { + wrapper3 = function onMessage(data, isBinary) { + const event = new MessageEvent2("message", { + data: isBinary ? data : data.toString() }); + event[kTarget] = this; + listener.call(this, event); }; - done = options2.dropWaitingJobs ? (this._run = function(index, next) { - return next.doDrop({ - message: options2.dropErrorMessage + } else if (type === "close") { + wrapper3 = function onClose(code2, message) { + const event = new CloseEvent("close", { + code: code2, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent }); - }, this._drainOne = () => { - return this.Promise.resolve(null); - }, this._registerLock.schedule(() => { - return this._submitLock.schedule(() => { - var k, ref, v2; - ref = this._scheduled; - for (k in ref) { - v2 = ref[k]; - if (this.jobStatus(v2.job.options.id) === "RUNNING") { - clearTimeout(v2.timeout); - clearTimeout(v2.expiration); - v2.job.doDrop({ - message: options2.dropErrorMessage - }); - } - } - this._dropAllQueued(options2.dropErrorMessage); - return waitForExecuting(0); + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === "error") { + wrapper3 = function onError(error2) { + const event = new ErrorEvent("error", { + error: error2, + message: error2.message }); - })) : this.schedule({ - priority: NUM_PRIORITIES - 1, - weight: 0 - }, () => { - return waitForExecuting(1); - }); - this._receive = function(job) { - return job._reject(new Bottleneck3.prototype.BottleneckError(options2.enqueueErrorMessage)); + event[kTarget] = this; + listener.call(this, event); }; - this.stop = () => { - return this.Promise.reject(new Bottleneck3.prototype.BottleneckError("stop() has already been called")); + } else if (type === "open") { + wrapper3 = function onOpen() { + const event = new Event("open"); + event[kTarget] = this; + listener.call(this, event); }; - return done; + } else { + return; } - _addToQueue(job) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var args, blocked, error2, options2, reachedHWM, shifted, strategy; - args = job.args; - options2 = job.options; - try { - var _ref2 = yield _this2._store.__submit__(_this2.queued(), options2.weight); - reachedHWM = _ref2.reachedHWM; - blocked = _ref2.blocked; - strategy = _ref2.strategy; - } catch (error1) { - error2 = error1; - _this2.Events.trigger("debug", `Could not queue ${options2.id}`, { - args, - options: options2, - error: error2 - }); - job.doDrop({ - error: error2 - }); - return false; + wrapper3[kForOnEventAttribute] = !!options2[kForOnEventAttribute]; + wrapper3[kListener] = listener; + if (options2.once) { + this.once(type, wrapper3); + } else { + this.on(type, wrapper3); + } + }, + /** + * Remove an event listener. + * + * @param {String} type A string representing the event type to remove + * @param {Function} handler The listener to remove + * @public + */ + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { + this.removeListener(type, listener); + break; + } + } + } + }; + module14.exports = { + CloseEvent, + ErrorEvent, + Event, + EventTarget: EventTarget2, + MessageEvent: MessageEvent2 + }; + } +}); +var require_extension = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/extension.js"(exports2, module14) { + "use strict"; + var { tokenChars } = require_validation(); + function push(dest, name, elem) { + if (dest[name] === void 0) dest[name] = [elem]; + else dest[name].push(elem); + } + function parse52(header) { + const offers = /* @__PURE__ */ Object.create(null); + let params = /* @__PURE__ */ Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; + let start = -1; + let code2 = -1; + let end = -1; + let i2 = 0; + for (; i2 < header.length; i2++) { + code2 = header.charCodeAt(i2); + if (extensionName === void 0) { + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); } - if (blocked) { - job.doDrop(); - return true; - } else if (reachedHWM) { - shifted = strategy === Bottleneck3.prototype.strategy.LEAK ? _this2._queues.shiftLastFrom(options2.priority) : strategy === Bottleneck3.prototype.strategy.OVERFLOW_PRIORITY ? _this2._queues.shiftLastFrom(options2.priority + 1) : strategy === Bottleneck3.prototype.strategy.OVERFLOW ? job : void 0; - if (shifted != null) { - shifted.doDrop(); - } - if (shifted == null || strategy === Bottleneck3.prototype.strategy.OVERFLOW) { - if (shifted == null) { - job.doDrop(); - } - return reachedHWM; - } + if (end === -1) end = i2; + const name = header.slice(start, end); + if (code2 === 44) { + push(offers, name, params); + params = /* @__PURE__ */ Object.create(null); + } else { + extensionName = name; } - job.doQueue(reachedHWM, blocked); - _this2._queues.push(job); - yield _this2._drainAll(); - return reachedHWM; - })(); - } - _receive(job) { - if (this._states.jobStatus(job.options.id) != null) { - job._reject(new Bottleneck3.prototype.BottleneckError(`A job with the same id already exists (id=${job.options.id})`)); - return false; + start = end = -1; } else { - job.doReceive(); - return this._submitLock.schedule(this._addToQueue, job); + throw new SyntaxError(`Unexpected character at index ${i2}`); } - } - submit(...args) { - var cb, fn, job, options2, ref, ref1, task; - if (typeof args[0] === "function") { - var _ref3, _ref4, _splice$call, _splice$call2; - ref = args, _ref3 = ref, _ref4 = _toArray(_ref3), fn = _ref4[0], args = _ref4.slice(1), _ref3, _splice$call = splice.call(args, -1), _splice$call2 = _slicedToArray2(_splice$call, 1), cb = _splice$call2[0], _splice$call; - options2 = parser3.load({}, this.jobDefaults); + } else if (paramName === void 0) { + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (code2 === 32 || code2 === 9) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (end === -1) end = i2; + push(params, header.slice(start, end), true); + if (code2 === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + start = end = -1; + } else if (code2 === 61 && start !== -1 && end === -1) { + paramName = header.slice(start, i2); + start = end = -1; } else { - var _ref5, _ref6, _splice$call3, _splice$call4; - ref1 = args, _ref5 = ref1, _ref6 = _toArray(_ref5), options2 = _ref6[0], fn = _ref6[1], args = _ref6.slice(2), _ref5, _splice$call3 = splice.call(args, -1), _splice$call4 = _slicedToArray2(_splice$call3, 1), cb = _splice$call4[0], _splice$call3; - options2 = parser3.load(options2, this.jobDefaults); + throw new SyntaxError(`Unexpected character at index ${i2}`); } - task = (...args2) => { - return new this.Promise(function(resolve82, reject) { - return fn(...args2, function(...args3) { - return (args3[0] != null ? reject : resolve82)(args3); - }); - }); - }; - job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); - job.promise.then(function(args2) { - return typeof cb === "function" ? cb(...args2) : void 0; - }).catch(function(args2) { - if (Array.isArray(args2)) { - return typeof cb === "function" ? cb(...args2) : void 0; + } else { + if (isEscaping) { + if (tokenChars[code2] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (start === -1) start = i2; + else if (!mustUnescape) mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (code2 === 34 && start !== -1) { + inQuotes = false; + end = i2; + } else if (code2 === 92) { + isEscaping = true; } else { - return typeof cb === "function" ? cb(args2) : void 0; + throw new SyntaxError(`Unexpected character at index ${i2}`); } - }); - return this._receive(job); - } - schedule(...args) { - var job, options2, task; - if (typeof args[0] === "function") { - var _args = args; - var _args2 = _toArray(_args); - task = _args2[0]; - args = _args2.slice(1); - options2 = {}; + } else if (code2 === 34 && header.charCodeAt(i2 - 1) === 61) { + inQuotes = true; + } else if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (start !== -1 && (code2 === 32 || code2 === 9)) { + if (end === -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (end === -1) end = i2; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ""); + mustUnescape = false; + } + push(params, paramName, value); + if (code2 === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + paramName = void 0; + start = end = -1; } else { - var _args3 = args; - var _args4 = _toArray(_args3); - options2 = _args4[0]; - task = _args4[1]; - args = _args4.slice(2); + throw new SyntaxError(`Unexpected character at index ${i2}`); } - job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); - this._receive(job); - return job.promise; - } - wrap(fn) { - var schedule, wrapped; - schedule = this.schedule.bind(this); - wrapped = function wrapped2(...args) { - return schedule(fn.bind(this), ...args); - }; - wrapped.withOptions = function(options2, ...args) { - return schedule(options2, fn, ...args); - }; - return wrapped; - } - updateSettings(options2 = {}) { - var _this3 = this; - return _asyncToGenerator2(function* () { - yield _this3._store.__updateSettings__(parser3.overwrite(options2, _this3.storeDefaults)); - parser3.overwrite(options2, _this3.instanceDefaults, _this3); - return _this3; - })(); - } - currentReservoir() { - return this._store.__currentReservoir__(); } - incrementReservoir(incr = 0) { - return this._store.__incrementReservoir__(incr); + } + if (start === -1 || inQuotes || code2 === 32 || code2 === 9) { + throw new SyntaxError("Unexpected end of input"); + } + if (end === -1) end = i2; + const token = header.slice(start, end); + if (extensionName === void 0) { + push(offers, token, params); + } else { + if (paramName === void 0) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, "")); + } else { + push(params, paramName, token); } + push(offers, extensionName, params); } - ; - Bottleneck3.default = Bottleneck3; - Bottleneck3.Events = Events2; - Bottleneck3.version = Bottleneck3.prototype.version = require_version().version; - Bottleneck3.strategy = Bottleneck3.prototype.strategy = { - LEAK: 1, - OVERFLOW: 2, - OVERFLOW_PRIORITY: 4, - BLOCK: 3 - }; - Bottleneck3.BottleneckError = Bottleneck3.prototype.BottleneckError = require_BottleneckError(); - Bottleneck3.Group = Bottleneck3.prototype.Group = require_Group(); - Bottleneck3.RedisConnection = Bottleneck3.prototype.RedisConnection = require_RedisConnection(); - Bottleneck3.IORedisConnection = Bottleneck3.prototype.IORedisConnection = require_IORedisConnection(); - Bottleneck3.Batcher = Bottleneck3.prototype.Batcher = require_Batcher(); - Bottleneck3.prototype.jobDefaults = { - priority: DEFAULT_PRIORITY, - weight: 1, - expiration: null, - id: "" - }; - Bottleneck3.prototype.storeDefaults = { - maxConcurrent: null, - minTime: 0, - highWater: null, - strategy: Bottleneck3.prototype.strategy.LEAK, - penalty: null, - reservoir: null, - reservoirRefreshInterval: null, - reservoirRefreshAmount: null, - reservoirIncreaseInterval: null, - reservoirIncreaseAmount: null, - reservoirIncreaseMaximum: null - }; - Bottleneck3.prototype.localStoreDefaults = { - Promise, - timeout: null, - heartbeatInterval: 250 - }; - Bottleneck3.prototype.redisStoreDefaults = { - Promise, - timeout: null, - heartbeatInterval: 5e3, - clientTimeout: 1e4, - Redis: null, - clientOptions: {}, - clusterNodes: null, - clearDatastore: false, - connection: null - }; - Bottleneck3.prototype.instanceDefaults = { - datastore: "local", - connection: null, - id: "", - rejectOnDrop: true, - trackDoneStatus: false, - Promise - }; - Bottleneck3.prototype.stopDefaults = { - enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", - dropWaitingJobs: true, - dropErrorMessage: "This limiter has been stopped." - }; - return Bottleneck3; - }.call(void 0); - module14.exports = Bottleneck2; + return offers; + } + function format52(extensions) { + return Object.keys(extensions).map((extension) => { + let configurations = extensions[extension]; + if (!Array.isArray(configurations)) configurations = [configurations]; + return configurations.map((params) => { + return [extension].concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) values = [values]; + return values.map((v2) => v2 === true ? k : `${k}=${v2}`).join("; "); + }) + ).join("; "); + }).join(", "); + }).join(", "); + } + module14.exports = { format: format52, parse: parse52 }; } }); -var require_lib36 = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/index.js"(exports2, module14) { +var require_websocket = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket.js"(exports2, module14) { "use strict"; - module14.exports = require_Bottleneck(); - } -}); -var require_package7 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/package.json"(exports2, module14) { - module14.exports = { - name: "joi", - description: "Object schema validation", - version: "18.0.1", - repository: { - url: "git://github.com/hapijs/joi", - type: "git" - }, - engines: { - node: ">= 20" - }, - main: "lib/index.js", - types: "lib/index.d.ts", - browser: "dist/joi-browser.min.js", - files: [ - "lib/**/*", - "dist/*" - ], - keywords: [ - "schema", - "validation" - ], - dependencies: { - "@hapi/address": "^5.1.1", - "@hapi/formula": "^3.0.2", - "@hapi/hoek": "^11.0.7", - "@hapi/pinpoint": "^2.0.1", - "@hapi/tlds": "^1.1.1", - "@hapi/topo": "^6.0.2", - "@standard-schema/spec": "^1.0.0" - }, - devDependencies: { - "@hapi/bourne": "^3.0.0", - "@hapi/code": "^9.0.3", - "@hapi/eslint-plugin": "^7.0.0", - "@hapi/joi-legacy-test": "npm:@hapi/joi@15.x.x", - "@hapi/lab": "^26.0.0", - "@types/node": "^20.17.47", - typescript: "^5.8.3" - }, - scripts: { - prepublishOnly: "cd browser && npm install && npm run build", - test: "lab -t 100 -a @hapi/code -L -Y", - "test-cov-html": "lab -r html -o coverage.html -a @hapi/code" - }, - license: "BSD-3-Clause" - }; - } -}); -var require_schemas2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/schemas.js"(exports2) { - "use strict"; - var Joi2 = require_lib39(); - var internals = {}; - internals.wrap = Joi2.string().min(1).max(2).allow(false); - exports2.preferences = Joi2.object({ - allowUnknown: Joi2.boolean(), - abortEarly: Joi2.boolean(), - artifacts: Joi2.boolean(), - cache: Joi2.boolean(), - context: Joi2.object(), - convert: Joi2.boolean(), - dateFormat: Joi2.valid("date", "iso", "string", "time", "utc"), - debug: Joi2.boolean(), - errors: { - escapeHtml: Joi2.boolean(), - label: Joi2.valid("path", "key", false), - language: [ - Joi2.string(), - Joi2.object().ref() - ], - render: Joi2.boolean(), - stack: Joi2.boolean(), - wrap: { - label: internals.wrap, - array: internals.wrap, - string: internals.wrap - } - }, - externals: Joi2.boolean(), - messages: Joi2.object(), - noDefaults: Joi2.boolean(), - nonEnumerables: Joi2.boolean(), - presence: Joi2.valid("required", "optional", "forbidden"), - skipFunctions: Joi2.boolean(), - stripUnknown: Joi2.object({ - arrays: Joi2.boolean(), - objects: Joi2.boolean() - }).or("arrays", "objects").allow(true, false), - warnings: Joi2.boolean() - }).strict(); - internals.nameRx = /^[a-zA-Z0-9]\w*$/; - internals.rule = Joi2.object({ - alias: Joi2.array().items(Joi2.string().pattern(internals.nameRx)).single(), - args: Joi2.array().items( - Joi2.string(), - Joi2.object({ - name: Joi2.string().pattern(internals.nameRx).required(), - ref: Joi2.boolean(), - assert: Joi2.alternatives([ - Joi2.function(), - Joi2.object().schema() - ]).conditional("ref", { is: true, then: Joi2.required() }), - normalize: Joi2.function(), - message: Joi2.string().when("assert", { is: Joi2.function(), then: Joi2.required() }) - }) - ), - convert: Joi2.boolean(), - manifest: Joi2.boolean(), - method: Joi2.function().allow(false), - multi: Joi2.boolean(), - validate: Joi2.function() - }); - exports2.extension = Joi2.object({ - type: Joi2.alternatives([ - Joi2.string(), - Joi2.object().regex() - ]).required(), - args: Joi2.function(), - cast: Joi2.object().pattern(internals.nameRx, Joi2.object({ - from: Joi2.function().maxArity(1).required(), - to: Joi2.function().minArity(1).maxArity(2).required() - })), - base: Joi2.object().schema().when("type", { is: Joi2.object().regex(), then: Joi2.forbidden() }), - coerce: [ - Joi2.function().maxArity(3), - Joi2.object({ method: Joi2.function().maxArity(3).required(), from: Joi2.array().items(Joi2.string()).single() }) - ], - flags: Joi2.object().pattern(internals.nameRx, Joi2.object({ - setter: Joi2.string(), - default: Joi2.any() - })), - manifest: { - build: Joi2.function().arity(2) - }, - messages: [Joi2.object(), Joi2.string()], - modifiers: Joi2.object().pattern(internals.nameRx, Joi2.function().minArity(1).maxArity(2)), - overrides: Joi2.object().pattern(internals.nameRx, Joi2.function()), - prepare: Joi2.function().maxArity(3), - rebuild: Joi2.function().arity(1), - rules: Joi2.object().pattern(internals.nameRx, internals.rule), - terms: Joi2.object().pattern(internals.nameRx, Joi2.object({ - init: Joi2.array().allow(null).required(), - manifest: Joi2.object().pattern(/.+/, [ - Joi2.valid("schema", "single"), - Joi2.object({ - mapped: Joi2.object({ - from: Joi2.string().required(), - to: Joi2.string().required() - }).required() - }) - ]) - })), - validate: Joi2.function().maxArity(3) - }).strict(); - exports2.extensions = Joi2.array().items(Joi2.object(), Joi2.function().arity(1)).strict(); - internals.desc = { - buffer: Joi2.object({ - buffer: Joi2.string() - }), - func: Joi2.object({ - function: Joi2.function().required(), - options: { - literal: true - } - }), - override: Joi2.object({ - override: true - }), - ref: Joi2.object({ - ref: Joi2.object({ - type: Joi2.valid("value", "global", "local"), - path: Joi2.array().required(), - separator: Joi2.string().length(1).allow(false), - ancestor: Joi2.number().min(0).integer().allow("root"), - map: Joi2.array().items(Joi2.array().length(2)).min(1), - adjust: Joi2.function(), - iterables: Joi2.boolean(), - in: Joi2.boolean(), - render: Joi2.boolean() - }).required() - }), - regex: Joi2.object({ - regex: Joi2.string().min(3) - }), - special: Joi2.object({ - special: Joi2.valid("deep").required() - }), - template: Joi2.object({ - template: Joi2.string().required(), - options: Joi2.object() - }), - value: Joi2.object({ - value: Joi2.alternatives([Joi2.object(), Joi2.array()]).required() - }) - }; - internals.desc.entity = Joi2.alternatives([ - Joi2.array().items(Joi2.link("...")), - Joi2.boolean(), - Joi2.function(), - Joi2.number(), - Joi2.string(), - internals.desc.buffer, - internals.desc.func, - internals.desc.ref, - internals.desc.regex, - internals.desc.special, - internals.desc.template, - internals.desc.value, - Joi2.link("/") - ]); - internals.desc.values = Joi2.array().items( - null, - Joi2.boolean(), - Joi2.function(), - Joi2.number().allow(Infinity, -Infinity), - Joi2.string().allow(""), - Joi2.symbol(), - internals.desc.buffer, - internals.desc.func, - internals.desc.override, - internals.desc.ref, - internals.desc.regex, - internals.desc.template, - internals.desc.value - ); - internals.desc.messages = Joi2.object().pattern(/.+/, [ - Joi2.string(), - internals.desc.template, - Joi2.object().pattern(/.+/, [Joi2.string(), internals.desc.template]) - ]); - exports2.description = Joi2.object({ - type: Joi2.string().required(), - flags: Joi2.object({ - cast: Joi2.string(), - default: Joi2.any(), - description: Joi2.string(), - empty: Joi2.link("/"), - failover: internals.desc.entity, - id: Joi2.string(), - label: Joi2.string(), - only: true, - presence: ["optional", "required", "forbidden"], - result: ["raw", "strip"], - strip: Joi2.boolean(), - unit: Joi2.string() - }).unknown(), - preferences: { - allowUnknown: Joi2.boolean(), - abortEarly: Joi2.boolean(), - artifacts: Joi2.boolean(), - cache: Joi2.boolean(), - convert: Joi2.boolean(), - dateFormat: ["date", "iso", "string", "time", "utc"], - errors: { - escapeHtml: Joi2.boolean(), - label: ["path", "key"], - language: [ - Joi2.string(), - internals.desc.ref - ], - wrap: { - label: internals.wrap, - array: internals.wrap - } - }, - externals: Joi2.boolean(), - messages: internals.desc.messages, - noDefaults: Joi2.boolean(), - nonEnumerables: Joi2.boolean(), - presence: ["required", "optional", "forbidden"], - skipFunctions: Joi2.boolean(), - stripUnknown: Joi2.object({ - arrays: Joi2.boolean(), - objects: Joi2.boolean() - }).or("arrays", "objects").allow(true, false), - warnings: Joi2.boolean() - }, - allow: internals.desc.values, - invalid: internals.desc.values, - rules: Joi2.array().min(1).items({ - name: Joi2.string().required(), - args: Joi2.object().min(1), - keep: Joi2.boolean(), - message: [ - Joi2.string(), - internals.desc.messages - ], - warn: Joi2.boolean() - }), - // Terms - keys: Joi2.object().pattern(/.*/, Joi2.link("/")), - link: internals.desc.ref - }).pattern(/^[a-z]\w*$/, Joi2.any()); - } -}); -var require_lib37 = __commonJS({ - "node_modules/.deno/@hapi+formula@3.0.2/node_modules/@hapi/formula/lib/index.js"(exports2) { - "use strict"; - var internals = { - operators: ["!", "^", "*", "/", "%", "+", "-", "<", "<=", ">", ">=", "==", "!=", "&&", "||", "??"], - operatorCharacters: ["!", "^", "*", "/", "%", "+", "-", "<", "=", ">", "&", "|", "?"], - operatorsOrder: [["^"], ["*", "/", "%"], ["+", "-"], ["<", "<=", ">", ">="], ["==", "!="], ["&&"], ["||", "??"]], - operatorsPrefix: ["!", "n"], - literals: { - '"': '"', - "`": "`", - "'": "'", - "[": "]" - }, - numberRx: /^(?:[0-9]*(\.[0-9]*)?){1}$/, - tokenRx: /^[\w\$\#\.\@\:\{\}]+$/, - symbol: Symbol("formula"), - settings: Symbol("settings") - }; - exports2.Parser = class { - constructor(string3, options2 = {}) { - if (!options2[internals.settings] && options2.constants) { - for (const constant in options2.constants) { - const value = options2.constants[constant]; - if (value !== null && !["boolean", "number", "string"].includes(typeof value)) { - throw new Error(`Formula constant ${constant} contains invalid ${typeof value} value type`); - } - } - } - this.settings = options2[internals.settings] ? options2 : Object.assign({ [internals.settings]: true, constants: {}, functions: {} }, options2); - this.single = null; - this._parts = null; - this._parse(string3); - } - _parse(string3) { - let parts = []; - let current = ""; - let parenthesis = 0; - let literal = false; - const flush = (inner) => { - if (parenthesis) { - throw new Error("Formula missing closing parenthesis"); - } - const last = parts.length ? parts[parts.length - 1] : null; - if (!literal && !current && !inner) { - return; - } - if (last && last.type === "reference" && inner === ")") { - last.type = "function"; - last.value = this._subFormula(current, last.value); - current = ""; - return; - } - if (inner === ")") { - const sub = new exports2.Parser(current, this.settings); - parts.push({ type: "segment", value: sub }); - } else if (literal) { - if (literal === "]") { - parts.push({ type: "reference", value: current }); - current = ""; - return; - } - parts.push({ type: "literal", value: current }); - } else if (internals.operatorCharacters.includes(current)) { - if (last && last.type === "operator" && internals.operators.includes(last.value + current)) { - last.value += current; - } else { - parts.push({ type: "operator", value: current }); - } - } else if (current.match(internals.numberRx)) { - parts.push({ type: "constant", value: parseFloat(current) }); - } else if (this.settings.constants[current] !== void 0) { - parts.push({ type: "constant", value: this.settings.constants[current] }); - } else { - if (!current.match(internals.tokenRx)) { - throw new Error(`Formula contains invalid token: ${current}`); - } - parts.push({ type: "reference", value: current }); - } - current = ""; - }; - for (const c of string3) { - if (literal) { - if (c === literal) { - flush(); - literal = false; - } else { - current += c; - } - } else if (parenthesis) { - if (c === "(") { - current += c; - ++parenthesis; - } else if (c === ")") { - --parenthesis; - if (!parenthesis) { - flush(c); - } else { - current += c; - } + var EventEmitter = __require2("events"); + var https = __require2("https"); + var http = __require2("http"); + var net = __require2("net"); + var tls = __require2("tls"); + var { randomBytes: randomBytes3, createHash } = __require2("crypto"); + var { Readable: Readable4 } = __require2("stream"); + var { URL: URL2 } = __require2("url"); + var PerMessageDeflate = require_permessage_deflate(); + var Receiver2 = require_receiver(); + var Sender2 = require_sender(); + var { + BINARY_TYPES, + EMPTY_BUFFER, + GUID, + kForOnEventAttribute, + kListener, + kStatusCode, + kWebSocket, + NOOP + } = require_constants2(); + var { + EventTarget: { addEventListener: addEventListener2, removeEventListener } + } = require_event_target(); + var { format: format52, parse: parse52 } = require_extension(); + var { toBuffer } = require_buffer_util(); + var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; + var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; + var protocolVersions = [8, 13]; + var closeTimeout = 30 * 1e3; + var WebSocket3 = class _WebSocket extends EventEmitter { + /** + * Create a new `WebSocket`. + * + * @param {(String|URL)} address The URL to which to connect + * @param {(String|String[])} [protocols] The subprotocols + * @param {Object} [options] Connection options + */ + constructor(address, protocols, options2) { + super(); + this._binaryType = BINARY_TYPES[0]; + this._closeCode = 1006; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = EMPTY_BUFFER; + this._closeTimer = null; + this._extensions = {}; + this._paused = false; + this._protocol = ""; + this._readyState = _WebSocket.CONNECTING; + this._receiver = null; + this._sender = null; + this._socket = null; + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + if (protocols === void 0) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === "object" && protocols !== null) { + options2 = protocols; + protocols = []; } else { - current += c; - } - } else if (c in internals.literals) { - literal = internals.literals[c]; - } else if (c === "(") { - flush(); - ++parenthesis; - } else if (internals.operatorCharacters.includes(c)) { - flush(); - current = c; - flush(); - } else if (c !== " ") { - current += c; - } else { - flush(); - } - } - flush(); - parts = parts.map((part, i2) => { - if (part.type !== "operator" || part.value !== "-" || i2 && parts[i2 - 1].type !== "operator") { - return part; - } - return { type: "operator", value: "n" }; - }); - let operator = false; - for (const part of parts) { - if (part.type === "operator") { - if (internals.operatorsPrefix.includes(part.value)) { - continue; - } - if (!operator) { - throw new Error("Formula contains an operator in invalid position"); - } - if (!internals.operators.includes(part.value)) { - throw new Error(`Formula contains an unknown operator ${part.value}`); + protocols = [protocols]; } - } else if (operator) { - throw new Error("Formula missing expected operator"); } - operator = !operator; - } - if (!operator) { - throw new Error("Formula contains invalid trailing operator"); - } - if (parts.length === 1 && ["reference", "literal", "constant"].includes(parts[0].type)) { - this.single = { type: parts[0].type === "reference" ? "reference" : "value", value: parts[0].value }; + initAsClient(this, address, protocols, options2); + } else { + this._isServer = true; } - this._parts = parts.map((part) => { - if (part.type === "operator") { - return internals.operatorsPrefix.includes(part.value) ? part : part.value; - } - if (part.type !== "reference") { - return part.value; - } - if (this.settings.tokenRx && !this.settings.tokenRx.test(part.value)) { - throw new Error(`Formula contains invalid reference ${part.value}`); - } - if (this.settings.reference) { - return this.settings.reference(part.value); - } - return internals.reference(part.value); - }); } - _subFormula(string3, name) { - const method = this.settings.functions[name]; - if (typeof method !== "function") { - throw new Error(`Formula contains unknown function ${name}`); - } - let args = []; - if (string3) { - let current = ""; - let parenthesis = 0; - let literal = false; - const flush = () => { - if (!current) { - throw new Error(`Formula contains function ${name} with invalid arguments ${string3}`); - } - args.push(current); - current = ""; - }; - for (let i2 = 0; i2 < string3.length; ++i2) { - const c = string3[i2]; - if (literal) { - current += c; - if (c === literal) { - literal = false; - } - } else if (c in internals.literals && !parenthesis) { - current += c; - literal = internals.literals[c]; - } else if (c === "," && !parenthesis) { - flush(); - } else { - current += c; - if (c === "(") { - ++parenthesis; - } else if (c === ")") { - --parenthesis; - } - } - } - flush(); - } - args = args.map((arg) => new exports2.Parser(arg, this.settings)); - return function(context) { - const innerValues = []; - for (const arg of args) { - innerValues.push(arg.evaluate(context)); - } - return method.call(context, ...innerValues); - }; + /** + * This deviates from the WHATWG interface since ws doesn't support the + * required default "blob" type (instead we define a custom "nodebuffer" + * type). + * + * @type {String} + */ + get binaryType() { + return this._binaryType; } - evaluate(context) { - const parts = this._parts.slice(); - for (let i2 = parts.length - 2; i2 >= 0; --i2) { - const part = parts[i2]; - if (part && part.type === "operator") { - const current = parts[i2 + 1]; - parts.splice(i2 + 1, 1); - const value = internals.evaluate(current, context); - parts[i2] = internals.single(part.value, value); - } - } - internals.operatorsOrder.forEach((set) => { - for (let i2 = 1; i2 < parts.length - 1; ) { - if (set.includes(parts[i2])) { - const operator = parts[i2]; - const left2 = internals.evaluate(parts[i2 - 1], context); - const right2 = internals.evaluate(parts[i2 + 1], context); - parts.splice(i2, 2); - const result = internals.calculate(operator, left2, right2); - parts[i2 - 1] = result === 0 ? 0 : result; - } else { - i2 += 2; - } - } - }); - return internals.evaluate(parts[0], context); + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) return; + this._binaryType = type; + if (this._receiver) this._receiver._binaryType = type; } - }; - exports2.Parser.prototype[internals.symbol] = true; - internals.reference = function(name) { - return function(context) { - return context && context[name] !== void 0 ? context[name] : null; - }; - }; - internals.evaluate = function(part, context) { - if (part === null) { + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) return this._bufferedAmount; + return this._socket._writableState.length + this._sender._bufferedBytes; + } + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onclose() { return null; } - if (typeof part === "function") { - return part(context); + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onerror() { + return null; } - if (part[internals.symbol]) { - return part.evaluate(context); + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onopen() { + return null; } - return part; - }; - internals.single = function(operator, value) { - if (operator === "!") { - return value ? false : true; + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onmessage() { + return null; } - const negative = -value; - if (negative === 0) { - return 0; + /** + * @type {String} + */ + get protocol() { + return this._protocol; } - return negative; - }; - internals.calculate = function(operator, left2, right2) { - if (operator === "??") { - return internals.exists(left2) ? left2 : right2; + /** + * @type {Number} + */ + get readyState() { + return this._readyState; } - if (typeof left2 === "string" || typeof right2 === "string") { - if (operator === "+") { - left2 = internals.exists(left2) ? left2 : ""; - right2 = internals.exists(right2) ? right2 : ""; - return left2 + right2; - } - } else { - switch (operator) { - case "^": - return Math.pow(left2, right2); - case "*": - return left2 * right2; - case "/": - return left2 / right2; - case "%": - return left2 % right2; - case "+": - return left2 + right2; - case "-": - return left2 - right2; - } - } - switch (operator) { - case "<": - return left2 < right2; - case "<=": - return left2 <= right2; - case ">": - return left2 > right2; - case ">=": - return left2 >= right2; - case "==": - return left2 === right2; - case "!=": - return left2 !== right2; - case "&&": - return left2 && right2; - case "||": - return left2 || right2; + /** + * @type {String} + */ + get url() { + return this._url; } - return null; - }; - internals.exists = function(value) { - return value !== null && value !== void 0; - }; - } -}); -var require_annotate2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/annotate.js"(exports2) { - "use strict"; - var { clone: clone2 } = require_lib(); - var Common = require_common3(); - var internals = { - annotations: Symbol("annotations") - }; - exports2.error = function(stripColorCodes) { - if (!this._original || typeof this._original !== "object") { - return this.details[0].message; + /** + * Set up the socket and the internal resources. + * + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Object} options Options object + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ + setSocket(socket, head, options2) { + const receiver = new Receiver2({ + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: options2.maxPayload, + skipUTF8Validation: options2.skipUTF8Validation + }); + this._sender = new Sender2(socket, this._extensions, options2.generateMask); + this._receiver = receiver; + this._socket = socket; + receiver[kWebSocket] = this; + socket[kWebSocket] = this; + receiver.on("conclude", receiverOnConclude); + receiver.on("drain", receiverOnDrain); + receiver.on("error", receiverOnError); + receiver.on("message", receiverOnMessage); + receiver.on("ping", receiverOnPing); + receiver.on("pong", receiverOnPong); + socket.setTimeout(0); + socket.setNoDelay(); + if (head.length > 0) socket.unshift(head); + socket.on("close", socketOnClose); + socket.on("data", socketOnData); + socket.on("end", socketOnEnd); + socket.on("error", socketOnError); + this._readyState = _WebSocket.OPEN; + this.emit("open"); } - const redFgEscape = stripColorCodes ? "" : "\x1B[31m"; - const redBgEscape = stripColorCodes ? "" : "\x1B[41m"; - const endColor = stripColorCodes ? "" : "\x1B[0m"; - const obj = clone2(this._original); - for (let i2 = this.details.length - 1; i2 >= 0; --i2) { - const pos = i2 + 1; - const error2 = this.details[i2]; - const path8 = error2.path; - let node = obj; - for (let j = 0; ; ++j) { - const seg = path8[j]; - if (Common.isSchema(node)) { - node = node.clone(); - } - if (j + 1 < path8.length && typeof node[seg] !== "string") { - node = node[seg]; - } else { - const refAnnotations = node[internals.annotations] || { errors: {}, missing: {} }; - node[internals.annotations] = refAnnotations; - const cacheKey = seg || error2.context.key; - if (node[seg] !== void 0) { - refAnnotations.errors[cacheKey] = refAnnotations.errors[cacheKey] || []; - refAnnotations.errors[cacheKey].push(pos); - } else { - refAnnotations.missing[cacheKey] = pos; - } - break; - } + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this._readyState = _WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); + return; + } + if (this._extensions[PerMessageDeflate.extensionName]) { + this._extensions[PerMessageDeflate.extensionName].cleanup(); } + this._receiver.removeAllListeners(); + this._readyState = _WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); } - const replacers = { - key: /_\$key\$_([, \d]+)_\$end\$_"/g, - missing: /"_\$miss\$_([^|]+)\|(\d+)_\$end\$_": "__missing__"/g, - arrayIndex: /\s*"_\$idx\$_([, \d]+)_\$end\$_",?\n(.*)/g, - specials: /"\[(NaN|Symbol.*|-?Infinity|function.*|\(.*)]"/g - }; - let message = internals.safeStringify(obj, 2).replace(replacers.key, ($0, $1) => `" ${redFgEscape}[${$1}]${endColor}`).replace(replacers.missing, ($0, $1, $2) => `${redBgEscape}"${$1}"${endColor}${redFgEscape} [${$2}]: -- missing --${endColor}`).replace(replacers.arrayIndex, ($0, $1, $2) => ` -${$2} ${redFgEscape}[${$1}]${endColor}`).replace(replacers.specials, ($0, $1) => $1); - message = `${message} -${redFgEscape}`; - for (let i2 = 0; i2 < this.details.length; ++i2) { - const pos = i2 + 1; - message = `${message} -[${pos}] ${this.details[i2].message}`; - } - message = message + endColor; - return message; - }; - internals.safeStringify = function(obj, spaces) { - return JSON.stringify(obj, internals.serializer(), spaces); - }; - internals.serializer = function() { - const keys = []; - const stack = []; - const cycleReplacer = (key, value) => { - if (stack[0] === value) { - return "[Circular ~]"; + /** + * Start a closing handshake. + * + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} [code] Status code explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing + * @public + */ + close(code2, data) { + if (this.readyState === _WebSocket.CLOSED) return; + if (this.readyState === _WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + return abortHandshake(this, this._req, msg); } - return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join(".") + "]"; - }; - return function(key, value) { - if (stack.length > 0) { - const thisPos = stack.indexOf(this); - if (~thisPos) { - stack.length = thisPos + 1; - keys.length = thisPos + 1; - keys[thisPos] = key; - } else { - stack.push(this); - keys.push(key); - } - if (~stack.indexOf(value)) { - value = cycleReplacer.call(this, key, value); + if (this.readyState === _WebSocket.CLOSING) { + if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { + this._socket.end(); } - } else { - stack.push(value); + return; } - if (value) { - const annotations = value[internals.annotations]; - if (annotations) { - if (Array.isArray(value)) { - const annotated = []; - for (let i2 = 0; i2 < value.length; ++i2) { - if (annotations.errors[i2]) { - annotated.push(`_$idx$_${annotations.errors[i2].sort().join(", ")}_$end$_`); - } - annotated.push(value[i2]); - } - value = annotated; - } else { - for (const errorKey in annotations.errors) { - value[`${errorKey}_$key$_${annotations.errors[errorKey].sort().join(", ")}_$end$_`] = value[errorKey]; - value[errorKey] = void 0; - } - for (const missingKey in annotations.missing) { - value[`_$miss$_${missingKey}|${annotations.missing[missingKey]}_$end$_`] = "__missing__"; - } - } - return value; + this._readyState = _WebSocket.CLOSING; + this._sender.close(code2, data, !this._isServer, (err) => { + if (err) return; + this._closeFrameSent = true; + if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { + this._socket.end(); } + }); + this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + closeTimeout + ); + } + /** + * Pause the socket. + * + * @public + */ + pause() { + if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { + return; } - if (value === Infinity || value === -Infinity || Number.isNaN(value) || typeof value === "function" || typeof value === "symbol") { - return "[" + value.toString() + "]"; + this._paused = true; + this._socket.pause(); + } + /** + * Send a ping. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the ping is sent + * @public + */ + ping(data, mask, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); } - return value; - }; - }; - } -}); -var require_errors3 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/errors.js"(exports2) { - "use strict"; - var Annotate = require_annotate2(); - var Common = require_common3(); - var Template = require_template2(); - exports2.Report = class { - constructor(code2, value, local, flags, messages, state, prefs) { - this.code = code2; - this.flags = flags; - this.messages = messages; - this.path = state.path; - this.prefs = prefs; - this.state = state; - this.value = value; - this.message = null; - this.template = null; - this.local = local || {}; - this.local.label = exports2.label(this.flags, this.state, this.prefs, this.messages); - if (this.value !== void 0 && !this.local.hasOwnProperty("value")) { - this.local.value = this.value; + if (typeof data === "function") { + cb = data; + data = mask = void 0; + } else if (typeof mask === "function") { + cb = mask; + mask = void 0; } - if (this.path.length) { - const key = this.path[this.path.length - 1]; - if (typeof key !== "object") { - this.local.key = key; - } + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + if (mask === void 0) mask = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask, cb); + } + /** + * Send a pong. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the pong is sent + * @public + */ + pong(data, mask, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + } + if (typeof data === "function") { + cb = data; + data = mask = void 0; + } else if (typeof mask === "function") { + cb = mask; + mask = void 0; + } + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + if (mask === void 0) mask = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask, cb); + } + /** + * Resume the socket. + * + * @public + */ + resume() { + if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { + return; + } + this._paused = false; + if (!this._receiver._writableState.needDrain) this._socket.resume(); + } + /** + * Send a data message. + * + * @param {*} data The message to send + * @param {Object} [options] Options object + * @param {Boolean} [options.binary] Specifies whether `data` is binary or + * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` + * @param {Boolean} [options.fin=true] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when data is written out + * @public + */ + send(data, options2, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + } + if (typeof options2 === "function") { + cb = options2; + options2 = {}; + } + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + const opts = { + binary: typeof data !== "string", + mask: !this._isServer, + compress: true, + fin: true, + ...options2 + }; + if (!this._extensions[PerMessageDeflate.extensionName]) { + opts.compress = false; + } + this._sender.send(data || EMPTY_BUFFER, opts, cb); + } + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === _WebSocket.CLOSED) return; + if (this.readyState === _WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + return abortHandshake(this, this._req, msg); + } + if (this._socket) { + this._readyState = _WebSocket.CLOSING; + this._socket.destroy(); } } - _setTemplate(template) { - this.template = template; - if (!this.flags.label && this.path.length === 0) { - const localized = this._template(this.template, "root"); - if (localized) { - this.local.label = localized; + }; + Object.defineProperty(WebSocket3, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") + }); + Object.defineProperty(WebSocket3.prototype, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") + }); + Object.defineProperty(WebSocket3, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") + }); + Object.defineProperty(WebSocket3.prototype, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") + }); + Object.defineProperty(WebSocket3, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") + }); + Object.defineProperty(WebSocket3.prototype, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") + }); + Object.defineProperty(WebSocket3, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") + }); + Object.defineProperty(WebSocket3.prototype, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") + }); + [ + "binaryType", + "bufferedAmount", + "extensions", + "isPaused", + "protocol", + "readyState", + "url" + ].forEach((property) => { + Object.defineProperty(WebSocket3.prototype, property, { enumerable: true }); + }); + ["open", "error", "close", "message"].forEach((method) => { + Object.defineProperty(WebSocket3.prototype, `on${method}`, { + enumerable: true, + get() { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) return listener[kListener]; + } + return null; + }, + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } } + if (typeof handler !== "function") return; + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true + }); } + }); + }); + WebSocket3.prototype.addEventListener = addEventListener2; + WebSocket3.prototype.removeEventListener = removeEventListener; + module14.exports = WebSocket3; + function initAsClient(websocket, address, protocols, options2) { + const opts = { + protocolVersion: protocolVersions[1], + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options2, + createConnection: void 0, + socketPath: void 0, + hostname: void 0, + protocol: void 0, + timeout: void 0, + method: void 0, + host: void 0, + path: void 0, + port: void 0 + }; + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` + ); } - toString() { - if (this.message) { - return this.message; - } - const code2 = this.code; - if (!this.prefs.errors.render) { - return this.code; - } - const template = this._template(this.template) || this._template(this.prefs.messages) || this._template(this.messages); - if (template === void 0) { - return `Error code "${code2}" is not defined, your custom type is missing the correct messages definition`; - } - this.message = template.render(this.value, this.state, this.prefs, this.local, { errors: this.prefs.errors, messages: [this.prefs.messages, this.messages] }); - if (!this.prefs.errors.label) { - this.message = this.message.replace(/^"" /, "").trim(); + let parsedUrl; + if (address instanceof URL2) { + parsedUrl = address; + websocket._url = address.href; + } else { + try { + parsedUrl = new URL2(address); + } catch (e2) { + throw new SyntaxError(`Invalid URL: ${address}`); } - return this.message; + websocket._url = address; } - _template(messages, code2) { - return exports2.template(this.value, messages, code2 || this.code, this.state, this.prefs); + const isSecure = parsedUrl.protocol === "wss:"; + const isUnixSocket = parsedUrl.protocol === "ws+unix:"; + let invalidURLMessage; + if (parsedUrl.protocol !== "ws:" && !isSecure && !isUnixSocket) { + invalidURLMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; + } else if (isUnixSocket && !parsedUrl.pathname) { + invalidURLMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidURLMessage = "The URL contains a fragment identifier"; } - }; - exports2.path = function(path8) { - let label = ""; - for (const segment of path8) { - if (typeof segment === "object") { - continue; - } - if (typeof segment === "string") { - if (label) { - label += "."; - } - label += segment; + if (invalidURLMessage) { + const err = new SyntaxError(invalidURLMessage); + if (websocket._redirects === 0) { + throw err; } else { - label += `[${segment}]`; - } - } - return label; - }; - exports2.template = function(value, messages, code2, state, prefs) { - if (!messages) { - return; - } - if (Template.isTemplate(messages)) { - return code2 !== "root" ? messages : null; - } - let lang = prefs.errors.language; - if (Common.isResolvable(lang)) { - lang = lang.resolve(value, state, prefs); - } - if (lang && messages[lang]) { - if (messages[lang][code2] !== void 0) { - return messages[lang][code2]; - } - if (messages[lang]["*"] !== void 0) { - return messages[lang]["*"]; + emitErrorAndClose(websocket, err); + return; } } - if (!messages[code2]) { - return messages["*"]; - } - return messages[code2]; - }; - exports2.label = function(flags, state, prefs, messages) { - if (!prefs.errors.label) { - return ""; - } - if (flags.label) { - return flags.label; - } - let path8 = state.path; - if (prefs.errors.label === "key" && state.path.length > 1) { - path8 = state.path.slice(-1); - } - const normalized = exports2.path(path8); - if (normalized) { - return normalized; - } - return exports2.template(null, prefs.messages, "root", state, prefs) || messages && exports2.template(null, messages, "root", state, prefs) || "value"; - }; - exports2.process = function(errors, original, prefs) { - if (!errors) { - return null; - } - const { override, message, details } = exports2.details(errors); - if (override) { - return override; - } - if (prefs.errors.stack) { - return new exports2.ValidationError(message, details, original); - } - const limit = Error.stackTraceLimit; - Error.stackTraceLimit = 0; - const validationError = new exports2.ValidationError(message, details, original); - Error.stackTraceLimit = limit; - return validationError; - }; - exports2.details = function(errors, options2 = {}) { - let messages = []; - const details = []; - for (const item of errors) { - if (item instanceof Error) { - if (options2.override !== false) { - return { override: item }; - } - const message2 = item.toString(); - messages.push(message2); - details.push({ - message: message2, - type: "override", - context: { error: item } - }); - continue; - } - const message = item.toString(); - messages.push(message); - details.push({ - message, - path: item.path.filter((v2) => typeof v2 !== "object"), - type: item.code, - context: item.local + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes3(16).toString("base64"); + const get2 = isSecure ? https.get : http.get; + const protocolSet = /* @__PURE__ */ new Set(); + let perMessageDeflate; + opts.createConnection = isSecure ? tlsConnect : netConnect; + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; + opts.headers = { + "Sec-WebSocket-Version": opts.protocolVersion, + "Sec-WebSocket-Key": key, + Connection: "Upgrade", + Upgrade: "websocket", + ...opts.headers + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); + opts.headers["Sec-WebSocket-Extensions"] = format52({ + [PerMessageDeflate.extensionName]: perMessageDeflate.offer() }); } - if (messages.length > 1) { - messages = [...new Set(messages)]; - } - return { message: messages.join(". "), details }; - }; - exports2.ValidationError = class extends Error { - constructor(message, details, original) { - super(message); - this._original = original; - this.details = details; - } - static isError(err) { - return err instanceof exports2.ValidationError; - } - }; - exports2.ValidationError.prototype.isJoi = true; - exports2.ValidationError.prototype.name = "ValidationError"; - exports2.ValidationError.prototype.annotate = Annotate.error; - } -}); -var require_ref2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/ref.js"(exports2) { - "use strict"; - var { assert: assert2, clone: clone2, reach } = require_lib(); - var Common = require_common3(); - var Template; - var internals = { - symbol: Symbol("ref"), - // Used to internally identify references (shared with other joi versions) - defaults: { - adjust: null, - in: false, - iterables: null, - map: null, - separator: ".", - type: "value" - } - }; - exports2.create = function(key, options2 = {}) { - assert2(typeof key === "string", "Invalid reference key:", key); - Common.assertOptions(options2, ["adjust", "ancestor", "in", "iterables", "map", "prefix", "render", "separator"]); - assert2(!options2.prefix || typeof options2.prefix === "object", "options.prefix must be of type object"); - const ref = Object.assign({}, internals.defaults, options2); - delete ref.prefix; - const separator = ref.separator; - const context = internals.context(key, separator, options2.prefix); - ref.type = context.type; - key = context.key; - if (ref.type === "value") { - if (context.root) { - assert2(!separator || key[0] !== separator, "Cannot specify relative path with root prefix"); - ref.ancestor = "root"; - if (!key) { - key = null; - } - } - if (separator && separator === key) { - key = null; - ref.ancestor = 0; - } else { - if (ref.ancestor !== void 0) { - assert2(!separator || !key || key[0] !== separator, "Cannot combine prefix with ancestor option"); - } else { - const [ancestor, slice] = internals.ancestor(key, separator); - if (slice) { - key = key.slice(slice); - if (key === "") { - key = null; - } - } - ref.ancestor = ancestor; + if (protocols.length) { + for (const protocol of protocols) { + if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { + throw new SyntaxError( + "An invalid or duplicated subprotocol was specified" + ); } + protocolSet.add(protocol); } + opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); } - ref.path = separator ? key === null ? [] : key.split(separator) : [key]; - return new internals.Ref(ref); - }; - exports2.in = function(key, options2 = {}) { - return exports2.create(key, { ...options2, in: true }); - }; - exports2.isRef = function(ref) { - return ref ? !!ref[Common.symbols.ref] : false; - }; - internals.Ref = class { - constructor(options2) { - assert2(typeof options2 === "object", "Invalid reference construction"); - Common.assertOptions(options2, [ - "adjust", - "ancestor", - "in", - "iterables", - "map", - "path", - "render", - "separator", - "type", - // Copied - "depth", - "key", - "root", - "display" - // Overridden - ]); - assert2([false, void 0].includes(options2.separator) || typeof options2.separator === "string" && options2.separator.length === 1, "Invalid separator"); - assert2(!options2.adjust || typeof options2.adjust === "function", "options.adjust must be a function"); - assert2(!options2.map || Array.isArray(options2.map), "options.map must be an array"); - assert2(!options2.map || !options2.adjust, "Cannot set both map and adjust options"); - Object.assign(this, internals.defaults, options2); - assert2(this.type === "value" || this.ancestor === void 0, "Non-value references cannot reference ancestors"); - if (Array.isArray(this.map)) { - this.map = new Map(this.map); + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers["Sec-WebSocket-Origin"] = opts.origin; + } else { + opts.headers.Origin = opts.origin; } - this.depth = this.path.length; - this.key = this.path.length ? this.path.join(this.separator) : null; - this.root = this.path[0]; - this.updateDisplay(); } - resolve(value, state, prefs, local, options2 = {}) { - assert2(!this.in || options2.in, "Invalid in() reference usage"); - if (this.type === "global") { - return this._resolve(prefs.context, state, options2); - } - if (this.type === "local") { - return this._resolve(local, state, options2); - } - if (!this.ancestor) { - return this._resolve(value, state, options2); - } - if (this.ancestor === "root") { - return this._resolve(state.ancestors[state.ancestors.length - 1], state, options2); - } - assert2(this.ancestor <= state.ancestors.length, "Invalid reference exceeds the schema root:", this.display); - return this._resolve(state.ancestors[this.ancestor - 1], state, options2); + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; } - _resolve(target, state, options2) { - let resolved; - if (this.type === "value" && state.mainstay.shadow && options2.shadow !== false) { - resolved = state.mainstay.shadow.get(this.absolute(state)); - } - if (resolved === void 0) { - resolved = reach(target, this.path, { iterables: this.iterables, functions: true }); - } - if (this.adjust) { - resolved = this.adjust(resolved); - } - if (this.map) { - const mapped = this.map.get(resolved); - if (mapped !== void 0) { - resolved = mapped; + if (isUnixSocket) { + const parts = opts.path.split(":"); + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + if (opts.followRedirects) { + if (websocket._redirects === 0) { + websocket._originalHost = parsedUrl.host; + const headers = options2 && options2.headers; + options2 = { ...options2, headers: {} }; + if (headers) { + for (const [key2, value] of Object.entries(headers)) { + options2.headers[key2.toLowerCase()] = value; + } } + } else if (parsedUrl.host !== websocket._originalHost) { + delete opts.headers.authorization; + delete opts.headers.cookie; + delete opts.headers.host; + opts.auth = void 0; } - if (state.mainstay) { - state.mainstay.tracer.resolve(state, this, resolved); + if (opts.auth && !options2.headers.authorization) { + options2.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); } - return resolved; } - toString() { - return this.display; - } - absolute(state) { - return [...state.path.slice(0, -this.ancestor), ...this.path]; - } - clone() { - return new internals.Ref(this); + let req = websocket._req = get2(opts); + if (opts.timeout) { + req.on("timeout", () => { + abortHandshake(websocket, req, "Opening handshake has timed out"); + }); } - describe() { - const ref = { path: this.path }; - if (this.type !== "value") { - ref.type = this.type; - } - if (this.separator !== ".") { - ref.separator = this.separator; - } - if (this.type === "value" && this.ancestor !== 1) { - ref.ancestor = this.ancestor; - } - if (this.map) { - ref.map = [...this.map]; - } - for (const key of ["adjust", "iterables", "render"]) { - if (this[key] !== null && this[key] !== void 0) { - ref[key] = this[key]; + req.on("error", (err) => { + if (req === null || req.aborted) return; + req = websocket._req = null; + emitErrorAndClose(websocket, err); + }); + req.on("response", (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { + if (++websocket._redirects > opts.maxRedirects) { + abortHandshake(websocket, req, "Maximum redirects exceeded"); + return; } + req.abort(); + let addr; + try { + addr = new URL2(location, address); + } catch (e2) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket, err); + return; + } + initAsClient(websocket, addr, protocols, options2); + } else if (!websocket.emit("unexpected-response", req, res)) { + abortHandshake( + websocket, + req, + `Unexpected server response: ${res.statusCode}` + ); } - if (this.in !== false) { - ref.in = true; - } - return { ref }; - } - updateDisplay() { - const key = this.key !== null ? this.key : ""; - if (this.type !== "value") { - this.display = `ref:${this.type}:${key}`; + }); + req.on("upgrade", (res, socket, head) => { + websocket.emit("upgrade", res); + if (websocket.readyState !== WebSocket3.CONNECTING) return; + req = websocket._req = null; + const digest = createHash("sha1").update(key + GUID).digest("base64"); + if (res.headers["sec-websocket-accept"] !== digest) { + abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header"); return; } - if (!this.separator) { - this.display = `ref:${key}`; - return; + const serverProt = res.headers["sec-websocket-protocol"]; + let protError; + if (serverProt !== void 0) { + if (!protocolSet.size) { + protError = "Server sent a subprotocol but none was requested"; + } else if (!protocolSet.has(serverProt)) { + protError = "Server sent an invalid subprotocol"; + } + } else if (protocolSet.size) { + protError = "Server sent no subprotocol"; } - if (!this.ancestor) { - this.display = `ref:${this.separator}${key}`; + if (protError) { + abortHandshake(websocket, socket, protError); return; } - if (this.ancestor === "root") { - this.display = `ref:root:${key}`; - return; + if (serverProt) websocket._protocol = serverProt; + const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; + if (secWebSocketExtensions !== void 0) { + if (!perMessageDeflate) { + const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; + abortHandshake(websocket, socket, message); + return; + } + let extensions; + try { + extensions = parse52(secWebSocketExtensions); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake(websocket, socket, message); + return; + } + const extensionNames = Object.keys(extensions); + if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) { + const message = "Server indicated an extension that was not requested"; + abortHandshake(websocket, socket, message); + return; + } + try { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake(websocket, socket, message); + return; + } + websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; } - if (this.ancestor === 1) { - this.display = `ref:${key || ".."}`; - return; + websocket.setSocket(socket, head, { + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); + }); + } + function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket3.CLOSING; + websocket.emit("error", err); + websocket.emitClose(); + } + function netConnect(options2) { + options2.path = options2.socketPath; + return net.connect(options2); + } + function tlsConnect(options2) { + options2.path = void 0; + if (!options2.servername && options2.servername !== "") { + options2.servername = net.isIP(options2.host) ? "" : options2.host; + } + return tls.connect(options2); + } + function abortHandshake(websocket, stream, message) { + websocket._readyState = WebSocket3.CLOSING; + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake); + if (stream.setHeader) { + stream.abort(); + if (stream.socket && !stream.socket.destroyed) { + stream.socket.destroy(); } - const lead = new Array(this.ancestor + 1).fill(this.separator).join(""); - this.display = `ref:${lead}${key || ""}`; + stream.once("abort", websocket.emitClose.bind(websocket)); + websocket.emit("error", err); + } else { + stream.destroy(err); + stream.once("error", websocket.emit.bind(websocket, "error")); + stream.once("close", websocket.emitClose.bind(websocket)); } - }; - internals.Ref.prototype[Common.symbols.ref] = true; - exports2.build = function(desc) { - desc = Object.assign({}, internals.defaults, desc); - if (desc.type === "value" && desc.ancestor === void 0) { - desc.ancestor = 1; + } + function sendAfterClose(websocket, data, cb) { + if (data) { + const length2 = toBuffer(data).length; + if (websocket._socket) websocket._sender._bufferedBytes += length2; + else websocket._bufferedAmount += length2; } - return new internals.Ref(desc); - }; - internals.context = function(key, separator, prefix = {}) { - key = key.trim(); - if (prefix) { - const globalp = prefix.global === void 0 ? "$" : prefix.global; - if (globalp !== separator && key.startsWith(globalp)) { - return { key: key.slice(globalp.length), type: "global" }; - } - const local = prefix.local === void 0 ? "#" : prefix.local; - if (local !== separator && key.startsWith(local)) { - return { key: key.slice(local.length), type: "local" }; - } - const root = prefix.root === void 0 ? "/" : prefix.root; - if (root !== separator && key.startsWith(root)) { - return { key: key.slice(root.length), type: "value", root: true }; - } + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})` + ); + cb(err); } - return { key, type: "value" }; - }; - internals.ancestor = function(key, separator) { - if (!separator) { - return [1, 0]; + } + function receiverOnConclude(code2, reason) { + const websocket = this[kWebSocket]; + websocket._closeFrameReceived = true; + websocket._closeMessage = reason; + websocket._closeCode = code2; + if (websocket._socket[kWebSocket] === void 0) return; + websocket._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket._socket); + if (code2 === 1005) websocket.close(); + else websocket.close(code2, reason); + } + function receiverOnDrain() { + const websocket = this[kWebSocket]; + if (!websocket.isPaused) websocket._socket.resume(); + } + function receiverOnError(err) { + const websocket = this[kWebSocket]; + if (websocket._socket[kWebSocket] !== void 0) { + websocket._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket._socket); + websocket.close(err[kStatusCode]); } - if (key[0] !== separator) { - return [1, 0]; + websocket.emit("error", err); + } + function receiverOnFinish() { + this[kWebSocket].emitClose(); + } + function receiverOnMessage(data, isBinary) { + this[kWebSocket].emit("message", data, isBinary); + } + function receiverOnPing(data) { + const websocket = this[kWebSocket]; + websocket.pong(data, !websocket._isServer, NOOP); + websocket.emit("ping", data); + } + function receiverOnPong(data) { + this[kWebSocket].emit("pong", data); + } + function resume(stream) { + stream.resume(); + } + function socketOnClose() { + const websocket = this[kWebSocket]; + this.removeListener("close", socketOnClose); + this.removeListener("data", socketOnData); + this.removeListener("end", socketOnEnd); + websocket._readyState = WebSocket3.CLOSING; + let chunk; + if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && (chunk = websocket._socket.read()) !== null) { + websocket._receiver.write(chunk); } - if (key[1] !== separator) { - return [0, 1]; + websocket._receiver.end(); + this[kWebSocket] = void 0; + clearTimeout(websocket._closeTimer); + if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) { + websocket.emitClose(); + } else { + websocket._receiver.on("error", receiverOnFinish); + websocket._receiver.on("finish", receiverOnFinish); } - let i2 = 2; - while (key[i2] === separator) { - ++i2; + } + function socketOnData(chunk) { + if (!this[kWebSocket]._receiver.write(chunk)) { + this.pause(); } - return [i2 - 1, i2]; - }; - exports2.toSibling = 0; - exports2.toParent = 1; - exports2.Manager = class { - constructor() { - this.refs = []; + } + function socketOnEnd() { + const websocket = this[kWebSocket]; + websocket._readyState = WebSocket3.CLOSING; + websocket._receiver.end(); + this.end(); + } + function socketOnError() { + const websocket = this[kWebSocket]; + this.removeListener("error", socketOnError); + this.on("error", NOOP); + if (websocket) { + websocket._readyState = WebSocket3.CLOSING; + this.destroy(); } - register(source, target) { - if (!source) { - return; - } - target = target === void 0 ? exports2.toParent : target; - if (Array.isArray(source)) { - for (const ref of source) { - this.register(ref, target); + } + } +}); +var require_subprotocol = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/subprotocol.js"(exports2, module14) { + "use strict"; + var { tokenChars } = require_validation(); + function parse52(header) { + const protocols = /* @__PURE__ */ new Set(); + let start = -1; + let end = -1; + let i2 = 0; + for (i2; i2 < header.length; i2++) { + const code2 = header.charCodeAt(i2); + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); } - return; + if (end === -1) end = i2; + const protocol2 = header.slice(start, end); + if (protocols.has(protocol2)) { + throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); + } + protocols.add(protocol2); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + } + if (start === -1 || end !== -1) { + throw new SyntaxError("Unexpected end of input"); + } + const protocol = header.slice(start, i2); + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + protocols.add(protocol); + return protocols; + } + module14.exports = { parse: parse52 }; + } +}); +var require_websocket_server = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket-server.js"(exports2, module14) { + "use strict"; + var EventEmitter = __require2("events"); + var http = __require2("http"); + var https = __require2("https"); + var net = __require2("net"); + var tls = __require2("tls"); + var { createHash } = __require2("crypto"); + var extension = require_extension(); + var PerMessageDeflate = require_permessage_deflate(); + var subprotocol = require_subprotocol(); + var WebSocket3 = require_websocket(); + var { GUID, kWebSocket } = require_constants2(); + var keyRegex = /^[+/0-9A-Za-z]{22}==$/; + var RUNNING = 0; + var CLOSING = 1; + var CLOSED = 2; + var WebSocketServer2 = class extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Number} [options.backlog=511] The maximum length of the queue of + * pending connections + * @param {Boolean} [options.clientTracking=true] Specifies whether or not to + * track clients + * @param {Function} [options.handleProtocols] A hook to handle protocols + * @param {String} [options.host] The hostname where to bind the server + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Boolean} [options.noServer=false] Enable no server mode + * @param {String} [options.path] Accept only connections matching this path + * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable + * permessage-deflate + * @param {Number} [options.port] The port where to bind the server + * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S + * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @param {Function} [options.verifyClient] A hook to reject connections + * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` + * class to use. It must be the `WebSocket` class or class that extends it + * @param {Function} [callback] A listener for the `listening` event + */ + constructor(options2, callback) { + super(); + options2 = { + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + verifyClient: null, + noServer: false, + backlog: null, + // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + WebSocket: WebSocket3, + ...options2 + }; + if (options2.port == null && !options2.server && !options2.noServer || options2.port != null && (options2.server || options2.noServer) || options2.server && options2.noServer) { + throw new TypeError( + 'One and only one of the "port", "server", or "noServer" options must be specified' + ); + } + if (options2.port != null) { + this._server = http.createServer((req, res) => { + const body = http.STATUS_CODES[426]; + res.writeHead(426, { + "Content-Length": body.length, + "Content-Type": "text/plain" + }); + res.end(body); + }); + this._server.listen( + options2.port, + options2.host, + options2.backlog, + callback + ); + } else if (options2.server) { + this._server = options2.server; } - if (Common.isSchema(source)) { - for (const item of source._refs.refs) { - if (item.ancestor - target >= 0) { - this.refs.push({ ancestor: item.ancestor - target, root: item.root }); + if (this._server) { + const emitConnection = this.emit.bind(this, "connection"); + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, "listening"), + error: this.emit.bind(this, "error"), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, emitConnection); } - } - return; - } - if (exports2.isRef(source) && source.type === "value" && source.ancestor - target >= 0) { - this.refs.push({ ancestor: source.ancestor - target, root: source.root }); + }); } - Template = Template || require_template2(); - if (Template.isTemplate(source)) { - this.register(source.refs(), target); + if (options2.perMessageDeflate === true) options2.perMessageDeflate = {}; + if (options2.clientTracking) { + this.clients = /* @__PURE__ */ new Set(); + this._shouldEmitClose = false; } + this.options = options2; + this._state = RUNNING; } - get length() { - return this.refs.length; - } - clone() { - const copy2 = new exports2.Manager(); - copy2.refs = clone2(this.refs); - return copy2; - } - reset() { - this.refs = []; - } - roots() { - return this.refs.filter((ref) => !ref.ancestor).map((ref) => ref.root); - } - }; - } -}); -var require_template2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/template.js"(exports2, module14) { - "use strict"; - var { assert: assert2, clone: clone2, escapeHtml } = require_lib(); - var Formula = require_lib37(); - var Common = require_common3(); - var Errors = require_errors3(); - var Ref = require_ref2(); - var internals = { - symbol: Symbol("template"), - opens: new Array(1e3).join("\0"), - closes: new Array(1e3).join(""), - dateFormat: { - date: Date.prototype.toDateString, - iso: Date.prototype.toISOString, - string: Date.prototype.toString, - time: Date.prototype.toTimeString, - utc: Date.prototype.toUTCString - } - }; - module14.exports = exports2 = internals.Template = class { - constructor(source, options2) { - assert2(typeof source === "string", "Template source must be a string"); - assert2(!source.includes("\0") && !source.includes(""), "Template source cannot contain reserved control characters"); - this.source = source; - this.rendered = source; - this._template = null; - if (options2) { - const { functions, ...opts } = options2; - this._settings = Object.keys(opts).length ? clone2(opts) : void 0; - this._functions = functions; - if (this._functions) { - assert2(Object.keys(this._functions).every((key) => typeof key === "string"), "Functions keys must be strings"); - assert2(Object.values(this._functions).every((key) => typeof key === "function"), "Functions values must be functions"); - } - } else { - this._settings = void 0; - this._functions = void 0; + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); } - this._parse(); + if (!this._server) return null; + return this._server.address(); } - _parse() { - if (!this.source.includes("{")) { + /** + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. + * + * @param {Function} [cb] A one-time listener for the `'close'` event + * @public + */ + close(cb) { + if (this._state === CLOSED) { + if (cb) { + this.once("close", () => { + cb(new Error("The server is not running")); + }); + } + process.nextTick(emitClose, this); return; } - const encoded = internals.encode(this.source); - const parts = internals.split(encoded); - let refs = false; - const processed = []; - const head = parts.shift(); - if (head) { - processed.push(head); - } - for (const part of parts) { - const raw = part[0] !== "{"; - const ender = raw ? "}" : "}}"; - const end = part.indexOf(ender); - if (end === -1 || // Ignore non-matching closing - part[1] === "{") { - processed.push(`{${internals.decode(part)}`); - continue; - } - let variable = part.slice(raw ? 0 : 1, end); - const wrapped = variable[0] === ":"; - if (wrapped) { - variable = variable.slice(1); - } - const dynamic = this._ref(internals.decode(variable), { raw, wrapped }); - processed.push(dynamic); - if (typeof dynamic !== "string") { - refs = true; + if (cb) this.once("close", cb); + if (this._state === CLOSING) return; + this._state = CLOSING; + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; } - const rest = part.slice(end + ender.length); - if (rest) { - processed.push(internals.decode(rest)); + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); } + } else { + const server = this._server; + this._removeListeners(); + this._removeListeners = this._server = null; + server.close(() => { + emitClose(this); + }); } - if (!refs) { - this.rendered = processed.join(""); - return; - } - this._template = processed; - } - static date(date3, prefs) { - return internals.dateFormat[prefs.dateFormat].call(date3); } - describe(options2 = {}) { - if (!this._settings && options2.compact) { - return this.source; - } - const desc = { template: this.source }; - if (this._settings) { - desc.options = this._settings; - } - if (this._functions) { - desc.functions = this._functions; + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf("?"); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + if (pathname !== this.options.path) return false; } - return desc; - } - static build(desc) { - return new internals.Template(desc.template, desc.options || desc.functions ? { ...desc.options, functions: desc.functions } : void 0); - } - isDynamic() { - return !!this._template; - } - static isTemplate(template) { - return template ? !!template[Common.symbols.template] : false; + return true; } - refs() { - if (!this._template) { - return; + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on("error", socketOnError); + const key = req.headers["sec-websocket-key"] !== void 0 ? req.headers["sec-websocket-key"] : false; + const version3 = +req.headers["sec-websocket-version"]; + if (req.method !== "GET" || req.headers.upgrade.toLowerCase() !== "websocket" || !key || !keyRegex.test(key) || version3 !== 8 && version3 !== 13 || !this.shouldHandle(req)) { + return abortHandshake(socket, 400); } - const refs = []; - for (const part of this._template) { - if (typeof part !== "string") { - refs.push(...part.refs); + const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; + let protocols = /* @__PURE__ */ new Set(); + if (secWebSocketProtocol !== void 0) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + return abortHandshake(socket, 400); } } - return refs; - } - resolve(value, state, prefs, local) { - if (this._template && this._template.length === 1) { - return this._part( - this._template[0], - /* context -> [*/ - value, - state, - prefs, - local, - {} - /*] */ + const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; + const extensions = {}; + if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { + const perMessageDeflate = new PerMessageDeflate( + this.options.perMessageDeflate, + true, + this.options.maxPayload ); - } - return this.render(value, state, prefs, local); - } - _part(part, ...args) { - if (part.ref) { - return part.ref.resolve(...args); - } - return part.formula.evaluate(args); - } - render(value, state, prefs, local, options2 = {}) { - if (!this.isDynamic()) { - return this.rendered; - } - const parts = []; - for (const part of this._template) { - if (typeof part === "string") { - parts.push(part); - } else { - const rendered = this._part( - part, - /* context -> [*/ - value, - state, - prefs, - local, - options2 - /*] */ - ); - const string3 = internals.stringify(rendered, value, state, prefs, local, options2); - if (string3 !== void 0) { - const result = part.raw || (options2.errors && options2.errors.escapeHtml) === false ? string3 : escapeHtml(string3); - parts.push(internals.wrap(result, part.wrapped && prefs.errors.wrap.label)); + try { + const offers = extension.parse(secWebSocketExtensions); + if (offers[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; } + } catch (err) { + return abortHandshake(socket, 400); } } - return parts.join(""); - } - _ref(content, { raw, wrapped }) { - const refs = []; - const reference = (variable) => { - const ref = Ref.create(variable, this._settings); - refs.push(ref); - return (context) => { - const resolved = ref.resolve(...context); - return resolved !== void 0 ? resolved : null; + if (this.options.verifyClient) { + const info = { + origin: req.headers[`${version3 === 8 ? "sec-websocket-origin" : "origin"}`], + secure: !!(req.socket.authorized || req.socket.encrypted), + req }; - }; - try { - const functions = this._functions ? { ...internals.functions, ...this._functions } : internals.functions; - var formula = new Formula.Parser(content, { reference, functions, constants: internals.constants }); - } catch (err) { - err.message = `Invalid template variable "${content}" fails due to: ${err.message}`; - throw err; - } - if (formula.single) { - if (formula.single.type === "reference") { - const ref = refs[0]; - return { ref, raw, refs, wrapped: wrapped || ref.type === "local" && ref.key === "label" }; + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code2, message, headers) => { + if (!verified) { + return abortHandshake(socket, code2 || 401, message, headers); + } + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); + }); + return; } - return internals.stringify(formula.single.value); - } - return { formula, raw, refs }; - } - toString() { - return this.source; - } - }; - internals.Template.prototype[Common.symbols.template] = true; - internals.Template.prototype.isImmutable = true; - internals.encode = function(string3) { - return string3.replace(/\\(\{+)/g, ($0, $1) => { - return internals.opens.slice(0, $1.length); - }).replace(/\\(\}+)/g, ($0, $1) => { - return internals.closes.slice(0, $1.length); - }); - }; - internals.decode = function(string3) { - return string3.replace(/\u0000/g, "{").replace(/\u0001/g, "}"); - }; - internals.split = function(string3) { - const parts = []; - let current = ""; - for (let i2 = 0; i2 < string3.length; ++i2) { - const char = string3[i2]; - if (char === "{") { - let next = ""; - while (i2 + 1 < string3.length && string3[i2 + 1] === "{") { - next += "{"; - ++i2; - } - parts.push(current); - current = next; - } else { - current += char; - } - } - parts.push(current); - return parts; - }; - internals.wrap = function(value, ends) { - if (!ends) { - return value; - } - if (ends.length === 1) { - return `${ends}${value}${ends}`; - } - return `${ends[0]}${value}${ends[1]}`; - }; - internals.stringify = function(value, original, state, prefs, local, options2 = {}) { - const type = typeof value; - const wrap2 = prefs && prefs.errors && prefs.errors.wrap || {}; - let skipWrap = false; - if (Ref.isRef(value) && value.render) { - skipWrap = value.in; - value = value.resolve(original, state, prefs, local, { in: value.in, ...options2 }); - } - if (value === null) { - return "null"; - } - if (type === "string") { - return internals.wrap(value, options2.arrayItems && wrap2.string); - } - if (type === "number" || type === "function" || type === "symbol") { - return value.toString(); - } - if (type !== "object") { - return JSON.stringify(value); - } - if (value instanceof Date) { - return internals.Template.date(value, prefs); - } - if (value instanceof Map) { - const pairs = []; - for (const [key, sym] of value.entries()) { - pairs.push(`${key.toString()} -> ${sym.toString()}`); - } - value = pairs; - } - if (!Array.isArray(value)) { - return value.toString(); - } - const values = []; - for (const item of value) { - values.push(internals.stringify(item, original, state, prefs, local, { arrayItems: true, ...options2 })); - } - return internals.wrap(values.join(", "), !skipWrap && wrap2.array); - }; - internals.constants = { - true: true, - false: false, - null: null, - second: 1e3, - minute: 60 * 1e3, - hour: 60 * 60 * 1e3, - day: 24 * 60 * 60 * 1e3 - }; - internals.functions = { - if(condition, then, otherwise) { - return condition ? then : otherwise; - }, - length(item) { - if (typeof item === "string") { - return item.length; - } - if (!item || typeof item !== "object") { - return null; - } - if (Array.isArray(item)) { - return item.length; - } - return Object.keys(item).length; - }, - msg(code2) { - const [value, state, prefs, local, options2] = this; - const messages = options2.messages; - if (!messages) { - return ""; - } - const template = Errors.template(value, messages[0], code2, state, prefs) || Errors.template(value, messages[1], code2, state, prefs); - if (!template) { - return ""; - } - return template.render(value, state, prefs, local, options2); - }, - number(value) { - if (typeof value === "number") { - return value; - } - if (typeof value === "string") { - return parseFloat(value); - } - if (typeof value === "boolean") { - return value ? 1 : 0; - } - if (value instanceof Date) { - return value.getTime(); + if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); } - return null; - } - }; - } -}); -var require_messages2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/messages.js"(exports2) { - "use strict"; - var { assert: assert2, clone: clone2 } = require_lib(); - var Template = require_template2(); - exports2.compile = function(messages, target) { - if (typeof messages === "string") { - assert2(!target, "Cannot set single message string"); - return new Template(messages); - } - if (Template.isTemplate(messages)) { - assert2(!target, "Cannot set single message template"); - return messages; + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); } - assert2(typeof messages === "object" && !Array.isArray(messages), "Invalid message options"); - target = target ? clone2(target) : {}; - for (let code2 in messages) { - const message = messages[code2]; - if (code2 === "root" || Template.isTemplate(message)) { - target[code2] = message; - continue; - } - if (typeof message === "string") { - target[code2] = new Template(message); - continue; + /** + * Upgrade the connection to WebSocket. + * + * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket + * @private + */ + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { + if (!socket.readable || !socket.writable) return socket.destroy(); + if (socket[kWebSocket]) { + throw new Error( + "server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" + ); } - assert2(typeof message === "object" && !Array.isArray(message), "Invalid message for", code2); - const language = code2; - target[language] = target[language] || {}; - for (code2 in message) { - const localized = message[code2]; - if (code2 === "root" || Template.isTemplate(localized)) { - target[language][code2] = localized; - continue; + if (this._state > RUNNING) return abortHandshake(socket, 503); + const digest = createHash("sha1").update(key + GUID).digest("base64"); + const headers = [ + "HTTP/1.1 101 Switching Protocols", + "Upgrade: websocket", + "Connection: Upgrade", + `Sec-WebSocket-Accept: ${digest}` + ]; + const ws = new this.options.WebSocket(null); + if (protocols.size) { + const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws._protocol = protocol; } - assert2(typeof localized === "string", "Invalid message for", code2, "in", language); - target[language][code2] = new Template(localized); - } - } - return target; - }; - exports2.decompile = function(messages) { - const target = {}; - for (let code2 in messages) { - const message = messages[code2]; - if (code2 === "root") { - target.root = message; - continue; } - if (Template.isTemplate(message)) { - target[code2] = message.describe({ compact: true }); - continue; + if (extensions[PerMessageDeflate.extensionName]) { + const params = extensions[PerMessageDeflate.extensionName].params; + const value = extension.format({ + [PerMessageDeflate.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; } - const language = code2; - target[language] = {}; - for (code2 in message) { - const localized = message[code2]; - if (code2 === "root") { - target[language].root = localized; - continue; - } - target[language][code2] = localized.describe({ compact: true }); + this.emit("headers", headers, req); + socket.write(headers.concat("\r\n").join("\r\n")); + socket.removeListener("error", socketOnError); + ws.setSocket(socket, head, { + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation + }); + if (this.clients) { + this.clients.add(ws); + ws.on("close", () => { + this.clients.delete(ws); + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); + } + }); } + cb(ws, req); } - return target; }; - exports2.merge = function(base2, extended) { - if (!base2) { - return exports2.compile(extended); - } - if (!extended) { - return base2; - } - if (typeof extended === "string") { - return new Template(extended); - } - if (Template.isTemplate(extended)) { - return extended; - } - const target = clone2(base2); - for (let code2 in extended) { - const message = extended[code2]; - if (code2 === "root" || Template.isTemplate(message)) { - target[code2] = message; - continue; - } - if (typeof message === "string") { - target[code2] = new Template(message); - continue; - } - assert2(typeof message === "object" && !Array.isArray(message), "Invalid message for", code2); - const language = code2; - target[language] = target[language] || {}; - for (code2 in message) { - const localized = message[code2]; - if (code2 === "root" || Template.isTemplate(localized)) { - target[language][code2] = localized; - continue; - } - assert2(typeof localized === "string", "Invalid message for", code2, "in", language); - target[language][code2] = new Template(localized); + module14.exports = WebSocketServer2; + function addListeners(server, map) { + for (const event of Object.keys(map)) server.on(event, map[event]); + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); } + }; + } + function emitClose(server) { + server._state = CLOSED; + server.emit("close"); + } + function socketOnError() { + this.destroy(); + } + function abortHandshake(socket, code2, message, headers) { + if (socket.writable) { + message = message || http.STATUS_CODES[code2]; + headers = { + Connection: "close", + "Content-Type": "text/html", + "Content-Length": Buffer.byteLength(message), + ...headers + }; + socket.write( + `HTTP/1.1 ${code2} ${http.STATUS_CODES[code2]}\r +` + Object.keys(headers).map((h2) => `${h2}: ${headers[h2]}`).join("\r\n") + "\r\n\r\n" + message + ); } - return target; - }; + socket.removeListener("error", socketOnError); + socket.destroy(); + } } }); -var require_common3 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/common.js"(exports2) { - "use strict"; - var { assert: Assert, AssertError } = require_lib(); - var Pkg = require_package7(); - var Messages; - var Schemas; - var internals = { - isoDate: /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/ - }; - exports2.version = Pkg.version; - exports2.defaults = { - abortEarly: true, - allowUnknown: false, - artifacts: false, - cache: true, - context: null, - convert: true, - dateFormat: "iso", - errors: { - escapeHtml: false, - label: "path", - language: null, - render: true, - stack: false, - wrap: { - label: '"', - array: "[]" - } - }, - externals: true, - messages: {}, - nonEnumerables: false, - noDefaults: false, - presence: "optional", - skipFunctions: false, - stripUnknown: false, - warnings: false - }; - exports2.symbols = { - any: Symbol.for("@hapi/joi/schema"), - // Used to internally identify any-based types (shared with other joi versions) - arraySingle: Symbol("arraySingle"), - deepDefault: Symbol("deepDefault"), - errors: Symbol("errors"), - literal: Symbol("literal"), - override: Symbol("override"), - parent: Symbol("parent"), - prefs: Symbol("prefs"), - ref: Symbol("ref"), - template: Symbol("template"), - values: Symbol("values") - }; - exports2.assertOptions = function(options2, keys, name = "Options") { - Assert(options2 && typeof options2 === "object" && !Array.isArray(options2), "Options must be of type object"); - const unknownKeys = Object.keys(options2).filter((k) => !keys.includes(k)); - Assert(unknownKeys.length === 0, `${name} contain unknown keys: ${unknownKeys}`); - }; - exports2.checkPreferences = function(prefs) { - Schemas = Schemas || require_schemas2(); - const result = Schemas.preferences.validate(prefs); - if (result.error) { - throw new AssertError([result.error.details[0].message]); - } - }; - exports2.compare = function(a, b, operator) { - switch (operator) { - case "=": - return a === b; - case ">": - return a > b; - case "<": - return a < b; - case ">=": - return a >= b; - case "<=": - return a <= b; - } - }; - exports2.default = function(value, defaultValue) { - return value === void 0 ? defaultValue : value; - }; - exports2.isIsoDate = function(date3) { - return internals.isoDate.test(date3); - }; - exports2.isNumber = function(value) { - return typeof value === "number" && !isNaN(value); - }; - exports2.isResolvable = function(obj) { - if (!obj) { - return false; - } - return obj[exports2.symbols.ref] || obj[exports2.symbols.template]; - }; - exports2.isSchema = function(schema, options2 = {}) { - const any = schema && schema[exports2.symbols.any]; - if (!any) { - return false; - } - Assert(options2.legacy || any.version === exports2.version, "Cannot mix different versions of joi schemas"); - return true; - }; - exports2.isValues = function(obj) { - return obj[exports2.symbols.values]; - }; - exports2.limit = function(value) { - return Number.isSafeInteger(value) && value >= 0; - }; - exports2.preferences = function(target, source) { - Messages = Messages || require_messages2(); - target = target || {}; - source = source || {}; - const merged = Object.assign({}, target, source); - if (source.errors && target.errors) { - merged.errors = Object.assign({}, target.errors, source.errors); - merged.errors.wrap = Object.assign({}, target.errors.wrap, source.errors.wrap); - } - if (source.messages) { - merged.messages = Messages.compile(source.messages, target.messages); - } - delete merged[exports2.symbols.prefs]; - return merged; - }; - exports2.tryWithPath = function(fn, key, options2 = {}) { - try { - return fn(); - } catch (err) { - if (err.path !== void 0) { - err.path = key + "." + err.path; - } else { - err.path = key; - } - if (options2.append) { - err.message = `${err.message} (${err.path})`; - } - throw err; - } - }; - exports2.validateArg = function(value, label, { assert: assert2, message }) { - if (exports2.isSchema(assert2)) { - const result = assert2.validate(value); - if (!result.error) { - return; - } - return result.error.message; - } else if (!assert2(value)) { - return label ? `${label} ${message}` : message; - } - }; - exports2.verifyFlat = function(args, method) { - for (const arg of args) { - Assert(!Array.isArray(arg), "Method no longer accepts array arguments:", method); - } - }; +var import_stream2; +var import_receiver; +var import_sender; +var import_websocket3; +var import_websocket_server; +var wrapper_default; +var init_wrapper = __esm({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/wrapper.mjs"() { + import_stream2 = __toESM(require_stream(), 1); + import_receiver = __toESM(require_receiver(), 1); + import_sender = __toESM(require_sender(), 1); + import_websocket3 = __toESM(require_websocket(), 1); + import_websocket_server = __toESM(require_websocket_server(), 1); + wrapper_default = import_websocket3.default; } }); -var require_cache2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/cache.js"(exports2) { - "use strict"; - var { assert: assert2, clone: clone2 } = require_lib(); - var Common = require_common3(); - var internals = { - max: 1e3, - supported: /* @__PURE__ */ new Set(["undefined", "boolean", "number", "string"]) - }; - exports2.provider = { - provision(options2) { - return new internals.Cache(options2); - } - }; - internals.Cache = class { - constructor(options2 = {}) { - Common.assertOptions(options2, ["max"]); - assert2(options2.max === void 0 || options2.max && options2.max > 0 && isFinite(options2.max), "Invalid max cache size"); - this._max = options2.max || internals.max; - this._map = /* @__PURE__ */ new Map(); - this._list = new internals.List(); - } - get length() { - return this._map.size; - } - set(key, value) { - if (key !== null && !internals.supported.has(typeof key)) { - return; - } - let node = this._map.get(key); - if (node) { - node.value = value; - this._list.first(node); - return; - } - node = this._list.unshift({ key, value }); - this._map.set(key, node); - this._compact(); - } - get(key) { - const node = this._map.get(key); - if (node) { - this._list.first(node); - return clone2(node.value); - } - } - _compact() { - if (this._map.size > this._max) { - const node = this._list.pop(); - this._map.delete(node.key); - } - } - }; - internals.List = class { - constructor() { - this.tail = null; - this.head = null; - } - unshift(node) { - node.next = null; - node.prev = this.head; - if (this.head) { - this.head.next = node; - } - this.head = node; - if (!this.tail) { - this.tail = node; - } - return node; - } - first(node) { - if (node === this.head) { - return; - } - this._remove(node); - this.unshift(node); +function createErrorResponse(data) { + return JSON.stringify({ type: ERROR, data }); +} +function createPushErrorResponse(data) { + return JSON.stringify({ + type: ERROR, + data: { + ...data, + type: REQUEST_TYPE.PUSH_ACTION + } + }); +} +function createNotification(type, data) { + return JSON.stringify({ type, data }); +} +function createOkResponse(data) { + return JSON.stringify({ type: OK, data }); +} +function createServer(httpServer2, options2 = {}) { + const server = new import_websocket_server.default({ + ...defaultOptions3, + ...options2, + ...{ clientTracking: true }, + server: httpServer2 + }); + server.channels = /* @__PURE__ */ new Set(); + server.customServerEventHandlers = { ...options2.serverHandlers }; + server.customSocketEventHandlers = { ...options2.socketHandlers }; + server.customMessageHandlers = { ...options2.messageHandlers }; + server.pingIntervalID = void 0; + server.subscribersByChannelID = /* @__PURE__ */ Object.create(null); + server.pushSubscriptions = /* @__PURE__ */ Object.create(null); + const handlers = Object.keys(defaultServerHandlers); + handlers.forEach((name) => { + server.on(name, (...args) => { + try { + ; + defaultServerHandlers[name].apply(server, args); + server.customServerEventHandlers[name]?.apply(server, args); + } catch (error2) { + server.emit("error", error2); } - pop() { - return this._remove(this.tail); + }); + }); + if (server.options.pingInterval > 0) { + server.pingIntervalID = setInterval(() => { + if (server.clients.size && server.options.logPingRounds) { + log.debug("Pinging clients"); } - _remove(node) { - const { next, prev } = node; - next.prev = prev; - if (prev) { - prev.next = next; + server.clients.forEach((client) => { + if (isPushSubscriptionInfo(client)) return; + if (client.pinged && !client.activeSinceLastPing) { + log(`Disconnecting irresponsive client ${client.id}`); + return client.terminate(); } - if (node === this.tail) { - this.tail = next; + if (client.readyState === wrapper_default.OPEN) { + client.send(createMessage(PING, Date.now()), () => { + client.activeSinceLastPing = false; + client.pinged = true; + }); } - node.prev = null; - node.next = null; - return node; - } - }; + }); + }, server.options.pingInterval); } -}); -var require_compile2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/compile.js"(exports2) { + return Object.assign(server, publicMethods2); +} +var import_npm_chalk; +var isPushSubscriptionInfo; +var bold; +var PING; +var PONG; +var PUB; +var SUB; +var UNSUB; +var KV_FILTER; +var ERROR; +var OK; +var defaultOptions3; +var tag2; +var generateSocketID; +var log; +var defaultServerHandlers; +var defaultSocketEventHandlers; +var defaultMessageHandlers2; +var publicMethods2; +var init_pubsub2 = __esm({ + "src/serve/pubsub.ts"() { "use strict"; - var { assert: assert2 } = require_lib(); - var Common = require_common3(); - var Ref = require_ref2(); - var internals = {}; - exports2.schema = function(Joi2, config2, options2 = {}) { - Common.assertOptions(options2, ["appendPath", "override"]); - try { - return internals.schema(Joi2, config2, options2); - } catch (err) { - if (options2.appendPath && err.path !== void 0) { - err.message = `${err.message} (${err.path})`; - } - throw err; - } - }; - internals.schema = function(Joi2, config2, options2) { - assert2(config2 !== void 0, "Invalid undefined schema"); - if (Array.isArray(config2)) { - assert2(config2.length, "Invalid empty array schema"); - if (config2.length === 1) { - config2 = config2[0]; - } - } - const valid = (base2, ...values) => { - if (options2.override !== false) { - return base2.valid(Joi2.override, ...values); - } - return base2.valid(...values); - }; - if (internals.simple(config2)) { - return valid(Joi2, config2); - } - if (typeof config2 === "function") { - return Joi2.custom(config2); - } - assert2(typeof config2 === "object", "Invalid schema content:", typeof config2); - if (Common.isResolvable(config2)) { - return valid(Joi2, config2); - } - if (Common.isSchema(config2)) { - return config2; - } - if (Array.isArray(config2)) { - for (const item of config2) { - if (!internals.simple(item)) { - return Joi2.alternatives().try(...config2); - } - } - return valid(Joi2, ...config2); - } - if (config2 instanceof RegExp) { - return Joi2.string().regex(config2); - } - if (config2 instanceof Date) { - return valid(Joi2.date(), config2); - } - assert2(Object.getPrototypeOf(config2) === Object.getPrototypeOf({}), "Schema can only contain plain objects"); - return Joi2.object().keys(config2); - }; - exports2.ref = function(id, options2) { - return Ref.isRef(id) ? id : Ref.create(id, options2); + init_esm5(); + init_pubsub(); + init_push(); + init_logger(); + import_npm_chalk = __toESM(require_source()); + init_wrapper(); + isPushSubscriptionInfo = (x3) => { + return has(x3, "endpoint"); }; - exports2.compile = function(root, schema, options2 = {}) { - Common.assertOptions(options2, ["legacy"]); - const any = schema && schema[Common.symbols.any]; - if (any) { - assert2(options2.legacy || any.version === Common.version, "Cannot mix different versions of joi schemas:", any.version, Common.version); - return schema; - } - if (typeof schema !== "object" || !options2.legacy) { - return exports2.schema(root, schema, { appendPath: true }); - } - const compiler = internals.walk(schema); - if (!compiler) { - return exports2.schema(root, schema, { appendPath: true }); - } - return compiler.compile(compiler.root, schema); + ({ bold } = import_npm_chalk.default); + ({ PING, PONG, PUB, SUB, UNSUB, KV_FILTER } = NOTIFICATION_TYPE); + ({ ERROR, OK } = RESPONSE_TYPE); + defaultOptions3 = { + logPingRounds: process8.env.NODE_ENV !== "production" && !process8.env.CI, + logPongMessages: false, + maxPayload: 6 * 1024 * 1024, + pingInterval: 3e4 }; - internals.walk = function(schema) { - if (typeof schema !== "object") { - return null; - } - if (Array.isArray(schema)) { - for (const item of schema) { - const compiler = internals.walk(item); - if (compiler) { - return compiler; + tag2 = "[pubsub]"; + generateSocketID = /* @__PURE__ */ (() => { + let counter = 0; + return (debugID) => String(counter++) + (debugID ? "-" + debugID : ""); + })(); + log = logger_default.info.bind(logger_default, tag2); + log.bold = (...args) => logger_default.debug(bold(tag2, ...args)); + log.debug = logger_default.debug.bind(logger_default, tag2); + log.error = (error2, ...args) => logger_default.error(error2, bold.red(tag2, ...args)); + defaultServerHandlers = { + close() { + log("Server closed"); + }, + /** + * Emitted when a connection handshake completes. + * + * @see https://github.com/websockets/ws/blob/master/doc/ws.md#event-connection + * @param {ws.WebSocket} socket - The client socket that connected. + * @param {http.IncomingMessage} request - The underlying Node http GET request. + */ + connection(socket, request) { + const server = this; + const url2 = request.url; + const urlSearch = url2?.includes("?") ? url2.slice(url2.lastIndexOf("?")) : ""; + const debugID = new URLSearchParams(urlSearch).get("debugID") || ""; + const send = socket.send.bind(socket); + socket.id = generateSocketID(debugID); + socket.activeSinceLastPing = true; + socket.pinged = false; + socket.server = server; + socket.subscriptions = /* @__PURE__ */ new Set(); + socket.kvFilter = /* @__PURE__ */ new Map(); + socket.ip = request.headers["x-real-ip"] || request.headers["x-forwarded-for"]?.split(",")[0].trim() || request.socket.remoteAddress; + socket.send = function(data) { + if (typeof data === "object" && data !== null && typeof data[Symbol.toPrimitive] === "function") { + return send(data[Symbol.toPrimitive]()); } - } - return null; - } - const any = schema[Common.symbols.any]; - if (any) { - return { root: schema[any.root], compile: any.compile }; - } - assert2(Object.getPrototypeOf(schema) === Object.getPrototypeOf({}), "Schema can only contain plain objects"); - for (const key in schema) { - const compiler = internals.walk(schema[key]); - if (compiler) { - return compiler; - } - } - return null; - }; - internals.simple = function(value) { - return value === null || ["boolean", "string", "number"].includes(typeof value); - }; - exports2.when = function(schema, condition, options2) { - if (options2 === void 0) { - assert2(condition && typeof condition === "object", "Missing options"); - options2 = condition; - condition = Ref.create("."); - } - if (Array.isArray(options2)) { - options2 = { switch: options2 }; - } - Common.assertOptions(options2, ["is", "not", "then", "otherwise", "switch", "break"]); - if (Common.isSchema(condition)) { - assert2(options2.is === void 0, '"is" can not be used with a schema condition'); - assert2(options2.not === void 0, '"not" can not be used with a schema condition'); - assert2(options2.switch === void 0, '"switch" can not be used with a schema condition'); - return internals.condition(schema, { is: condition, then: options2.then, otherwise: options2.otherwise, break: options2.break }); - } - assert2(Ref.isRef(condition) || typeof condition === "string", "Invalid condition:", condition); - assert2(options2.not === void 0 || options2.is === void 0, 'Cannot combine "is" with "not"'); - if (options2.switch === void 0) { - let rule2 = options2; - if (options2.not !== void 0) { - rule2 = { is: options2.not, then: options2.otherwise, otherwise: options2.then, break: options2.break }; - } - let is = rule2.is !== void 0 ? schema.$_compile(rule2.is) : schema.$_root.invalid(null, false, 0, "").required(); - assert2(rule2.then !== void 0 || rule2.otherwise !== void 0, 'options must have at least one of "then", "otherwise", or "switch"'); - assert2(rule2.break === void 0 || rule2.then === void 0 || rule2.otherwise === void 0, "Cannot specify then, otherwise, and break all together"); - if (options2.is !== void 0 && !Ref.isRef(options2.is) && !Common.isSchema(options2.is)) { - is = is.required(); - } - return internals.condition(schema, { ref: exports2.ref(condition), is, then: rule2.then, otherwise: rule2.otherwise, break: rule2.break }); - } - assert2(Array.isArray(options2.switch), '"switch" must be an array'); - assert2(options2.is === void 0, 'Cannot combine "switch" with "is"'); - assert2(options2.not === void 0, 'Cannot combine "switch" with "not"'); - assert2(options2.then === void 0, 'Cannot combine "switch" with "then"'); - const rule = { - ref: exports2.ref(condition), - switch: [], - break: options2.break - }; - for (let i2 = 0; i2 < options2.switch.length; ++i2) { - const test = options2.switch[i2]; - const last = i2 === options2.switch.length - 1; - Common.assertOptions(test, last ? ["is", "then", "otherwise"] : ["is", "then"]); - assert2(test.is !== void 0, 'Switch statement missing "is"'); - assert2(test.then !== void 0, 'Switch statement missing "then"'); - const item = { - is: schema.$_compile(test.is), - then: schema.$_compile(test.then) + return send(data); }; - if (!Ref.isRef(test.is) && !Common.isSchema(test.is)) { - item.is = item.is.required(); - } - if (last) { - assert2(options2.otherwise === void 0 || test.otherwise === void 0, 'Cannot specify "otherwise" inside and outside a "switch"'); - const otherwise = options2.otherwise !== void 0 ? options2.otherwise : test.otherwise; - if (otherwise !== void 0) { - assert2(rule.break === void 0, "Cannot specify both otherwise and break"); - item.otherwise = schema.$_compile(otherwise); - } - } - rule.switch.push(item); - } - return rule; - }; - internals.condition = function(schema, condition) { - for (const key of ["then", "otherwise"]) { - if (condition[key] === void 0) { - delete condition[key]; - } else { - condition[key] = schema.$_compile(condition[key]); - } - } - return condition; - }; - } -}); -var require_extend2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/extend.js"(exports2) { - "use strict"; - var { assert: assert2, clone: clone2 } = require_lib(); - var Common = require_common3(); - var Messages = require_messages2(); - var internals = {}; - exports2.type = function(from3, options2) { - const base2 = Object.getPrototypeOf(from3); - const prototype = clone2(base2); - const schema = from3._assign(Object.create(prototype)); - const def = Object.assign({}, options2); - delete def.base; - prototype._definition = def; - const parent = base2._definition || {}; - def.messages = Messages.merge(parent.messages, def.messages); - def.properties = Object.assign({}, parent.properties, def.properties); - schema.type = def.type; - def.flags = Object.assign({}, parent.flags, def.flags); - const terms = Object.assign({}, parent.terms); - if (def.terms) { - for (const name in def.terms) { - const term = def.terms[name]; - assert2(schema.$_terms[name] === void 0, "Invalid term override for", def.type, name); - schema.$_terms[name] = term.init; - terms[name] = term; - } - } - def.terms = terms; - if (!def.args) { - def.args = parent.args; - } - def.prepare = internals.prepare(def.prepare, parent.prepare); - if (def.coerce) { - if (typeof def.coerce === "function") { - def.coerce = { method: def.coerce }; - } - if (def.coerce.from && !Array.isArray(def.coerce.from)) { - def.coerce = { method: def.coerce.method, from: [].concat(def.coerce.from) }; - } - } - def.coerce = internals.coerce(def.coerce, parent.coerce); - def.validate = internals.validate(def.validate, parent.validate); - const rules = Object.assign({}, parent.rules); - if (def.rules) { - for (const name in def.rules) { - const rule = def.rules[name]; - assert2(typeof rule === "object", "Invalid rule definition for", def.type, name); - let method = rule.method; - if (method === void 0) { - method = function() { - return this.$_addRule(name); - }; - } - if (method) { - assert2(!prototype[name], "Rule conflict in", def.type, name); - prototype[name] = method; - } - assert2(!rules[name], "Rule conflict in", def.type, name); - rules[name] = rule; - if (rule.alias) { - const aliases = [].concat(rule.alias); - for (const alias of aliases) { - prototype[alias] = rule.method; - } - } - if (rule.args) { - rule.argsByName = /* @__PURE__ */ new Map(); - rule.args = rule.args.map((arg) => { - if (typeof arg === "string") { - arg = { name: arg }; - } - assert2(!rule.argsByName.has(arg.name), "Duplicated argument name", arg.name); - if (Common.isSchema(arg.assert)) { - arg.assert = arg.assert.strict().label(arg.name); - } - rule.argsByName.set(arg.name, arg); - return arg; - }); - } - } - } - def.rules = rules; - const modifiers = Object.assign({}, parent.modifiers); - if (def.modifiers) { - for (const name in def.modifiers) { - assert2(!prototype[name], "Rule conflict in", def.type, name); - const modifier = def.modifiers[name]; - assert2(typeof modifier === "function", "Invalid modifier definition for", def.type, name); - const method = function(arg) { - return this.rule({ [name]: arg }); - }; - prototype[name] = method; - modifiers[name] = modifier; - } - } - def.modifiers = modifiers; - if (def.overrides) { - prototype._super = base2; - schema.$_super = {}; - for (const override in def.overrides) { - assert2(base2[override], "Cannot override missing", override); - def.overrides[override][Common.symbols.parent] = base2[override]; - schema.$_super[override] = base2[override].bind(schema); - } - Object.assign(prototype, def.overrides); - } - def.cast = Object.assign({}, parent.cast, def.cast); - const manifest2 = Object.assign({}, parent.manifest, def.manifest); - manifest2.build = internals.build(def.manifest && def.manifest.build, parent.manifest && parent.manifest.build); - def.manifest = manifest2; - def.rebuild = internals.rebuild(def.rebuild, parent.rebuild); - return schema; - }; - internals.build = function(child, parent) { - if (!child || !parent) { - return child || parent; - } - return function(obj, desc) { - return parent(child(obj, desc), desc); - }; - }; - internals.coerce = function(child, parent) { - if (!child || !parent) { - return child || parent; - } - return { - from: child.from && parent.from ? [.../* @__PURE__ */ new Set([...child.from, ...parent.from])] : null, - method(value, helpers) { - let coerced; - if (!parent.from || parent.from.includes(typeof value)) { - coerced = parent.method(value, helpers); - if (coerced) { - if (coerced.errors || coerced.value === void 0) { - return coerced; - } - value = coerced.value; + log.bold(`Socket ${socket.id} connected. Total: ${this.clients.size}`); + ["close", "error", "message", "ping", "pong"].forEach((eventName) => { + socket.on(eventName, (...args) => { + if (eventName !== "message") { + log.debug(`Event '${eventName}' on socket ${socket.id}`, ...args.map((arg) => String(arg))); } - } - if (!child.from || child.from.includes(typeof value)) { - const own = child.method(value, helpers); - if (own) { - return own; + try { + ; + defaultSocketEventHandlers[eventName]?.call(socket, ...args); + socket.server.customSocketEventHandlers[eventName]?.call(socket, ...args); + } catch (error2) { + socket.server.emit("error", error2); + socket.terminate(); } - } - return coerced; - } - }; - }; - internals.prepare = function(child, parent) { - if (!child || !parent) { - return child || parent; - } - return function(value, helpers) { - const prepared = child(value, helpers); - if (prepared) { - if (prepared.errors || prepared.value === void 0) { - return prepared; - } - value = prepared.value; - } - return parent(value, helpers) || prepared; - }; - }; - internals.rebuild = function(child, parent) { - if (!child || !parent) { - return child || parent; - } - return function(schema) { - parent(schema); - child(schema); - }; - }; - internals.validate = function(child, parent) { - if (!child || !parent) { - return child || parent; + }); + }); + }, + error(error2) { + log.error(error2, "Server error"); + }, + headers() { + }, + listening() { + log("Server listening"); } - return function(value, helpers) { - const result = parent(value, helpers); - if (result) { - if (result.errors && (!Array.isArray(result.errors) || result.errors.length)) { - return result; - } - value = result.value; - } - return child(value, helpers) || result; - }; }; - } -}); -var require_manifest = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/manifest.js"(exports2) { - "use strict"; - var { assert: assert2, clone: clone2 } = require_lib(); - var Common = require_common3(); - var Messages = require_messages2(); - var Ref = require_ref2(); - var Template = require_template2(); - var Schemas; - var internals = {}; - exports2.describe = function(schema) { - const def = schema._definition; - const desc = { - type: schema.type, - flags: {}, - rules: [] - }; - for (const flag in schema._flags) { - if (flag[0] !== "_") { - desc.flags[flag] = internals.describe(schema._flags[flag]); - } - } - if (!Object.keys(desc.flags).length) { - delete desc.flags; - } - if (schema._preferences) { - desc.preferences = clone2(schema._preferences, { shallow: ["messages"] }); - delete desc.preferences[Common.symbols.prefs]; - if (desc.preferences.messages) { - desc.preferences.messages = Messages.decompile(desc.preferences.messages); + defaultSocketEventHandlers = { + close() { + const socket = this; + const { server } = this; + for (const channelID of socket.subscriptions) { + server.subscribersByChannelID[channelID].delete(socket); } - } - if (schema._valids) { - desc.allow = schema._valids.describe(); - } - if (schema._invalids) { - desc.invalid = schema._invalids.describe(); - } - for (const rule of schema._rules) { - const ruleDef = def.rules[rule.name]; - if (ruleDef.manifest === false) { - continue; + socket.subscriptions.clear(); + }, + message(data) { + const socket = this; + const { server } = this; + const text = data.toString(); + let msg = { type: "" }; + try { + msg = messageParser(text); + } catch (error2) { + log.error(error2, `Malformed message: ${error2.message}`); + server.rejectMessageAndTerminateSocket(msg, socket); + return; } - const item = { name: rule.name }; - for (const custom in def.modifiers) { - if (rule[custom] !== void 0) { - item[custom] = internals.describe(rule[custom]); - } + if (msg.type !== "pong" || server.options.logPongMessages) { + log.debug(`Received '${msg.type}' on socket ${socket.id}`, text); } - if (rule.args) { - item.args = {}; - for (const key in rule.args) { - const arg = rule.args[key]; - if (key === "options" && !Object.keys(arg).length) { - continue; - } - item.args[key] = internals.describe(arg, { assign: key }); - } - if (!Object.keys(item.args).length) { - delete item.args; + socket.activeSinceLastPing = true; + const defaultHandler = defaultMessageHandlers2[msg.type]; + const customHandler = server.customMessageHandlers[msg.type]; + if (defaultHandler || customHandler) { + try { + ; + defaultHandler?.call(socket, msg); + customHandler?.call(socket, msg); + } catch (error2) { + log.error(error2, "onMessage"); + server.rejectMessageAndTerminateSocket(msg, socket); } + } else { + log.error(`Unhandled message type: ${msg.type}`); + server.rejectMessageAndTerminateSocket(msg, socket); } - desc.rules.push(item); - } - if (!desc.rules.length) { - delete desc.rules; } - for (const term in schema.$_terms) { - if (term[0] === "_") { - continue; - } - assert2(!desc[term], "Cannot describe schema due to internal name conflict with", term); - const items = schema.$_terms[term]; - if (!items) { - continue; + }; + defaultMessageHandlers2 = { + [PONG]() { + const socket = this; + socket.activeSinceLastPing = true; + }, + [PUB](msg) { + const { server } = this; + const subscribers = server.subscribersByChannelID[msg.channelID]; + server.broadcast(msg, { to: subscribers ?? [] }); + }, + [SUB]({ channelID, kvFilter }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); + return; } - if (items instanceof Map) { - if (items.size) { - desc[term] = [...items.entries()]; + if (!socket.subscriptions.has(channelID)) { + socket.subscriptions.add(channelID); + if (Array.isArray(kvFilter)) { + socket.kvFilter.set(channelID, new Set(kvFilter)); } - continue; - } - if (Common.isValues(items)) { - desc[term] = items.describe(); - continue; - } - assert2(def.terms[term], "Term", term, "missing configuration"); - const manifest2 = def.terms[term].manifest; - const mapped = typeof manifest2 === "object"; - if (!items.length && !mapped) { - continue; - } - const normalized = []; - for (const item of items) { - normalized.push(internals.describe(item)); - } - if (mapped) { - const { from: from3, to } = manifest2.mapped; - desc[term] = {}; - for (const item of normalized) { - desc[term][item[to]] = item[from3]; + if (!server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); } - continue; + server.subscribersByChannelID[channelID].add(socket); + } else { + log.debug("Already subscribed to", channelID); } - if (manifest2 === "single") { - assert2(normalized.length === 1, "Term", term, "contains more than one item"); - desc[term] = normalized[0]; - continue; + socket.send(createOkResponse({ type: SUB, channelID, kvFilter })); + }, + [KV_FILTER]({ channelID, kvFilter }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); + return; } - desc[term] = normalized; - } - internals.validate(schema.$_root, desc); - return desc; - }; - internals.describe = function(item, options2 = {}) { - if (Array.isArray(item)) { - return item.map(internals.describe); - } - if (item === Common.symbols.deepDefault) { - return { special: "deep" }; - } - if (typeof item !== "object" || item === null) { - return item; - } - if (options2.assign === "options") { - return clone2(item); - } - if (Buffer && Buffer.isBuffer(item)) { - return { buffer: item.toString("binary") }; - } - if (item instanceof Date) { - return item.toISOString(); - } - if (item instanceof Error) { - return item; - } - if (item instanceof RegExp) { - if (options2.assign === "regex") { - return item.toString(); + if (socket.subscriptions.has(channelID)) { + if (Array.isArray(kvFilter)) { + socket.kvFilter.set(channelID, new Set(kvFilter)); + } else { + socket.kvFilter.delete(channelID); + } + } else { + log.debug("[KV_FILTER] Not subscribed to", channelID); } - return { regex: item.toString() }; - } - if (item[Common.symbols.literal]) { - return { function: item.literal }; - } - if (typeof item.describe === "function") { - if (options2.assign === "ref") { - return item.describe().ref; + socket.send(createOkResponse({ type: KV_FILTER, channelID, kvFilter })); + }, + [UNSUB]({ channelID }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: UNSUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); } - return item.describe(); - } - const normalized = {}; - for (const key in item) { - const value = item[key]; - if (value === void 0) { - continue; + if (socket.subscriptions.has(channelID)) { + socket.subscriptions.delete(channelID); + socket.kvFilter.delete(channelID); + if (server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID].delete(socket); + } } - normalized[key] = internals.describe(value, { assign: key }); + socket.send(createOkResponse({ type: UNSUB, channelID })); } - return normalized; - }; - exports2.build = function(joi, desc) { - const builder = new internals.Builder(joi); - return builder.parse(desc); }; - internals.Builder = class { - constructor(joi) { - this.joi = joi; - } - parse(desc) { - internals.validate(this.joi, desc); - let schema = this.joi[desc.type]()._bare(); - const def = schema._definition; - if (desc.flags) { - for (const flag in desc.flags) { - const setter = def.flags[flag] && def.flags[flag].setter || flag; - assert2(typeof schema[setter] === "function", "Invalid flag", flag, "for type", desc.type); - schema = schema[setter](this.build(desc.flags[flag])); + publicMethods2 = { + /** + * Broadcasts a message, ignoring clients which are not open. + * + * @param message + * @param to - The intended recipients of the message. Defaults to every open client socket. + * @param except - A recipient to exclude. Optional. + */ + broadcast(message, { to, except, wsOnly } = {}) { + const server = this; + const msg = typeof message === "string" ? message : JSON.stringify(message); + let shortMsg; + const shortenPayload = () => { + if (!shortMsg && (typeof message === "object" && message.type === NOTIFICATION_TYPE.ENTRY && message.data)) { + delete message.data; + shortMsg = JSON.stringify(message); } - } - if (desc.preferences) { - schema = schema.preferences(this.build(desc.preferences)); - } - if (desc.allow) { - schema = schema.allow(...this.build(desc.allow)); - } - if (desc.invalid) { - schema = schema.invalid(...this.build(desc.invalid)); - } - if (desc.rules) { - for (const rule of desc.rules) { - assert2(typeof schema[rule.name] === "function", "Invalid rule", rule.name, "for type", desc.type); - const args = []; - if (rule.args) { - const built = {}; - for (const key in rule.args) { - built[key] = this.build(rule.args[key], { assign: key }); - } - const keys = Object.keys(built); - const definition = def.rules[rule.name].args; - if (definition) { - assert2(keys.length <= definition.length, "Invalid number of arguments for", desc.type, rule.name, "(expected up to", definition.length, ", found", keys.length, ")"); - for (const { name } of definition) { - args.push(built[name]); - } - } else { - assert2(keys.length === 1, "Invalid number of arguments for", desc.type, rule.name, "(expected up to 1, found", keys.length, ")"); - args.push(built[keys[0]]); + return shortMsg; + }; + for (const client of to || server.clients) { + if (!wsOnly && isPushSubscriptionInfo(client)) { + if (msg.length > 4096 - 86 - 17) { + if (!shortenPayload()) { + console.info("Skipping too large of a payload for", client.id); + continue; } } - schema = schema[rule.name](...args); - const options2 = {}; - for (const custom in def.modifiers) { - if (rule[custom] !== void 0) { - options2[custom] = this.build(rule[custom]); + postEvent(client, shortMsg || msg).catch((e2) => { + if (e2?.message === "Payload too large") { + if (shortMsg || !shortenPayload()) { + console.info("Skipping too large of a payload for", client.id); + return; + } + postEvent(client, shortMsg).catch((e3) => { + console.error(e3, "Error posting push notification"); + }); + return; } - } - if (Object.keys(options2).length) { - schema = schema.rule(options2); - } - } - } - const terms = {}; - for (const key in desc) { - if (["allow", "flags", "invalid", "whens", "preferences", "rules", "type"].includes(key)) { - continue; - } - assert2(def.terms[key], "Term", key, "missing configuration"); - const manifest2 = def.terms[key].manifest; - if (manifest2 === "schema") { - terms[key] = desc[key].map((item) => this.parse(item)); - continue; - } - if (manifest2 === "values") { - terms[key] = desc[key].map((item) => this.build(item)); - continue; - } - if (manifest2 === "single") { - terms[key] = this.build(desc[key]); + console.error(e2, "Error posting push notification"); + }); continue; } - if (typeof manifest2 === "object") { - terms[key] = {}; - for (const name in desc[key]) { - const value = desc[key][name]; - terms[key][name] = this.parse(value); - } - continue; + if (client.readyState === wrapper_default.OPEN && client !== except) { + client.send(msg); } - terms[key] = this.build(desc[key]); - } - if (desc.whens) { - terms.whens = desc.whens.map((when) => this.build(when)); - } - schema = def.manifest.build(schema, terms); - schema.$_temp.ruleset = false; - return schema; - } - build(desc, options2 = {}) { - if (desc === null) { - return null; - } - if (Array.isArray(desc)) { - return desc.map((item) => this.build(item)); - } - if (desc instanceof Error) { - return desc; - } - if (options2.assign === "options") { - return clone2(desc); } - if (options2.assign === "regex") { - return internals.regex(desc); - } - if (options2.assign === "ref") { - return Ref.build(desc); - } - if (typeof desc !== "object") { - return desc; - } - if (Object.keys(desc).length === 1) { - if (desc.buffer) { - assert2(Buffer, "Buffers are not supported"); - return Buffer && Buffer.from(desc.buffer, "binary"); - } - if (desc.function) { - return { [Common.symbols.literal]: true, literal: desc.function }; - } - if (desc.override) { - return Common.symbols.override; - } - if (desc.ref) { - return Ref.build(desc.ref); - } - if (desc.regex) { - return internals.regex(desc.regex); - } - if (desc.special) { - assert2(["deep"].includes(desc.special), "Unknown special value", desc.special); - return Common.symbols.deepDefault; - } - if (desc.value) { - return clone2(desc.value); + }, + // Enumerates the subscribers of a given channel. + *enumerateSubscribers(channelID, kvKey) { + const server = this; + if (channelID in server.subscribersByChannelID) { + const subscribers = server.subscribersByChannelID[channelID]; + if (!kvKey) { + yield* subscribers; + } else { + for (const subscriber of subscribers) { + const kvFilter = subscriber.kvFilter?.get(channelID); + if (!kvFilter || kvFilter.has(kvKey)) yield subscriber; + } } } - if (desc.type) { - return this.parse(desc); - } - if (desc.template) { - return Template.build(desc); - } - const normalized = {}; - for (const key in desc) { - normalized[key] = this.build(desc[key], { assign: key }); - } - return normalized; + }, + rejectMessageAndTerminateSocket(request, socket) { + socket.send(createErrorResponse({ ...request }), () => socket.terminate()); } }; - internals.regex = function(string3) { - const end = string3.lastIndexOf("/"); - const exp = string3.slice(1, end); - const flags = string3.slice(end + 1); - return new RegExp(exp, flags); - }; - internals.validate = function(joi, desc) { - Schemas = Schemas || require_schemas2(); - joi.assert(desc, Schemas.description); - }; } }); -var require_lib38 = __commonJS({ - "node_modules/.deno/@hapi+pinpoint@2.0.1/node_modules/@hapi/pinpoint/lib/index.js"(exports2) { +var require_parser2 = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js"(exports2) { "use strict"; - exports2.location = function(depth = 0) { - const orig = Error.prepareStackTrace; - Error.prepareStackTrace = (ignore, stack) => stack; - const capture = {}; - Error.captureStackTrace(capture, this); - const line = capture.stack[depth + 1]; - Error.prepareStackTrace = orig; - return { - filename: line.getFileName(), - line: line.getLineNumber() - }; + exports2.load = function(received, defaults, onto = {}) { + var k, ref, v2; + for (k in defaults) { + v2 = defaults[k]; + onto[k] = (ref = received[k]) != null ? ref : v2; + } + return onto; + }; + exports2.overwrite = function(received, defaults, onto = {}) { + var k, v2; + for (k in received) { + v2 = received[k]; + if (defaults[k] !== void 0) { + onto[k] = v2; + } + } + return onto; }; } }); -var require_trace = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/trace.js"(exports2) { +var require_DLList = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/DLList.js"(exports2, module14) { "use strict"; - var { deepEqual } = require_lib(); - var Pinpoint = require_lib38(); - var Errors = require_errors3(); - var internals = { - codes: { - error: 1, - pass: 2, - full: 3 - }, - labels: { - 0: "never used", - 1: "always error", - 2: "always pass" - } - }; - exports2.setup = function(root) { - const trace = function() { - root._tracer = root._tracer || new internals.Tracer(); - return root._tracer; - }; - root.trace = trace; - root[Symbol.for("@hapi/lab/coverage/initialize")] = trace; - root.untrace = () => { - root._tracer = null; - }; - }; - exports2.location = function(schema) { - return schema.$_setFlag("_tracerLocation", Pinpoint.location(2)); - }; - internals.Tracer = class { - constructor() { - this.name = "Joi"; - this._schemas = /* @__PURE__ */ new Map(); + var DLList; + DLList = class DLList { + constructor(incr, decr) { + this.incr = incr; + this.decr = decr; + this._first = null; + this._last = null; + this.length = 0; } - _register(schema) { - const existing = this._schemas.get(schema); - if (existing) { - return existing.store; + push(value) { + var node; + this.length++; + if (typeof this.incr === "function") { + this.incr(); } - const store = new internals.Store(schema); - const { filename, line } = schema._flags._tracerLocation || Pinpoint.location(5); - this._schemas.set(schema, { filename, line, store }); - return store; - } - _combine(merged, sources) { - for (const { store } of this._schemas.values()) { - store._combine(merged, sources); + node = { + value, + prev: this._last, + next: null + }; + if (this._last != null) { + this._last.next = node; + this._last = node; + } else { + this._first = this._last = node; } + return void 0; } - report(file) { - const coverage = []; - for (const { filename, line, store } of this._schemas.values()) { - if (file && file !== filename) { - continue; - } - const missing = []; - const skipped = []; - for (const [schema, log2] of store._sources.entries()) { - if (internals.sub(log2.paths, skipped)) { - continue; - } - if (!log2.entry) { - missing.push({ - status: "never reached", - paths: [...log2.paths] - }); - skipped.push(...log2.paths); - continue; - } - for (const type of ["valid", "invalid"]) { - const set = schema[`_${type}s`]; - if (!set) { - continue; - } - const values = new Set(set._values); - const refs = new Set(set._refs); - for (const { value, ref } of log2[type]) { - values.delete(value); - refs.delete(ref); - } - if (values.size || refs.size) { - missing.push({ - status: [...values, ...[...refs].map((ref) => ref.display)], - rule: `${type}s` - }); - } - } - const rules = schema._rules.map((rule) => rule.name); - for (const type of ["default", "failover"]) { - if (schema._flags[type] !== void 0) { - rules.push(type); - } - } - for (const name of rules) { - const status = internals.labels[log2.rule[name] || 0]; - if (status) { - const report = { rule: name, status }; - if (log2.paths.size) { - report.paths = [...log2.paths]; - } - missing.push(report); - } - } - } - if (missing.length) { - coverage.push({ - filename, - line, - missing, - severity: "error", - message: `Schema missing tests for ${missing.map(internals.message).join(", ")}` - }); + shift() { + var value; + if (this._first == null) { + return; + } else { + this.length--; + if (typeof this.decr === "function") { + this.decr(); } } - return coverage.length ? coverage : null; - } - }; - internals.Store = class { - constructor(schema) { - this.active = true; - this._sources = /* @__PURE__ */ new Map(); - this._combos = /* @__PURE__ */ new Map(); - this._scan(schema); - } - debug(state, source, name, result) { - state.mainstay.debug && state.mainstay.debug.push({ type: source, name, result, path: state.path }); - } - entry(schema, state) { - internals.debug(state, { type: "entry" }); - this._record(schema, (log2) => { - log2.entry = true; - }); - } - filter(schema, state, source, value) { - internals.debug(state, { type: source, ...value }); - this._record(schema, (log2) => { - log2[source].add(value); - }); - } - log(schema, state, source, name, result) { - internals.debug(state, { type: source, name, result: result === "full" ? "pass" : result }); - this._record(schema, (log2) => { - log2[source][name] = log2[source][name] || 0; - log2[source][name] |= internals.codes[result]; - }); - } - resolve(state, ref, to) { - if (!state.mainstay.debug) { - return; + value = this._first.value; + if ((this._first = this._first.next) != null) { + this._first.prev = null; + } else { + this._last = null; } - const log2 = { type: "resolve", ref: ref.display, to, path: state.path }; - state.mainstay.debug.push(log2); + return value; } - value(state, by, from3, to, name) { - if (!state.mainstay.debug || deepEqual(from3, to)) { - return; - } - const log2 = { type: "value", by, from: from3, to, path: state.path }; - if (name) { - log2.name = name; + first() { + if (this._first != null) { + return this._first.value; } - state.mainstay.debug.push(log2); } - _record(schema, each) { - const log2 = this._sources.get(schema); - if (log2) { - each(log2); - return; - } - const sources = this._combos.get(schema); - for (const source of sources) { - this._record(source, each); - } - } - _scan(schema, _path) { - const path8 = _path || []; - let log2 = this._sources.get(schema); - if (!log2) { - log2 = { - paths: /* @__PURE__ */ new Set(), - entry: false, - rule: {}, - valid: /* @__PURE__ */ new Set(), - invalid: /* @__PURE__ */ new Set() - }; - this._sources.set(schema, log2); - } - if (path8.length) { - log2.paths.add(path8); + getArray() { + var node, ref, results; + node = this._first; + results = []; + while (node != null) { + results.push((ref = node, node = node.next, ref.value)); } - const each = (sub, source) => { - const subId = internals.id(sub, source); - this._scan(sub, path8.concat(subId)); - }; - schema.$_modify({ each, ref: false }); - } - _combine(merged, sources) { - this._combos.set(merged, sources); - } - }; - internals.message = function(item) { - const path8 = item.paths ? Errors.path(item.paths[0]) + (item.rule ? ":" : "") : ""; - return `${path8}${item.rule || ""} (${item.status})`; - }; - internals.id = function(schema, { source, name, path: path8, key }) { - if (schema._flags.id) { - return schema._flags.id; - } - if (key) { - return key; + return results; } - name = `@${name}`; - if (source === "terms") { - return [name, path8[Math.min(path8.length - 1, 1)]]; + forEachShift(cb) { + var node; + node = this.shift(); + while (node != null) { + cb(node), node = this.shift(); + } + return void 0; } - return name; - }; - internals.sub = function(paths, skipped) { - for (const path8 of paths) { - for (const skip of skipped) { - if (deepEqual(path8.slice(0, skip.length), skip)) { - return true; - } + debug() { + var node, ref, ref1, ref2, results; + node = this._first; + results = []; + while (node != null) { + results.push((ref = node, node = node.next, { + value: ref.value, + prev: (ref1 = ref.prev) != null ? ref1.value : void 0, + next: (ref2 = ref.next) != null ? ref2.value : void 0 + })); } - } - return false; - }; - internals.debug = function(state, event) { - if (state.mainstay.debug) { - event.path = state.debug ? [...state.path, state.debug] : state.path; - state.mainstay.debug.push(event); + return results; } }; + module14.exports = DLList; } }); -var require_modify2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/modify.js"(exports2) { +var require_Events = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Events.js"(exports2, module14) { "use strict"; - var { assert: assert2 } = require_lib(); - var Common = require_common3(); - var Ref = require_ref2(); - var internals = {}; - exports2.Ids = internals.Ids = class { - constructor() { - this._byId = /* @__PURE__ */ new Map(); - this._byKey = /* @__PURE__ */ new Map(); - this._schemaChain = false; - } - clone() { - const clone2 = new internals.Ids(); - clone2._byId = new Map(this._byId); - clone2._byKey = new Map(this._byKey); - clone2._schemaChain = this._schemaChain; - return clone2; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - concat(source) { - if (source._schemaChain) { - this._schemaChain = true; - } - for (const [id, value] of source._byId.entries()) { - assert2(!this._byKey.has(id), "Schema id conflicts with existing key:", id); - this._byId.set(id, value); - } - for (const [key, value] of source._byKey.entries()) { - assert2(!this._byId.has(key), "Schema key conflicts with existing id:", key); - this._byKey.set(key, value); - } + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - fork(path8, adjuster, root) { - const chain = this._collect(path8); - chain.push({ schema: root }); - const tail = chain.shift(); - let adjusted = { id: tail.id, schema: adjuster(tail.schema) }; - assert2(Common.isSchema(adjusted.schema), "adjuster function failed to return a joi schema type"); - for (const node of chain) { - adjusted = { id: node.id, schema: internals.fork(node.schema, adjusted.id, adjusted.schema) }; + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; + } + var Events2; + Events2 = class Events { + constructor(instance) { + this.instance = instance; + this._events = {}; + if (this.instance.on != null || this.instance.once != null || this.instance.removeAllListeners != null) { + throw new Error("An Emitter already exists for this object"); } - return adjusted.schema; + this.instance.on = (name, cb) => { + return this._addListener(name, "many", cb); + }; + this.instance.once = (name, cb) => { + return this._addListener(name, "once", cb); + }; + this.instance.removeAllListeners = (name = null) => { + if (name != null) { + return delete this._events[name]; + } else { + return this._events = {}; + } + }; } - labels(path8, behind = []) { - const current = path8[0]; - const node = this._get(current); - if (!node) { - return [...behind, ...path8].join("."); - } - const forward = path8.slice(1); - behind = [...behind, node.schema._flags.label || current]; - if (!forward.length) { - return behind.join("."); + _addListener(name, status, cb) { + var base2; + if ((base2 = this._events)[name] == null) { + base2[name] = []; } - return node.schema._ids.labels(forward, behind); + this._events[name].push({ + cb, + status + }); + return this.instance; } - reach(path8, behind = []) { - const current = path8[0]; - const node = this._get(current); - assert2(node, "Schema does not contain path", [...behind, ...path8].join(".")); - const forward = path8.slice(1); - if (!forward.length) { - return node.schema; + listenerCount(name) { + if (this._events[name] != null) { + return this._events[name].length; + } else { + return 0; } - return node.schema._ids.reach(forward, [...behind, current]); } - register(schema, { key } = {}) { - if (!schema || !Common.isSchema(schema)) { - return; - } - if (schema.$_property("schemaChain") || schema._ids._schemaChain) { - this._schemaChain = true; - } - const id = schema._flags.id; - if (id) { - const existing = this._byId.get(id); - assert2(!existing || existing.schema === schema, "Cannot add different schemas with the same id:", id); - assert2(!this._byKey.has(id), "Schema id conflicts with existing key:", id); - this._byId.set(id, { schema, id }); - } - if (key) { - assert2(!this._byKey.has(key), "Schema already contains key:", key); - assert2(!this._byId.has(key), "Schema key conflicts with existing id:", key); - this._byKey.set(key, { schema, id: key }); - } + trigger(name, ...args) { + var _this = this; + return _asyncToGenerator2(function* () { + var e2, promises; + try { + if (name !== "debug") { + _this.trigger("debug", `Event triggered: ${name}`, args); + } + if (_this._events[name] == null) { + return; + } + _this._events[name] = _this._events[name].filter(function(listener) { + return listener.status !== "none"; + }); + promises = _this._events[name].map( + /* @__PURE__ */ function() { + var _ref = _asyncToGenerator2(function* (listener) { + var e3, returned; + if (listener.status === "none") { + return; + } + if (listener.status === "once") { + listener.status = "none"; + } + try { + returned = typeof listener.cb === "function" ? listener.cb(...args) : void 0; + if (typeof (returned != null ? returned.then : void 0) === "function") { + return yield returned; + } else { + return returned; + } + } catch (error2) { + e3 = error2; + if (true) { + _this.trigger("error", e3); + } + return null; + } + }); + return function(_x) { + return _ref.apply(this, arguments); + }; + }() + ); + return (yield Promise.all(promises)).find(function(x3) { + return x3 != null; + }); + } catch (error2) { + e2 = error2; + if (true) { + _this.trigger("error", e2); + } + return null; + } + })(); } - reset() { - this._byId = /* @__PURE__ */ new Map(); - this._byKey = /* @__PURE__ */ new Map(); - this._schemaChain = false; + }; + module14.exports = Events2; + } +}); +var require_Queues = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Queues.js"(exports2, module14) { + "use strict"; + var DLList; + var Events2; + var Queues; + DLList = require_DLList(); + Events2 = require_Events(); + Queues = class Queues { + constructor(num_priorities) { + var i2; + this.Events = new Events2(this); + this._length = 0; + this._lists = function() { + var j, ref, results; + results = []; + for (i2 = j = 1, ref = num_priorities; 1 <= ref ? j <= ref : j >= ref; i2 = 1 <= ref ? ++j : --j) { + results.push(new DLList(() => { + return this.incr(); + }, () => { + return this.decr(); + })); + } + return results; + }.call(this); } - _collect(path8, behind = [], nodes = []) { - const current = path8[0]; - const node = this._get(current); - assert2(node, "Schema does not contain path", [...behind, ...path8].join(".")); - nodes = [node, ...nodes]; - const forward = path8.slice(1); - if (!forward.length) { - return nodes; + incr() { + if (this._length++ === 0) { + return this.Events.trigger("leftzero"); } - return node.schema._ids._collect(forward, [...behind, current], nodes); - } - _get(id) { - return this._byId.get(id) || this._byKey.get(id); } - }; - internals.fork = function(schema, id, replacement) { - const each = (item, { key }) => { - if (id === (item._flags.id || key)) { - return replacement; - } - }; - const obj = exports2.schema(schema, { each, ref: false }); - return obj ? obj.$_mutateRebuild() : schema; - }; - exports2.schema = function(schema, options2) { - let obj; - for (const name in schema._flags) { - if (name[0] === "_") { - continue; - } - const result = internals.scan(schema._flags[name], { source: "flags", name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - obj._flags[name] = result; + decr() { + if (--this._length === 0) { + return this.Events.trigger("zero"); } } - for (let i2 = 0; i2 < schema._rules.length; ++i2) { - const rule = schema._rules[i2]; - const result = internals.scan(rule.args, { source: "rules", name: rule.name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - const clone2 = Object.assign({}, rule); - clone2.args = result; - obj._rules[i2] = clone2; - const existingUnique = obj._singleRules.get(rule.name); - if (existingUnique === rule) { - obj._singleRules.set(rule.name, clone2); - } - } + push(job) { + return this._lists[job.options.priority].push(job); } - for (const name in schema.$_terms) { - if (name[0] === "_") { - continue; - } - const result = internals.scan(schema.$_terms[name], { source: "terms", name }, options2); - if (result !== void 0) { - obj = obj || schema.clone(); - obj.$_terms[name] = result; + queued(priority) { + if (priority != null) { + return this._lists[priority].length; + } else { + return this._length; } } - return obj; - }; - internals.scan = function(item, source, options2, _path, _key) { - const path8 = _path || []; - if (item === null || typeof item !== "object") { - return; + shiftAll(fn) { + return this._lists.forEach(function(list) { + return list.forEachShift(fn); + }); } - let clone2; - if (Array.isArray(item)) { - for (let i2 = 0; i2 < item.length; ++i2) { - const key = source.source === "terms" && source.name === "keys" && item[i2].key; - const result = internals.scan(item[i2], source, options2, [i2, ...path8], key); - if (result !== void 0) { - clone2 = clone2 || item.slice(); - clone2[i2] = result; + getFirst(arr = this._lists) { + var j, len, list; + for (j = 0, len = arr.length; j < len; j++) { + list = arr[j]; + if (list.length > 0) { + return list; } } - return clone2; - } - if (options2.schema !== false && Common.isSchema(item) || options2.ref !== false && Ref.isRef(item)) { - const result = options2.each(item, { ...source, path: path8, key: _key }); - if (result === item) { - return; - } - return result; + return []; } - for (const key in item) { - if (key[0] === "_") { - continue; - } - const result = internals.scan(item[key], source, options2, [key, ...path8], _key); - if (result !== void 0) { - clone2 = clone2 || Object.assign({}, item); - clone2[key] = result; - } + shiftLastFrom(priority) { + return this.getFirst(this._lists.slice(priority).reverse()).shift(); } - return clone2; }; + module14.exports = Queues; } }); -var require_state3 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/state.js"(exports2, module14) { +var require_BottleneckError = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/BottleneckError.js"(exports2, module14) { "use strict"; - var { clone: clone2, reach } = require_lib(); - var Common = require_common3(); - var internals = { - value: Symbol("value") + var BottleneckError; + BottleneckError = class BottleneckError extends Error { }; - module14.exports = internals.State = class { - constructor(path8, ancestors, state) { - this.path = path8; - this.ancestors = ancestors; - this.mainstay = state.mainstay; - this.schemas = state.schemas; - this.debug = null; - } - localize(path8, ancestors = null, schema = null) { - const state = new internals.State(path8, ancestors, this); - if (schema && state.schemas) { - state.schemas = [internals.schemas(schema), ...state.schemas]; - } - return state; + module14.exports = BottleneckError; + } +}); +var require_Job = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Job.js"(exports2, module14) { + "use strict"; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - nest(schema, debug) { - const state = new internals.State(this.path, this.ancestors, this); - state.schemas = state.schemas && [internals.schemas(schema), ...state.schemas]; - state.debug = debug; - return state; + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - shadow(value, reason) { - this.mainstay.shadow = this.mainstay.shadow || new internals.Shadow(); - this.mainstay.shadow.set(this.path, value, reason); + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; + } + var BottleneckError; + var DEFAULT_PRIORITY; + var Job; + var NUM_PRIORITIES; + var parser3; + NUM_PRIORITIES = 10; + DEFAULT_PRIORITY = 5; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + Job = class Job { + constructor(task, args, options2, jobDefaults, rejectOnDrop, Events2, _states, Promise2) { + this.task = task; + this.args = args; + this.rejectOnDrop = rejectOnDrop; + this.Events = Events2; + this._states = _states; + this.Promise = Promise2; + this.options = parser3.load(options2, jobDefaults); + this.options.priority = this._sanitizePriority(this.options.priority); + if (this.options.id === jobDefaults.id) { + this.options.id = `${this.options.id}-${this._randomIndex()}`; + } + this.promise = new this.Promise((_resolve, _reject) => { + this._resolve = _resolve; + this._reject = _reject; + }); + this.retryCount = 0; } - snapshot() { - if (this.mainstay.shadow) { - this._snapshot = clone2(this.mainstay.shadow.node(this.path)); + _sanitizePriority(priority) { + var sProperty; + sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; + if (sProperty < 0) { + return 0; + } else if (sProperty > NUM_PRIORITIES - 1) { + return NUM_PRIORITIES - 1; + } else { + return sProperty; } - this.mainstay.snapshot(); } - restore() { - if (this.mainstay.shadow) { - this.mainstay.shadow.override(this.path, this._snapshot); - this._snapshot = void 0; + _randomIndex() { + return Math.random().toString(36).slice(2); + } + doDrop({ + error: error2, + message = "This job has been dropped by Bottleneck" + } = {}) { + if (this._states.remove(this.options.id)) { + if (this.rejectOnDrop) { + this._reject(error2 != null ? error2 : new BottleneckError(message)); + } + this.Events.trigger("dropped", { + args: this.args, + options: this.options, + task: this.task, + promise: this.promise + }); + return true; + } else { + return false; } - this.mainstay.restore(); } - commit() { - if (this.mainstay.shadow) { - this.mainstay.shadow.override(this.path, this._snapshot); - this._snapshot = void 0; + _assertStatus(expected) { + var status; + status = this._states.jobStatus(this.options.id); + if (!(status === expected || expected === "DONE" && status === null)) { + throw new BottleneckError(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`); } - this.mainstay.commit(); } - }; - internals.schemas = function(schema) { - if (Common.isSchema(schema)) { - return { schema }; + doReceive() { + this._states.start(this.options.id); + return this.Events.trigger("received", { + args: this.args, + options: this.options + }); } - return schema; - }; - internals.Shadow = class { - constructor() { - this._values = null; + doQueue(reachedHWM, blocked) { + this._assertStatus("RECEIVED"); + this._states.next(this.options.id); + return this.Events.trigger("queued", { + args: this.args, + options: this.options, + reachedHWM, + blocked + }); } - set(path8, value, reason) { - if (!path8.length) { - return; - } - if (reason === "strip" && typeof path8[path8.length - 1] === "number") { - return; + doRun() { + if (this.retryCount === 0) { + this._assertStatus("QUEUED"); + this._states.next(this.options.id); + } else { + this._assertStatus("EXECUTING"); } - this._values = this._values || /* @__PURE__ */ new Map(); - let node = this._values; - for (let i2 = 0; i2 < path8.length; ++i2) { - const segment = path8[i2]; - let next = node.get(segment); - if (!next) { - next = /* @__PURE__ */ new Map(); - node.set(segment, next); + return this.Events.trigger("scheduled", { + args: this.args, + options: this.options + }); + } + doExecute(chained, clearGlobalState, run2, free) { + var _this = this; + return _asyncToGenerator2(function* () { + var error2, eventInfo, passed; + if (_this.retryCount === 0) { + _this._assertStatus("RUNNING"); + _this._states.next(_this.options.id); + } else { + _this._assertStatus("EXECUTING"); } - node = next; - } - node[internals.value] = value; + eventInfo = { + args: _this.args, + options: _this.options, + retryCount: _this.retryCount + }; + _this.Events.trigger("executing", eventInfo); + try { + passed = yield chained != null ? chained.schedule(_this.options, _this.task, ..._this.args) : _this.task(..._this.args); + if (clearGlobalState()) { + _this.doDone(eventInfo); + yield free(_this.options, eventInfo); + _this._assertStatus("DONE"); + return _this._resolve(passed); + } + } catch (error1) { + error2 = error1; + return _this._onFailure(error2, eventInfo, clearGlobalState, run2, free); + } + })(); } - get(path8) { - const node = this.node(path8); - if (node) { - return node[internals.value]; + doExpire(clearGlobalState, run2, free) { + var error2, eventInfo; + if (this._states.jobStatus(this.options.id === "RUNNING")) { + this._states.next(this.options.id); } + this._assertStatus("EXECUTING"); + eventInfo = { + args: this.args, + options: this.options, + retryCount: this.retryCount + }; + error2 = new BottleneckError(`This job timed out after ${this.options.expiration} ms.`); + return this._onFailure(error2, eventInfo, clearGlobalState, run2, free); } - node(path8) { - if (!this._values) { - return; - } - return reach(this._values, path8, { iterables: true }); + _onFailure(error2, eventInfo, clearGlobalState, run2, free) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var retry, retryAfter; + if (clearGlobalState()) { + retry = yield _this2.Events.trigger("failed", error2, eventInfo); + if (retry != null) { + retryAfter = ~~retry; + _this2.Events.trigger("retry", `Retrying ${_this2.options.id} after ${retryAfter} ms`, eventInfo); + _this2.retryCount++; + return run2(retryAfter); + } else { + _this2.doDone(eventInfo); + yield free(_this2.options, eventInfo); + _this2._assertStatus("DONE"); + return _this2._reject(error2); + } + } + })(); } - override(path8, node) { - if (!this._values) { - return; - } - const parents = path8.slice(0, -1); - const own = path8[path8.length - 1]; - const parent = reach(this._values, parents, { iterables: true }); - if (node) { - parent.set(own, node); - return; - } - if (parent) { - parent.delete(own); - } + doDone(eventInfo) { + this._assertStatus("EXECUTING"); + this._states.next(this.options.id); + return this.Events.trigger("done", eventInfo); } }; + module14.exports = Job; } }); -var require_validator3 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/validator.js"(exports2) { +var require_LocalDatastore = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/LocalDatastore.js"(exports2, module14) { "use strict"; - var { assert: assert2, clone: clone2, ignore, reach } = require_lib(); - var Common = require_common3(); - var Errors = require_errors3(); - var State = require_state3(); - var internals = { - result: Symbol("result") - }; - exports2.entry = function(value, schema, prefs) { - let settings = Common.defaults; - if (prefs) { - assert2(prefs.warnings === void 0, "Cannot override warnings preference in synchronous validation"); - assert2(prefs.artifacts === void 0, "Cannot override artifacts preference in synchronous validation"); - settings = Common.preferences(Common.defaults, prefs); - } - const result = internals.entry(value, schema, settings); - assert2(!result.mainstay.externals.length, "Schema with external rules must use validateAsync()"); - const outcome = { value: result.value }; - if (result.error) { - outcome.error = result.error; - } - if (result.mainstay.warnings.length) { - outcome.warning = Errors.details(result.mainstay.warnings); - } - if (result.mainstay.debug) { - outcome.debug = result.mainstay.debug; - } - if (result.mainstay.artifacts) { - outcome.artifacts = result.mainstay.artifacts; - } - return outcome; - }; - exports2.entryAsync = async function(value, schema, prefs) { - let settings = Common.defaults; - if (prefs) { - settings = Common.preferences(Common.defaults, prefs); + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - const result = internals.entry(value, schema, settings); - const mainstay = result.mainstay; - if (result.error) { - if (mainstay.debug) { - result.error.debug = mainstay.debug; - } - throw result.error; + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - if (mainstay.externals.length) { - let root = result.value; - const errors = []; - for (const external of mainstay.externals) { - const path8 = external.state.path; - const linked = external.schema.type === "link" ? mainstay.links.get(external.schema) : null; - let node = root; - let key; - let parent; - const ancestors = path8.length ? [root] : []; - const original = path8.length ? reach(value, path8) : value; - if (path8.length) { - key = path8[path8.length - 1]; - let current = root; - for (const segment of path8.slice(0, -1)) { - current = current[segment]; - ancestors.unshift(current); - } - parent = ancestors[0]; - node = parent[key]; + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - try { - const createError = (code2, local) => (linked || external.schema).$_createError(code2, node, local, external.state, settings); - const output = await external.method(node, { - schema: external.schema, - linked, - state: external.state, - prefs, - original, - error: createError, - errorsArray: internals.errorsArray, - warn: (code2, local) => mainstay.warnings.push((linked || external.schema).$_createError(code2, node, local, external.state, settings)), - message: (messages, local) => (linked || external.schema).$_createError("external", node, local, external.state, settings, { messages }) - }); - if (output === void 0 || output === node) { - continue; - } - if (output instanceof Errors.Report) { - mainstay.tracer.log(external.schema, external.state, "rule", "external", "error"); - errors.push(output); - if (settings.abortEarly) { - break; - } - continue; + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; + } + var BottleneckError; + var LocalDatastore; + var parser3; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + LocalDatastore = class LocalDatastore { + constructor(instance, storeOptions, storeInstanceOptions) { + this.instance = instance; + this.storeOptions = storeOptions; + this.clientId = this.instance._randomIndex(); + parser3.load(storeInstanceOptions, storeInstanceOptions, this); + this._nextRequest = this._lastReservoirRefresh = this._lastReservoirIncrease = Date.now(); + this._running = 0; + this._done = 0; + this._unblockTime = 0; + this.ready = this.Promise.resolve(); + this.clients = {}; + this._startHeartbeat(); + } + _startHeartbeat() { + var base2; + if (this.heartbeat == null && (this.storeOptions.reservoirRefreshInterval != null && this.storeOptions.reservoirRefreshAmount != null || this.storeOptions.reservoirIncreaseInterval != null && this.storeOptions.reservoirIncreaseAmount != null)) { + return typeof (base2 = this.heartbeat = setInterval(() => { + var amount, incr, maximum, now, reservoir; + now = Date.now(); + if (this.storeOptions.reservoirRefreshInterval != null && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { + this._lastReservoirRefresh = now; + this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; + this.instance._drainAll(this.computeCapacity()); } - if (Array.isArray(output) && output[Common.symbols.errors]) { - mainstay.tracer.log(external.schema, external.state, "rule", "external", "error"); - errors.push(...output); - if (settings.abortEarly) { - break; + if (this.storeOptions.reservoirIncreaseInterval != null && now >= this._lastReservoirIncrease + this.storeOptions.reservoirIncreaseInterval) { + var _this$storeOptions = this.storeOptions; + amount = _this$storeOptions.reservoirIncreaseAmount; + maximum = _this$storeOptions.reservoirIncreaseMaximum; + reservoir = _this$storeOptions.reservoir; + this._lastReservoirIncrease = now; + incr = maximum != null ? Math.min(amount, maximum - reservoir) : amount; + if (incr > 0) { + this.storeOptions.reservoir += incr; + return this.instance._drainAll(this.computeCapacity()); } - continue; - } - if (parent) { - mainstay.tracer.value(external.state, "rule", node, output, "external"); - parent[key] = output; - } else { - mainstay.tracer.value(external.state, "rule", root, output, "external"); - root = output; - } - } catch (err) { - if (settings.errors.label) { - err.message += ` (${external.label})`; } - throw err; - } - } - result.value = root; - if (errors.length) { - result.error = Errors.process(errors, value, settings); - if (mainstay.debug) { - result.error.debug = mainstay.debug; - } - throw result.error; + }, this.heartbeatInterval)).unref === "function" ? base2.unref() : void 0; + } else { + return clearInterval(this.heartbeat); } } - if (!settings.warnings && !settings.debug && !settings.artifacts) { - return result.value; - } - const outcome = { value: result.value }; - if (mainstay.warnings.length) { - outcome.warning = Errors.details(mainstay.warnings); - } - if (mainstay.debug) { - outcome.debug = mainstay.debug; - } - if (mainstay.artifacts) { - outcome.artifacts = mainstay.artifacts; - } - return outcome; - }; - exports2.standard = function(value, schema) { - if (schema.isAsync()) { - return exports2.entryAsync(value, schema); + __publish__(message) { + var _this = this; + return _asyncToGenerator2(function* () { + yield _this.yieldLoop(); + return _this.instance.Events.trigger("message", message.toString()); + })(); } - return exports2.entry(value, schema); - }; - internals.Mainstay = class { - constructor(tracer, debug, links) { - this.externals = []; - this.warnings = []; - this.tracer = tracer; - this.debug = debug; - this.links = links; - this.shadow = null; - this.artifacts = null; - this._snapshots = []; + __disconnect__(flush) { + var _this2 = this; + return _asyncToGenerator2(function* () { + yield _this2.yieldLoop(); + clearInterval(_this2.heartbeat); + return _this2.Promise.resolve(); + })(); } - snapshot() { - this._snapshots.push({ - externals: this.externals.slice(), - warnings: this.warnings.slice() + yieldLoop(t = 0) { + return new this.Promise(function(resolve82, reject) { + return setTimeout(resolve82, t); }); } - restore() { - const snapshot = this._snapshots.pop(); - this.externals = snapshot.externals; - this.warnings = snapshot.warnings; - } - commit() { - this._snapshots.pop(); + computePenalty() { + var ref; + return (ref = this.storeOptions.penalty) != null ? ref : 15 * this.storeOptions.minTime || 5e3; } - }; - internals.entry = function(value, schema, prefs) { - const { tracer, cleanup } = internals.tracer(schema, prefs); - const debug = prefs.debug ? [] : null; - const links = schema._ids._schemaChain ? /* @__PURE__ */ new Map() : null; - const mainstay = new internals.Mainstay(tracer, debug, links); - const schemas = schema._ids._schemaChain ? [{ schema }] : null; - const state = new State([], [], { mainstay, schemas }); - const result = exports2.validate(value, schema, state, prefs); - if (cleanup) { - schema.$_root.untrace(); + __updateSettings__(options2) { + var _this3 = this; + return _asyncToGenerator2(function* () { + yield _this3.yieldLoop(); + parser3.overwrite(options2, options2, _this3.storeOptions); + _this3._startHeartbeat(); + _this3.instance._drainAll(_this3.computeCapacity()); + return true; + })(); } - const error2 = Errors.process(result.errors, value, prefs); - return { value: result.value, error: error2, mainstay }; - }; - internals.tracer = function(schema, prefs) { - if (schema.$_root._tracer) { - return { tracer: schema.$_root._tracer._register(schema) }; + __running__() { + var _this4 = this; + return _asyncToGenerator2(function* () { + yield _this4.yieldLoop(); + return _this4._running; + })(); } - if (prefs.debug) { - assert2(schema.$_root.trace, "Debug mode not supported"); - return { tracer: schema.$_root.trace()._register(schema), cleanup: true }; + __queued__() { + var _this5 = this; + return _asyncToGenerator2(function* () { + yield _this5.yieldLoop(); + return _this5.instance.queued(); + })(); } - return { tracer: internals.ignore }; - }; - exports2.validate = function(value, schema, state, prefs, overrides = {}) { - if (schema.$_terms.whens) { - schema = schema._generate(value, state, prefs).schema; + __done__() { + var _this6 = this; + return _asyncToGenerator2(function* () { + yield _this6.yieldLoop(); + return _this6._done; + })(); } - if (schema._preferences) { - prefs = internals.prefs(schema, prefs); + __groupCheck__(time3) { + var _this7 = this; + return _asyncToGenerator2(function* () { + yield _this7.yieldLoop(); + return _this7._nextRequest + _this7.timeout < time3; + })(); } - if (schema._cache && prefs.cache) { - const result = schema._cache.get(value); - state.mainstay.tracer.debug(state, "validate", "cached", !!result); - if (result) { - return result; + computeCapacity() { + var maxConcurrent, reservoir; + var _this$storeOptions2 = this.storeOptions; + maxConcurrent = _this$storeOptions2.maxConcurrent; + reservoir = _this$storeOptions2.reservoir; + if (maxConcurrent != null && reservoir != null) { + return Math.min(maxConcurrent - this._running, reservoir); + } else if (maxConcurrent != null) { + return maxConcurrent - this._running; + } else if (reservoir != null) { + return reservoir; + } else { + return null; } } - const createError = (code2, local, localState) => schema.$_createError(code2, value, local, localState || state, prefs); - const helpers = { - original: value, - prefs, - schema, - state, - error: createError, - errorsArray: internals.errorsArray, - warn: (code2, local, localState) => state.mainstay.warnings.push(createError(code2, local, localState)), - message: (messages, local) => schema.$_createError("custom", value, local, state, prefs, { messages }) - }; - state.mainstay.tracer.entry(schema, state); - const def = schema._definition; - if (def.prepare && value !== void 0 && prefs.convert) { - const prepared = def.prepare(value, helpers); - if (prepared) { - state.mainstay.tracer.value(state, "prepare", value, prepared.value); - if (prepared.errors) { - return internals.finalize(prepared.value, [].concat(prepared.errors), helpers); - } - value = prepared.value; - } + conditionsCheck(weight) { + var capacity; + capacity = this.computeCapacity(); + return capacity == null || weight <= capacity; } - if (def.coerce && value !== void 0 && prefs.convert && (!def.coerce.from || def.coerce.from.includes(typeof value))) { - const coerced = def.coerce.method(value, helpers); - if (coerced) { - state.mainstay.tracer.value(state, "coerced", value, coerced.value); - if (coerced.errors) { - return internals.finalize(coerced.value, [].concat(coerced.errors), helpers); - } - value = coerced.value; - } + __incrementReservoir__(incr) { + var _this8 = this; + return _asyncToGenerator2(function* () { + var reservoir; + yield _this8.yieldLoop(); + reservoir = _this8.storeOptions.reservoir += incr; + _this8.instance._drainAll(_this8.computeCapacity()); + return reservoir; + })(); } - const empty2 = schema._flags.empty; - if (empty2 && empty2.$_match(internals.trim(value, schema), state.nest(empty2), Common.defaults)) { - state.mainstay.tracer.value(state, "empty", value, void 0); - value = void 0; + __currentReservoir__() { + var _this9 = this; + return _asyncToGenerator2(function* () { + yield _this9.yieldLoop(); + return _this9.storeOptions.reservoir; + })(); } - const presence = overrides.presence || schema._flags.presence || (schema._flags._endedSwitch ? null : prefs.presence); - if (value === void 0) { - if (presence === "forbidden") { - return internals.finalize(value, null, helpers); - } - if (presence === "required") { - return internals.finalize(value, [schema.$_createError("any.required", value, null, state, prefs)], helpers); - } - if (presence === "optional") { - if (schema._flags.default !== Common.symbols.deepDefault) { - return internals.finalize(value, null, helpers); - } - state.mainstay.tracer.value(state, "default", value, {}); - value = {}; - } - } else if (presence === "forbidden") { - return internals.finalize(value, [schema.$_createError("any.unknown", value, null, state, prefs)], helpers); + isBlocked(now) { + return this._unblockTime >= now; } - const errors = []; - if (schema._valids) { - const match = schema._valids.get(value, state, prefs, schema._flags.insensitive); - if (match) { - if (prefs.convert) { - state.mainstay.tracer.value(state, "valids", value, match.value); - value = match.value; - } - state.mainstay.tracer.filter(schema, state, "valid", match); - return internals.finalize(value, null, helpers); - } - if (schema._flags.only) { - const report = schema.$_createError("any.only", value, { valids: schema._valids.values({ display: true }) }, state, prefs); - if (prefs.abortEarly) { - return internals.finalize(value, [report], helpers); - } - errors.push(report); - } + check(weight, now) { + return this.conditionsCheck(weight) && this._nextRequest - now <= 0; } - if (schema._invalids) { - const match = schema._invalids.get(value, state, prefs, schema._flags.insensitive); - if (match) { - state.mainstay.tracer.filter(schema, state, "invalid", match); - const report = schema.$_createError("any.invalid", value, { invalids: schema._invalids.values({ display: true }) }, state, prefs); - if (prefs.abortEarly) { - return internals.finalize(value, [report], helpers); - } - errors.push(report); - } + __check__(weight) { + var _this10 = this; + return _asyncToGenerator2(function* () { + var now; + yield _this10.yieldLoop(); + now = Date.now(); + return _this10.check(weight, now); + })(); } - if (def.validate) { - const base2 = def.validate(value, helpers); - if (base2) { - state.mainstay.tracer.value(state, "base", value, base2.value); - value = base2.value; - if (base2.errors) { - if (!Array.isArray(base2.errors)) { - errors.push(base2.errors); - return internals.finalize(value, errors, helpers); - } - if (base2.errors.length) { - errors.push(...base2.errors); - return internals.finalize(value, errors, helpers); + __register__(index, weight, expiration) { + var _this11 = this; + return _asyncToGenerator2(function* () { + var now, wait; + yield _this11.yieldLoop(); + now = Date.now(); + if (_this11.conditionsCheck(weight)) { + _this11._running += weight; + if (_this11.storeOptions.reservoir != null) { + _this11.storeOptions.reservoir -= weight; } + wait = Math.max(_this11._nextRequest - now, 0); + _this11._nextRequest = now + wait + _this11.storeOptions.minTime; + return { + success: true, + wait, + reservoir: _this11.storeOptions.reservoir + }; + } else { + return { + success: false + }; } - } + })(); } - if (!schema._rules.length) { - return internals.finalize(value, errors, helpers); + strategyIsBlock() { + return this.storeOptions.strategy === 3; } - return internals.rules(value, errors, helpers); - }; - internals.rules = function(value, errors, helpers) { - const { schema, state, prefs } = helpers; - for (const rule of schema._rules) { - const definition = schema._definition.rules[rule.method]; - if (definition.convert && prefs.convert) { - state.mainstay.tracer.log(schema, state, "rule", rule.name, "full"); - continue; - } - let ret; - let args = rule.args; - if (rule._resolve.length) { - args = Object.assign({}, args); - for (const key of rule._resolve) { - const resolver = definition.argsByName.get(key); - const resolved = args[key].resolve(value, state, prefs); - const normalized = resolver.normalize ? resolver.normalize(resolved) : resolved; - const invalid = Common.validateArg(normalized, null, resolver); - if (invalid) { - ret = schema.$_createError("any.ref", resolved, { arg: key, ref: args[key], reason: invalid }, state, prefs); - break; - } - args[key] = normalized; - } - } - ret = ret || definition.validate(value, helpers, args, rule); - const result = internals.rule(ret, rule); - if (result.errors) { - state.mainstay.tracer.log(schema, state, "rule", rule.name, "error"); - if (rule.warn) { - state.mainstay.warnings.push(...result.errors); - continue; + __submit__(queueLength, weight) { + var _this12 = this; + return _asyncToGenerator2(function* () { + var blocked, now, reachedHWM; + yield _this12.yieldLoop(); + if (_this12.storeOptions.maxConcurrent != null && weight > _this12.storeOptions.maxConcurrent) { + throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${_this12.storeOptions.maxConcurrent}`); } - if (prefs.abortEarly) { - return internals.finalize(value, result.errors, helpers); + now = Date.now(); + reachedHWM = _this12.storeOptions.highWater != null && queueLength === _this12.storeOptions.highWater && !_this12.check(weight, now); + blocked = _this12.strategyIsBlock() && (reachedHWM || _this12.isBlocked(now)); + if (blocked) { + _this12._unblockTime = now + _this12.computePenalty(); + _this12._nextRequest = _this12._unblockTime + _this12.storeOptions.minTime; + _this12.instance._dropAllQueued(); } - errors.push(...result.errors); - } else { - state.mainstay.tracer.log(schema, state, "rule", rule.name, "pass"); - state.mainstay.tracer.value(state, "rule", value, result.value, rule.name); - value = result.value; - } - } - return internals.finalize(value, errors, helpers); - }; - internals.rule = function(ret, rule) { - if (ret instanceof Errors.Report) { - internals.error(ret, rule); - return { errors: [ret], value: null }; - } - if (Array.isArray(ret) && ret[Common.symbols.errors]) { - ret.forEach((report) => internals.error(report, rule)); - return { errors: ret, value: null }; + return { + reachedHWM, + blocked, + strategy: _this12.storeOptions.strategy + }; + })(); } - return { errors: null, value: ret }; - }; - internals.error = function(report, rule) { - if (rule.message) { - report._setTemplate(rule.message); + __free__(index, weight) { + var _this13 = this; + return _asyncToGenerator2(function* () { + yield _this13.yieldLoop(); + _this13._running -= weight; + _this13._done += weight; + _this13.instance._drainAll(_this13.computeCapacity()); + return { + running: _this13._running + }; + })(); } - return report; }; - internals.finalize = function(value, errors, helpers) { - errors = errors || []; - const { schema, state, prefs } = helpers; - if (errors.length) { - const failover = internals.default("failover", void 0, errors, helpers); - if (failover !== void 0) { - state.mainstay.tracer.value(state, "failover", value, failover); - value = failover; - errors = []; - } - } - if (errors.length && schema._flags.error) { - if (typeof schema._flags.error === "function") { - errors = schema._flags.error(errors); - if (!Array.isArray(errors)) { - errors = [errors]; - } - for (const error2 of errors) { - assert2(error2 instanceof Error || error2 instanceof Errors.Report, "error() must return an Error object"); - } - } else { - errors = [schema._flags.error]; - } - } - if (value === void 0) { - const defaulted = internals.default("default", value, errors, helpers); - state.mainstay.tracer.value(state, "default", value, defaulted); - value = defaulted; - } - if (schema._flags.cast && value !== void 0) { - const caster = schema._definition.cast[schema._flags.cast]; - if (caster.from(value)) { - const casted = caster.to(value, helpers); - state.mainstay.tracer.value(state, "cast", value, casted, schema._flags.cast); - value = casted; - } - } - if (schema.$_terms.externals && prefs.externals && prefs._externals !== false) { - for (const { method } of schema.$_terms.externals) { - state.mainstay.externals.push({ method, schema, state, label: Errors.label(schema._flags, state, prefs) }); - } - } - const result = { value, errors: errors.length ? errors : null }; - if (schema._flags.result) { - result.value = schema._flags.result === "strip" ? void 0 : ( - /* raw */ - helpers.original - ); - state.mainstay.tracer.value(state, schema._flags.result, value, result.value); - state.shadow(value, schema._flags.result); - } - if (schema._cache && prefs.cache !== false && !schema._refs.length) { - schema._cache.set(helpers.original, result); - } - if (value !== void 0 && !result.errors && schema._flags.artifact !== void 0) { - state.mainstay.artifacts = state.mainstay.artifacts || /* @__PURE__ */ new Map(); - if (!state.mainstay.artifacts.has(schema._flags.artifact)) { - state.mainstay.artifacts.set(schema._flags.artifact, []); - } - state.mainstay.artifacts.get(schema._flags.artifact).push(state.path); - } - return result; + module14.exports = LocalDatastore; + } +}); +var require_lua = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/lua.json"(exports2, module14) { + module14.exports = { + "blacklist_client.lua": "local blacklist = ARGV[num_static_argv + 1]\n\nif redis.call('zscore', client_last_seen_key, blacklist) then\n redis.call('zadd', client_last_seen_key, 0, blacklist)\nend\n\n\nreturn {}\n", + "check.lua": "local weight = tonumber(ARGV[num_static_argv + 1])\n\nlocal capacity = process_tick(now, false)['capacity']\nlocal nextRequest = tonumber(redis.call('hget', settings_key, 'nextRequest'))\n\nreturn conditions_check(capacity, weight) and nextRequest - now <= 0\n", + "conditions_check.lua": "local conditions_check = function (capacity, weight)\n return capacity == nil or weight <= capacity\nend\n", + "current_reservoir.lua": "return process_tick(now, false)['reservoir']\n", + "done.lua": "process_tick(now, false)\n\nreturn tonumber(redis.call('hget', settings_key, 'done'))\n", + "free.lua": "local index = ARGV[num_static_argv + 1]\n\nredis.call('zadd', job_expirations_key, 0, index)\n\nreturn process_tick(now, false)['running']\n", + "get_time.lua": "redis.replicate_commands()\n\nlocal get_time = function ()\n local time = redis.call('time')\n\n return tonumber(time[1]..string.sub(time[2], 1, 3))\nend\n", + "group_check.lua": "return not (redis.call('exists', settings_key) == 1)\n", + "heartbeat.lua": "process_tick(now, true)\n", + "increment_reservoir.lua": "local incr = tonumber(ARGV[num_static_argv + 1])\n\nredis.call('hincrby', settings_key, 'reservoir', incr)\n\nlocal reservoir = process_tick(now, true)['reservoir']\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn reservoir\n", + "init.lua": `local clear = tonumber(ARGV[num_static_argv + 1]) +local limiter_version = ARGV[num_static_argv + 2] +local num_local_argv = num_static_argv + 2 + +if clear == 1 then + redis.call('del', unpack(KEYS)) +end + +if redis.call('exists', settings_key) == 0 then + -- Create + local args = {'hmset', settings_key} + + for i = num_local_argv + 1, #ARGV do + table.insert(args, ARGV[i]) + end + + redis.call(unpack(args)) + redis.call('hmset', settings_key, + 'nextRequest', now, + 'lastReservoirRefresh', now, + 'lastReservoirIncrease', now, + 'running', 0, + 'done', 0, + 'unblockTime', 0, + 'capacityPriorityCounter', 0 + ) + +else + -- Apply migrations + local settings = redis.call('hmget', settings_key, + 'id', + 'version' + ) + local id = settings[1] + local current_version = settings[2] + + if current_version ~= limiter_version then + local version_digits = {} + for k, v in string.gmatch(current_version, "([^.]+)") do + table.insert(version_digits, tonumber(k)) + end + + -- 2.10.0 + if version_digits[2] < 10 then + redis.call('hsetnx', settings_key, 'reservoirRefreshInterval', '') + redis.call('hsetnx', settings_key, 'reservoirRefreshAmount', '') + redis.call('hsetnx', settings_key, 'lastReservoirRefresh', '') + redis.call('hsetnx', settings_key, 'done', 0) + redis.call('hset', settings_key, 'version', '2.10.0') + end + + -- 2.11.1 + if version_digits[2] < 11 or (version_digits[2] == 11 and version_digits[3] < 1) then + if redis.call('hstrlen', settings_key, 'lastReservoirRefresh') == 0 then + redis.call('hmset', settings_key, + 'lastReservoirRefresh', now, + 'version', '2.11.1' + ) + end + end + + -- 2.14.0 + if version_digits[2] < 14 then + local old_running_key = 'b_'..id..'_running' + local old_executing_key = 'b_'..id..'_executing' + + if redis.call('exists', old_running_key) == 1 then + redis.call('rename', old_running_key, job_weights_key) + end + if redis.call('exists', old_executing_key) == 1 then + redis.call('rename', old_executing_key, job_expirations_key) + end + redis.call('hset', settings_key, 'version', '2.14.0') + end + + -- 2.15.2 + if version_digits[2] < 15 or (version_digits[2] == 15 and version_digits[3] < 2) then + redis.call('hsetnx', settings_key, 'capacityPriorityCounter', 0) + redis.call('hset', settings_key, 'version', '2.15.2') + end + + -- 2.17.0 + if version_digits[2] < 17 then + redis.call('hsetnx', settings_key, 'clientTimeout', 10000) + redis.call('hset', settings_key, 'version', '2.17.0') + end + + -- 2.18.0 + if version_digits[2] < 18 then + redis.call('hsetnx', settings_key, 'reservoirIncreaseInterval', '') + redis.call('hsetnx', settings_key, 'reservoirIncreaseAmount', '') + redis.call('hsetnx', settings_key, 'reservoirIncreaseMaximum', '') + redis.call('hsetnx', settings_key, 'lastReservoirIncrease', now) + redis.call('hset', settings_key, 'version', '2.18.0') + end + + end + + process_tick(now, false) +end + +local groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout')) +refresh_expiration(0, 0, groupTimeout) + +return {} +`, + "process_tick.lua": "local process_tick = function (now, always_publish)\n\n local compute_capacity = function (maxConcurrent, running, reservoir)\n if maxConcurrent ~= nil and reservoir ~= nil then\n return math.min((maxConcurrent - running), reservoir)\n elseif maxConcurrent ~= nil then\n return maxConcurrent - running\n elseif reservoir ~= nil then\n return reservoir\n else\n return nil\n end\n end\n\n local settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'running',\n 'reservoir',\n 'reservoirRefreshInterval',\n 'reservoirRefreshAmount',\n 'lastReservoirRefresh',\n 'reservoirIncreaseInterval',\n 'reservoirIncreaseAmount',\n 'reservoirIncreaseMaximum',\n 'lastReservoirIncrease',\n 'capacityPriorityCounter',\n 'clientTimeout'\n )\n local id = settings[1]\n local maxConcurrent = tonumber(settings[2])\n local running = tonumber(settings[3])\n local reservoir = tonumber(settings[4])\n local reservoirRefreshInterval = tonumber(settings[5])\n local reservoirRefreshAmount = tonumber(settings[6])\n local lastReservoirRefresh = tonumber(settings[7])\n local reservoirIncreaseInterval = tonumber(settings[8])\n local reservoirIncreaseAmount = tonumber(settings[9])\n local reservoirIncreaseMaximum = tonumber(settings[10])\n local lastReservoirIncrease = tonumber(settings[11])\n local capacityPriorityCounter = tonumber(settings[12])\n local clientTimeout = tonumber(settings[13])\n\n local initial_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n --\n -- Process 'running' changes\n --\n local expired = redis.call('zrangebyscore', job_expirations_key, '-inf', '('..now)\n\n if #expired > 0 then\n redis.call('zremrangebyscore', job_expirations_key, '-inf', '('..now)\n\n local flush_batch = function (batch, acc)\n local weights = redis.call('hmget', job_weights_key, unpack(batch))\n redis.call('hdel', job_weights_key, unpack(batch))\n local clients = redis.call('hmget', job_clients_key, unpack(batch))\n redis.call('hdel', job_clients_key, unpack(batch))\n\n -- Calculate sum of removed weights\n for i = 1, #weights do\n acc['total'] = acc['total'] + (tonumber(weights[i]) or 0)\n end\n\n -- Calculate sum of removed weights by client\n local client_weights = {}\n for i = 1, #clients do\n local removed = tonumber(weights[i]) or 0\n if removed > 0 then\n acc['client_weights'][clients[i]] = (acc['client_weights'][clients[i]] or 0) + removed\n end\n end\n end\n\n local acc = {\n ['total'] = 0,\n ['client_weights'] = {}\n }\n local batch_size = 1000\n\n -- Compute changes to Zsets and apply changes to Hashes\n for i = 1, #expired, batch_size do\n local batch = {}\n for j = i, math.min(i + batch_size - 1, #expired) do\n table.insert(batch, expired[j])\n end\n\n flush_batch(batch, acc)\n end\n\n -- Apply changes to Zsets\n if acc['total'] > 0 then\n redis.call('hincrby', settings_key, 'done', acc['total'])\n running = tonumber(redis.call('hincrby', settings_key, 'running', -acc['total']))\n end\n\n for client, weight in pairs(acc['client_weights']) do\n redis.call('zincrby', client_running_key, -weight, client)\n end\n end\n\n --\n -- Process 'reservoir' changes\n --\n local reservoirRefreshActive = reservoirRefreshInterval ~= nil and reservoirRefreshAmount ~= nil\n if reservoirRefreshActive and now >= lastReservoirRefresh + reservoirRefreshInterval then\n reservoir = reservoirRefreshAmount\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirRefresh', now\n )\n end\n\n local reservoirIncreaseActive = reservoirIncreaseInterval ~= nil and reservoirIncreaseAmount ~= nil\n if reservoirIncreaseActive and now >= lastReservoirIncrease + reservoirIncreaseInterval then\n local num_intervals = math.floor((now - lastReservoirIncrease) / reservoirIncreaseInterval)\n local incr = reservoirIncreaseAmount * num_intervals\n if reservoirIncreaseMaximum ~= nil then\n incr = math.min(incr, reservoirIncreaseMaximum - (reservoir or 0))\n end\n if incr > 0 then\n reservoir = (reservoir or 0) + incr\n end\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirIncrease', lastReservoirIncrease + (num_intervals * reservoirIncreaseInterval)\n )\n end\n\n --\n -- Clear unresponsive clients\n --\n local unresponsive = redis.call('zrangebyscore', client_last_seen_key, '-inf', (now - clientTimeout))\n local unresponsive_lookup = {}\n local terminated_clients = {}\n for i = 1, #unresponsive do\n unresponsive_lookup[unresponsive[i]] = true\n if tonumber(redis.call('zscore', client_running_key, unresponsive[i])) == 0 then\n table.insert(terminated_clients, unresponsive[i])\n end\n end\n if #terminated_clients > 0 then\n redis.call('zrem', client_running_key, unpack(terminated_clients))\n redis.call('hdel', client_num_queued_key, unpack(terminated_clients))\n redis.call('zrem', client_last_registered_key, unpack(terminated_clients))\n redis.call('zrem', client_last_seen_key, unpack(terminated_clients))\n end\n\n --\n -- Broadcast capacity changes\n --\n local final_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n if always_publish or (initial_capacity ~= nil and final_capacity == nil) then\n -- always_publish or was not unlimited, now unlimited\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n\n elseif initial_capacity ~= nil and final_capacity ~= nil and final_capacity > initial_capacity then\n -- capacity was increased\n -- send the capacity message to the limiter having the lowest number of running jobs\n -- the tiebreaker is the limiter having not registered a job in the longest time\n\n local lowest_concurrency_value = nil\n local lowest_concurrency_clients = {}\n local lowest_concurrency_last_registered = {}\n local client_concurrencies = redis.call('zrange', client_running_key, 0, -1, 'withscores')\n\n for i = 1, #client_concurrencies, 2 do\n local client = client_concurrencies[i]\n local concurrency = tonumber(client_concurrencies[i+1])\n\n if (\n lowest_concurrency_value == nil or lowest_concurrency_value == concurrency\n ) and (\n not unresponsive_lookup[client]\n ) and (\n tonumber(redis.call('hget', client_num_queued_key, client)) > 0\n ) then\n lowest_concurrency_value = concurrency\n table.insert(lowest_concurrency_clients, client)\n local last_registered = tonumber(redis.call('zscore', client_last_registered_key, client))\n table.insert(lowest_concurrency_last_registered, last_registered)\n end\n end\n\n if #lowest_concurrency_clients > 0 then\n local position = 1\n local earliest = lowest_concurrency_last_registered[1]\n\n for i,v in ipairs(lowest_concurrency_last_registered) do\n if v < earliest then\n position = i\n earliest = v\n end\n end\n\n local next_client = lowest_concurrency_clients[position]\n redis.call('publish', 'b_'..id,\n 'capacity-priority:'..(final_capacity or '')..\n ':'..next_client..\n ':'..capacityPriorityCounter\n )\n redis.call('hincrby', settings_key, 'capacityPriorityCounter', '1')\n else\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n end\n end\n\n return {\n ['capacity'] = final_capacity,\n ['running'] = running,\n ['reservoir'] = reservoir\n }\nend\n", + "queued.lua": "local clientTimeout = tonumber(redis.call('hget', settings_key, 'clientTimeout'))\nlocal valid_clients = redis.call('zrangebyscore', client_last_seen_key, (now - clientTimeout), 'inf')\nlocal client_queued = redis.call('hmget', client_num_queued_key, unpack(valid_clients))\n\nlocal sum = 0\nfor i = 1, #client_queued do\n sum = sum + tonumber(client_queued[i])\nend\n\nreturn sum\n", + "refresh_expiration.lua": "local refresh_expiration = function (now, nextRequest, groupTimeout)\n\n if groupTimeout ~= nil then\n local ttl = (nextRequest + groupTimeout) - now\n\n for i = 1, #KEYS do\n redis.call('pexpire', KEYS[i], ttl)\n end\n end\n\nend\n", + "refs.lua": "local settings_key = KEYS[1]\nlocal job_weights_key = KEYS[2]\nlocal job_expirations_key = KEYS[3]\nlocal job_clients_key = KEYS[4]\nlocal client_running_key = KEYS[5]\nlocal client_num_queued_key = KEYS[6]\nlocal client_last_registered_key = KEYS[7]\nlocal client_last_seen_key = KEYS[8]\n\nlocal now = tonumber(ARGV[1])\nlocal client = ARGV[2]\n\nlocal num_static_argv = 2\n", + "register.lua": "local index = ARGV[num_static_argv + 1]\nlocal weight = tonumber(ARGV[num_static_argv + 2])\nlocal expiration = tonumber(ARGV[num_static_argv + 3])\n\nlocal state = process_tick(now, false)\nlocal capacity = state['capacity']\nlocal reservoir = state['reservoir']\n\nlocal settings = redis.call('hmget', settings_key,\n 'nextRequest',\n 'minTime',\n 'groupTimeout'\n)\nlocal nextRequest = tonumber(settings[1])\nlocal minTime = tonumber(settings[2])\nlocal groupTimeout = tonumber(settings[3])\n\nif conditions_check(capacity, weight) then\n\n redis.call('hincrby', settings_key, 'running', weight)\n redis.call('hset', job_weights_key, index, weight)\n if expiration ~= nil then\n redis.call('zadd', job_expirations_key, now + expiration, index)\n end\n redis.call('hset', job_clients_key, index, client)\n redis.call('zincrby', client_running_key, weight, client)\n redis.call('hincrby', client_num_queued_key, client, -1)\n redis.call('zadd', client_last_registered_key, now, client)\n\n local wait = math.max(nextRequest - now, 0)\n local newNextRequest = now + wait + minTime\n\n if reservoir == nil then\n redis.call('hset', settings_key,\n 'nextRequest', newNextRequest\n )\n else\n reservoir = reservoir - weight\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'nextRequest', newNextRequest\n )\n end\n\n refresh_expiration(now, newNextRequest, groupTimeout)\n\n return {true, wait, reservoir}\n\nelse\n return {false}\nend\n", + "register_client.lua": "local queued = tonumber(ARGV[num_static_argv + 1])\n\n-- Could have been re-registered concurrently\nif not redis.call('zscore', client_last_seen_key, client) then\n redis.call('zadd', client_running_key, 0, client)\n redis.call('hset', client_num_queued_key, client, queued)\n redis.call('zadd', client_last_registered_key, 0, client)\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n\nreturn {}\n", + "running.lua": "return process_tick(now, false)['running']\n", + "submit.lua": "local queueLength = tonumber(ARGV[num_static_argv + 1])\nlocal weight = tonumber(ARGV[num_static_argv + 2])\n\nlocal capacity = process_tick(now, false)['capacity']\n\nlocal settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'highWater',\n 'nextRequest',\n 'strategy',\n 'unblockTime',\n 'penalty',\n 'minTime',\n 'groupTimeout'\n)\nlocal id = settings[1]\nlocal maxConcurrent = tonumber(settings[2])\nlocal highWater = tonumber(settings[3])\nlocal nextRequest = tonumber(settings[4])\nlocal strategy = tonumber(settings[5])\nlocal unblockTime = tonumber(settings[6])\nlocal penalty = tonumber(settings[7])\nlocal minTime = tonumber(settings[8])\nlocal groupTimeout = tonumber(settings[9])\n\nif maxConcurrent ~= nil and weight > maxConcurrent then\n return redis.error_reply('OVERWEIGHT:'..weight..':'..maxConcurrent)\nend\n\nlocal reachedHWM = (highWater ~= nil and queueLength == highWater\n and not (\n conditions_check(capacity, weight)\n and nextRequest - now <= 0\n )\n)\n\nlocal blocked = strategy == 3 and (reachedHWM or unblockTime >= now)\n\nif blocked then\n local computedPenalty = penalty\n if computedPenalty == nil then\n if minTime == 0 then\n computedPenalty = 5000\n else\n computedPenalty = 15 * minTime\n end\n end\n\n local newNextRequest = now + computedPenalty + minTime\n\n redis.call('hmset', settings_key,\n 'unblockTime', now + computedPenalty,\n 'nextRequest', newNextRequest\n )\n\n local clients_queued_reset = redis.call('hkeys', client_num_queued_key)\n local queued_reset = {}\n for i = 1, #clients_queued_reset do\n table.insert(queued_reset, clients_queued_reset[i])\n table.insert(queued_reset, 0)\n end\n redis.call('hmset', client_num_queued_key, unpack(queued_reset))\n\n redis.call('publish', 'b_'..id, 'blocked:')\n\n refresh_expiration(now, newNextRequest, groupTimeout)\nend\n\nif not blocked and not reachedHWM then\n redis.call('hincrby', client_num_queued_key, client, 1)\nend\n\nreturn {reachedHWM, blocked, strategy}\n", + "update_settings.lua": "local args = {'hmset', settings_key}\n\nfor i = num_static_argv + 1, #ARGV do\n table.insert(args, ARGV[i])\nend\n\nredis.call(unpack(args))\n\nprocess_tick(now, true)\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn {}\n", + "validate_client.lua": "if not redis.call('zscore', client_last_seen_key, client) then\n return redis.error_reply('UNKNOWN_CLIENT')\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n", + "validate_keys.lua": "if not (redis.call('exists', settings_key) == 1) then\n return redis.error_reply('SETTINGS_KEY_NOT_FOUND')\nend\n" }; - internals.prefs = function(schema, prefs) { - const isDefaultOptions = prefs === Common.defaults; - if (isDefaultOptions && schema._preferences[Common.symbols.prefs]) { - return schema._preferences[Common.symbols.prefs]; - } - prefs = Common.preferences(prefs, schema._preferences); - if (isDefaultOptions) { - schema._preferences[Common.symbols.prefs] = prefs; - } - return prefs; + } +}); +var require_Scripts = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Scripts.js"(exports2) { + "use strict"; + var headers; + var lua; + var templates; + lua = require_lua(); + headers = { + refs: lua["refs.lua"], + validate_keys: lua["validate_keys.lua"], + validate_client: lua["validate_client.lua"], + refresh_expiration: lua["refresh_expiration.lua"], + process_tick: lua["process_tick.lua"], + conditions_check: lua["conditions_check.lua"], + get_time: lua["get_time.lua"] }; - internals.default = function(flag, value, errors, helpers) { - const { schema, state, prefs } = helpers; - const source = schema._flags[flag]; - if (prefs.noDefaults || source === void 0) { - return value; - } - state.mainstay.tracer.log(schema, state, "rule", flag, "full"); - if (!source) { - return source; - } - if (typeof source === "function") { - const args = source.length ? [clone2(state.ancestors[0]), helpers] : []; - try { - return source(...args); - } catch (err) { - errors.push(schema.$_createError(`any.${flag}`, null, { error: err }, state, prefs)); - return; - } - } - if (typeof source !== "object") { - return source; - } - if (source[Common.symbols.literal]) { - return source.literal; - } - if (Common.isResolvable(source)) { - return source.resolve(value, state, prefs); - } - return clone2(source); + exports2.allKeys = function(id) { + return [ + /* + HASH + */ + `b_${id}_settings`, + /* + HASH + job index -> weight + */ + `b_${id}_job_weights`, + /* + ZSET + job index -> expiration + */ + `b_${id}_job_expirations`, + /* + HASH + job index -> client + */ + `b_${id}_job_clients`, + /* + ZSET + client -> sum running + */ + `b_${id}_client_running`, + /* + HASH + client -> num queued + */ + `b_${id}_client_num_queued`, + /* + ZSET + client -> last job registered + */ + `b_${id}_client_last_registered`, + /* + ZSET + client -> last seen + */ + `b_${id}_client_last_seen` + ]; }; - internals.trim = function(value, schema) { - if (typeof value !== "string") { - return value; - } - const trim = schema.$_getRule("trim"); - if (!trim || !trim.args.enabled) { - return value; + templates = { + init: { + keys: exports2.allKeys, + headers: ["process_tick"], + refresh_expiration: true, + code: lua["init.lua"] + }, + group_check: { + keys: exports2.allKeys, + headers: [], + refresh_expiration: false, + code: lua["group_check.lua"] + }, + register_client: { + keys: exports2.allKeys, + headers: ["validate_keys"], + refresh_expiration: false, + code: lua["register_client.lua"] + }, + blacklist_client: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client"], + refresh_expiration: false, + code: lua["blacklist_client.lua"] + }, + heartbeat: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["heartbeat.lua"] + }, + update_settings: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["update_settings.lua"] + }, + running: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["running.lua"] + }, + queued: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client"], + refresh_expiration: false, + code: lua["queued.lua"] + }, + done: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["done.lua"] + }, + check: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: false, + code: lua["check.lua"] + }, + submit: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: true, + code: lua["submit.lua"] + }, + register: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: true, + code: lua["register.lua"] + }, + free: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["free.lua"] + }, + current_reservoir: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["current_reservoir.lua"] + }, + increment_reservoir: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["increment_reservoir.lua"] } - return value.trim(); }; - internals.ignore = { - active: false, - debug: ignore, - entry: ignore, - filter: ignore, - log: ignore, - resolve: ignore, - value: ignore + exports2.names = Object.keys(templates); + exports2.keys = function(name, id) { + return templates[name].keys(id); }; - internals.errorsArray = function() { - const errors = []; - errors[Common.symbols.errors] = true; - return errors; + exports2.payload = function(name) { + var template; + template = templates[name]; + return Array.prototype.concat(headers.refs, template.headers.map(function(h2) { + return headers[h2]; + }), template.refresh_expiration ? headers.refresh_expiration : "", template.code).join("\n"); }; } }); -var require_values2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/values.js"(exports2, module14) { +var require_RedisConnection = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisConnection.js"(exports, module) { "use strict"; - var { assert: assert2, deepEqual } = require_lib(); - var Common = require_common3(); - var internals = {}; - module14.exports = internals.Values = class { - constructor(values, refs) { - this._values = new Set(values); - this._refs = new Set(refs); - this._lowercase = internals.lowercases(values); - this._override = false; - } - get length() { - return this._values.size + this._refs.size; + function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - add(value, refs) { - if (Common.isResolvable(value)) { - if (!this._refs.has(value)) { - this._refs.add(value); - if (refs) { - refs.register(value); - } - } - return; - } - if (!this.has(value, null, null, false)) { - this._values.add(value); - if (typeof value === "string") { - this._lowercase.set(value.toLowerCase(), value); - } - } + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - static merge(target, source, remove) { - target = target || new internals.Values(); - if (source) { - if (source._override) { - return source.clone(); - } - for (const item of [...source._values, ...source._refs]) { - target.add(item); + } + function _asyncToGenerator(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); } - } - if (remove) { - for (const item of [...remove._values, ...remove._refs]) { - target.remove(item); + function _throw(err) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); } - } - return target.length ? target : null; - } - remove(value) { - if (Common.isResolvable(value)) { - this._refs.delete(value); - return; - } - this._values.delete(value); - if (typeof value === "string") { - this._lowercase.delete(value.toLowerCase()); - } - } - has(value, state, prefs, insensitive) { - return !!this.get(value, state, prefs, insensitive); - } - get(value, state, prefs, insensitive) { - if (!this.length) { - return false; - } - if (this._values.has(value)) { - return { value }; - } - if (typeof value === "string" && value && insensitive) { - const found = this._lowercase.get(value.toLowerCase()); - if (found) { - return { value: found }; + _next(void 0); + }); + }; + } + var Events; + var RedisConnection; + var Scripts; + var parser; + parser = require_parser2(); + Events = require_Events(); + Scripts = require_Scripts(); + RedisConnection = function() { + class RedisConnection { + constructor(options = {}) { + parser.load(options, this.defaults, this); + if (this.Redis == null) { + this.Redis = eval("require")("redis"); } - } - if (!this._refs.size && typeof value !== "object") { - return false; - } - if (typeof value === "object") { - for (const item of this._values) { - if (deepEqual(item, value)) { - return { value: item }; - } + if (this.Events == null) { + this.Events = new Events(this); } - } - if (state) { - for (const ref of this._refs) { - const resolved = ref.resolve(value, state, prefs, null, { in: true }); - if (resolved === void 0) { - continue; - } - const items = !ref.in || typeof resolved !== "object" ? [resolved] : Array.isArray(resolved) ? resolved : Object.keys(resolved); - for (const item of items) { - if (typeof item !== typeof value) { - continue; - } - if (insensitive && value && typeof value === "string") { - if (item.toLowerCase() === value.toLowerCase()) { - return { value: item, ref }; - } - } else { - if (deepEqual(item, value)) { - return { value: item, ref }; - } - } - } + this.terminated = false; + if (this.client == null) { + this.client = this.Redis.createClient(this.clientOptions); } + this.subscriber = this.client.duplicate(); + this.limiters = {}; + this.shas = {}; + this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { + return this._loadScripts(); + }).then(() => { + return { + client: this.client, + subscriber: this.subscriber + }; + }); } - return false; - } - override() { - this._override = true; - } - values(options2) { - if (options2 && options2.display) { - const values = []; - for (const item of [...this._values, ...this._refs]) { - if (item !== void 0) { - values.push(item); + _setup(client, sub) { + client.setMaxListeners(0); + return new this.Promise((resolve82, reject) => { + client.on("error", (e2) => { + return this.Events.trigger("error", e2); + }); + if (sub) { + client.on("message", (channel, message) => { + var ref; + return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; + }); } - } - return values; - } - return Array.from([...this._values, ...this._refs]); - } - clone() { - const set = new internals.Values(this._values, this._refs); - set._override = this._override; - return set; - } - concat(source) { - assert2(!source._override, "Cannot concat override set of values"); - const set = new internals.Values([...this._values, ...source._values], [...this._refs, ...source._refs]); - set._override = this._override; - return set; - } - describe() { - const normalized = []; - if (this._override) { - normalized.push({ override: true }); - } - for (const value of this._values.values()) { - normalized.push(value && typeof value === "object" ? { value } : value); - } - for (const value of this._refs.values()) { - normalized.push(value.describe()); - } - return normalized; - } - }; - internals.Values.prototype[Common.symbols.values] = true; - internals.Values.prototype.slice = internals.Values.prototype.clone; - internals.lowercases = function(from3) { - const map = /* @__PURE__ */ new Map(); - if (from3) { - for (const value of from3) { - if (typeof value === "string") { - map.set(value.toLowerCase(), value); - } - } - } - return map; - }; - } -}); -var require_base2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/base.js"(exports2, module14) { - "use strict"; - var { assert: assert2, clone: clone2, deepEqual, merge: merge3 } = require_lib(); - var Cache = require_cache2(); - var Common = require_common3(); - var Compile = require_compile2(); - var Errors = require_errors3(); - var Extend = require_extend2(); - var Manifest = require_manifest(); - var Messages = require_messages2(); - var Modify = require_modify2(); - var Ref = require_ref2(); - var Trace = require_trace(); - var Validator = require_validator3(); - var Values = require_values2(); - var internals = {}; - internals.Base = class { - constructor(type) { - this.type = type; - this.$_root = null; - this._definition = {}; - this._reset(); - } - _reset() { - this._ids = new Modify.Ids(); - this._preferences = null; - this._refs = new Ref.Manager(); - this._cache = null; - this._valids = null; - this._invalids = null; - this._flags = {}; - this._rules = []; - this._singleRules = /* @__PURE__ */ new Map(); - this.$_terms = {}; - this.$_temp = { - // Runtime state (not cloned) - ruleset: null, - // null: use last, false: error, number: start position - whens: {} - // Runtime cache of generated whens - }; - } - // Manifest - describe() { - assert2(typeof Manifest.describe === "function", "Manifest functionality disabled"); - return Manifest.describe(this); - } - // Rules - allow(...values) { - Common.verifyFlat(values, "allow"); - return this._values(values, "_valids"); - } - alter(targets) { - assert2(targets && typeof targets === "object" && !Array.isArray(targets), "Invalid targets argument"); - assert2(!this._inRuleset(), "Cannot set alterations inside a ruleset"); - const obj = this.clone(); - obj.$_terms.alterations = obj.$_terms.alterations || []; - for (const target in targets) { - const adjuster = targets[target]; - assert2(typeof adjuster === "function", "Alteration adjuster for", target, "must be a function"); - obj.$_terms.alterations.push({ target, adjuster }); - } - obj.$_temp.ruleset = false; - return obj; - } - artifact(id) { - assert2(id !== void 0, "Artifact cannot be undefined"); - assert2(!this._cache, "Cannot set an artifact with a rule cache"); - return this.$_setFlag("artifact", id); - } - cast(to) { - assert2(to === false || typeof to === "string", "Invalid to value"); - assert2(to === false || this._definition.cast[to], "Type", this.type, "does not support casting to", to); - return this.$_setFlag("cast", to === false ? void 0 : to); - } - default(value, options2) { - return this._default("default", value, options2); - } - description(desc) { - assert2(desc && typeof desc === "string", "Description must be a non-empty string"); - return this.$_setFlag("description", desc); - } - empty(schema) { - const obj = this.clone(); - if (schema !== void 0) { - schema = obj.$_compile(schema, { override: false }); - } - return obj.$_setFlag("empty", schema, { clone: false }); - } - error(err) { - assert2(err, "Missing error"); - assert2(err instanceof Error || typeof err === "function", "Must provide a valid Error object or a function"); - return this.$_setFlag("error", err); - } - example(example, options2 = {}) { - assert2(example !== void 0, "Missing example"); - Common.assertOptions(options2, ["override"]); - return this._inner("examples", example, { single: true, override: options2.override }); - } - external(method, description) { - if (typeof method === "object") { - assert2(!description, "Cannot combine options with description"); - description = method.description; - method = method.method; - } - assert2(typeof method === "function", "Method must be a function"); - assert2(description === void 0 || description && typeof description === "string", "Description must be a non-empty string"); - return this._inner("externals", { method, description }, { single: true }); - } - failover(value, options2) { - return this._default("failover", value, options2); - } - forbidden() { - return this.presence("forbidden"); - } - id(id) { - if (!id) { - return this.$_setFlag("id", void 0); - } - assert2(typeof id === "string", "id must be a non-empty string"); - assert2(/^[^\.]+$/.test(id), "id cannot contain period character"); - return this.$_setFlag("id", id); - } - invalid(...values) { - return this._values(values, "_invalids"); - } - label(name) { - assert2(name && typeof name === "string", "Label name must be a non-empty string"); - return this.$_setFlag("label", name); - } - meta(meta) { - assert2(meta !== void 0, "Meta cannot be undefined"); - return this._inner("metas", meta, { single: true }); - } - note(...notes) { - assert2(notes.length, "Missing notes"); - for (const note of notes) { - assert2(note && typeof note === "string", "Notes must be non-empty strings"); - } - return this._inner("notes", notes); - } - only(mode = true) { - assert2(typeof mode === "boolean", "Invalid mode:", mode); - return this.$_setFlag("only", mode); - } - optional() { - return this.presence("optional"); - } - prefs(prefs) { - assert2(prefs, "Missing preferences"); - assert2(prefs.context === void 0, "Cannot override context"); - assert2(prefs.externals === void 0, "Cannot override externals"); - assert2(prefs.warnings === void 0, "Cannot override warnings"); - assert2(prefs.debug === void 0, "Cannot override debug"); - Common.checkPreferences(prefs); - const obj = this.clone(); - obj._preferences = Common.preferences(obj._preferences, prefs); - return obj; - } - presence(mode) { - assert2(["optional", "required", "forbidden"].includes(mode), "Unknown presence mode", mode); - return this.$_setFlag("presence", mode); - } - raw(enabled2 = true) { - return this.$_setFlag("result", enabled2 ? "raw" : void 0); - } - result(mode) { - assert2(["raw", "strip"].includes(mode), "Unknown result mode", mode); - return this.$_setFlag("result", mode); - } - required() { - return this.presence("required"); - } - strict(enabled2) { - const obj = this.clone(); - const convert = enabled2 === void 0 ? false : !enabled2; - obj._preferences = Common.preferences(obj._preferences, { convert }); - return obj; - } - strip(enabled2 = true) { - return this.$_setFlag("result", enabled2 ? "strip" : void 0); - } - tag(...tags) { - assert2(tags.length, "Missing tags"); - for (const tag3 of tags) { - assert2(tag3 && typeof tag3 === "string", "Tags must be non-empty strings"); - } - return this._inner("tags", tags); - } - unit(name) { - assert2(name && typeof name === "string", "Unit name must be a non-empty string"); - return this.$_setFlag("unit", name); - } - valid(...values) { - Common.verifyFlat(values, "valid"); - const obj = this.allow(...values); - obj.$_setFlag("only", !!obj._valids, { clone: false }); - return obj; - } - when(condition, options2) { - const obj = this.clone(); - if (!obj.$_terms.whens) { - obj.$_terms.whens = []; - } - const when = Compile.when(obj, condition, options2); - if (!["any", "link"].includes(obj.type)) { - const conditions = when.is ? [when] : when.switch; - for (const item of conditions) { - assert2(!item.then || item.then.type === "any" || item.then.type === obj.type, "Cannot combine", obj.type, "with", item.then && item.then.type); - assert2(!item.otherwise || item.otherwise.type === "any" || item.otherwise.type === obj.type, "Cannot combine", obj.type, "with", item.otherwise && item.otherwise.type); - } - } - obj.$_terms.whens.push(when); - return obj.$_mutateRebuild(); - } - // Helpers - cache(cache2) { - assert2(!this._inRuleset(), "Cannot set caching inside a ruleset"); - assert2(!this._cache, "Cannot override schema cache"); - assert2(this._flags.artifact === void 0, "Cannot cache a rule with an artifact"); - const obj = this.clone(); - obj._cache = cache2 || Cache.provider.provision(); - obj.$_temp.ruleset = false; - return obj; - } - clone() { - const obj = Object.create(Object.getPrototypeOf(this)); - return this._assign(obj); - } - concat(source) { - assert2(Common.isSchema(source), "Invalid schema object"); - assert2(this.type === "any" || source.type === "any" || source.type === this.type, "Cannot merge type", this.type, "with another type:", source.type); - assert2(!this._inRuleset(), "Cannot concatenate onto a schema with open ruleset"); - assert2(!source._inRuleset(), "Cannot concatenate a schema with open ruleset"); - let obj = this.clone(); - if (this.type === "any" && source.type !== "any") { - const tmpObj = source.clone(); - for (const key of Object.keys(obj)) { - if (key !== "type") { - tmpObj[key] = obj[key]; - } - } - obj = tmpObj; - } - obj._ids.concat(source._ids); - obj._refs.register(source, Ref.toSibling); - obj._preferences = obj._preferences ? Common.preferences(obj._preferences, source._preferences) : source._preferences; - obj._valids = Values.merge(obj._valids, source._valids, source._invalids); - obj._invalids = Values.merge(obj._invalids, source._invalids, source._valids); - for (const name of source._singleRules.keys()) { - if (obj._singleRules.has(name)) { - obj._rules = obj._rules.filter((target) => target.keep || target.name !== name); - obj._singleRules.delete(name); - } - } - for (const test of source._rules) { - if (!source._definition.rules[test.method].multi) { - obj._singleRules.set(test.name, test); - } - obj._rules.push(test); - } - if (obj._flags.empty && source._flags.empty) { - obj._flags.empty = obj._flags.empty.concat(source._flags.empty); - const flags = Object.assign({}, source._flags); - delete flags.empty; - merge3(obj._flags, flags); - } else if (source._flags.empty) { - obj._flags.empty = source._flags.empty; - const flags = Object.assign({}, source._flags); - delete flags.empty; - merge3(obj._flags, flags); - } else { - merge3(obj._flags, source._flags); - } - for (const key in source.$_terms) { - const terms = source.$_terms[key]; - if (!terms) { - if (!obj.$_terms[key]) { - obj.$_terms[key] = terms; + if (client.ready) { + return resolve82(); + } else { + return client.once("ready", resolve82); } - continue; - } - if (!obj.$_terms[key]) { - obj.$_terms[key] = terms.slice(); - continue; - } - obj.$_terms[key] = obj.$_terms[key].concat(terms); - } - if (this.$_root._tracer) { - this.$_root._tracer._combine(obj, [this, source]); - } - return obj.$_mutateRebuild(); - } - extend(options2) { - assert2(!options2.base, "Cannot extend type with another base"); - return Extend.type(this, options2); - } - extract(path8) { - path8 = Array.isArray(path8) ? path8 : path8.split("."); - return this._ids.reach(path8); - } - fork(paths, adjuster) { - assert2(!this._inRuleset(), "Cannot fork inside a ruleset"); - let obj = this; - for (let path8 of [].concat(paths)) { - path8 = Array.isArray(path8) ? path8 : path8.split("."); - obj = obj._ids.fork(path8, adjuster, obj); - } - obj.$_temp.ruleset = false; - return obj; - } - isAsync() { - if (Boolean(this.$_terms.externals?.length)) { - return true; + }); } - if (this.$_terms.whens) { - for (const when of this.$_terms.whens) { - if (when.then?.isAsync()) { - return true; - } - if (when.otherwise?.isAsync()) { - return true; - } - if (when.switch) { - for (const item of when.switch) { - if (item.then?.isAsync()) { - return true; - } - if (item.otherwise?.isAsync()) { - return true; - } + _loadScript(name) { + return new this.Promise((resolve82, reject) => { + var payload; + payload = Scripts.payload(name); + return this.client.multi([["script", "load", payload]]).exec((err, replies) => { + if (err != null) { + return reject(err); } - } - } - } - return false; - } - rule(options2) { - const def = this._definition; - Common.assertOptions(options2, Object.keys(def.modifiers)); - assert2(this.$_temp.ruleset !== false, "Cannot apply rules to empty ruleset or the last rule added does not support rule properties"); - const start = this.$_temp.ruleset === null ? this._rules.length - 1 : this.$_temp.ruleset; - assert2(start >= 0 && start < this._rules.length, "Cannot apply rules to empty ruleset"); - const obj = this.clone(); - for (let i2 = start; i2 < obj._rules.length; ++i2) { - const original = obj._rules[i2]; - const rule = clone2(original); - for (const name in options2) { - def.modifiers[name](rule, options2[name]); - assert2(rule.name === original.name, "Cannot change rule name"); - } - obj._rules[i2] = rule; - if (obj._singleRules.get(rule.name) === original) { - obj._singleRules.set(rule.name, rule); - } - } - obj.$_temp.ruleset = false; - return obj.$_mutateRebuild(); - } - get ruleset() { - assert2(!this._inRuleset(), "Cannot start a new ruleset without closing the previous one"); - const obj = this.clone(); - obj.$_temp.ruleset = obj._rules.length; - return obj; - } - get $() { - return this.ruleset; - } - tailor(targets) { - targets = [].concat(targets); - assert2(!this._inRuleset(), "Cannot tailor inside a ruleset"); - let obj = this; - if (this.$_terms.alterations) { - for (const { target, adjuster } of this.$_terms.alterations) { - if (targets.includes(target)) { - obj = adjuster(obj); - assert2(Common.isSchema(obj), "Alteration adjuster for", target, "failed to return a schema object"); - } - } + this.shas[name] = replies[0]; + return resolve82(replies[0]); + }); + }); } - obj = obj.$_modify({ each: (item) => item.tailor(targets), ref: false }); - obj.$_temp.ruleset = false; - return obj.$_mutateRebuild(); - } - tracer() { - return Trace.location ? Trace.location(this) : this; - } - validate(value, options2) { - return Validator.entry(value, this, options2); - } - validateAsync(value, options2) { - return Validator.entryAsync(value, this, options2); - } - // Extensions - $_addRule(options2) { - if (typeof options2 === "string") { - options2 = { name: options2 }; + _loadScripts() { + return this.Promise.all(Scripts.names.map((k) => { + return this._loadScript(k); + })); } - assert2(options2 && typeof options2 === "object", "Invalid options"); - assert2(options2.name && typeof options2.name === "string", "Invalid rule name"); - for (const key in options2) { - assert2(key[0] !== "_", "Cannot set private rule properties"); - } - const rule = Object.assign({}, options2); - rule._resolve = []; - rule.method = rule.method || rule.name; - const definition = this._definition.rules[rule.method]; - const args = rule.args; - assert2(definition, "Unknown rule", rule.method); - const obj = this.clone(); - if (args) { - assert2(Object.keys(args).length === 1 || Object.keys(args).length === this._definition.rules[rule.name].args.length, "Invalid rule definition for", this.type, rule.name); - for (const key in args) { - let arg = args[key]; - if (definition.argsByName) { - const resolver = definition.argsByName.get(key); - if (resolver.ref && Common.isResolvable(arg)) { - rule._resolve.push(key); - obj.$_mutateRegister(arg); - } else { - if (resolver.normalize) { - arg = resolver.normalize(arg); - args[key] = arg; - } - if (resolver.assert) { - const error2 = Common.validateArg(arg, key, resolver); - assert2(!error2, error2, "or reference"); + __runCommand__(cmd) { + var _this = this; + return _asyncToGenerator(function* () { + yield _this.ready; + return new _this.Promise((resolve82, reject) => { + return _this.client.multi([cmd]).exec_atomic(function(err, replies) { + if (err != null) { + return reject(err); + } else { + return resolve82(replies[0]); } - } - } - if (arg === void 0) { - delete args[key]; - continue; - } - args[key] = arg; - } - } - if (!definition.multi) { - obj._ruleRemove(rule.name, { clone: false }); - obj._singleRules.set(rule.name, rule); - } - if (obj.$_temp.ruleset === false) { - obj.$_temp.ruleset = null; - } - if (definition.priority) { - obj._rules.unshift(rule); - } else { - obj._rules.push(rule); - } - return obj; - } - $_compile(schema, options2) { - return Compile.schema(this.$_root, schema, options2); - } - $_createError(code2, value, local, state, prefs, options2 = {}) { - const flags = options2.flags !== false ? this._flags : {}; - const messages = options2.messages ? Messages.merge(this._definition.messages, options2.messages) : this._definition.messages; - return new Errors.Report(code2, value, local, flags, messages, state, prefs); - } - $_getFlag(name) { - return this._flags[name]; - } - $_getRule(name) { - return this._singleRules.get(name); - } - $_mapLabels(path8) { - path8 = Array.isArray(path8) ? path8 : path8.split("."); - return this._ids.labels(path8); - } - $_match(value, state, prefs, overrides) { - prefs = Object.assign({}, prefs); - prefs.abortEarly = true; - prefs._externals = false; - state.snapshot(); - const result = !Validator.validate(value, this, state, prefs, overrides).errors; - state.restore(); - return result; - } - $_modify(options2) { - Common.assertOptions(options2, ["each", "once", "ref", "schema"]); - return Modify.schema(this, options2) || this; - } - $_mutateRebuild() { - assert2(!this._inRuleset(), "Cannot add this rule inside a ruleset"); - this._refs.reset(); - this._ids.reset(); - const each = (item, { source, name, path: path8, key }) => { - const family = this._definition[source][name] && this._definition[source][name].register; - if (family !== false) { - this.$_mutateRegister(item, { family, key }); - } - }; - this.$_modify({ each }); - if (this._definition.rebuild) { - this._definition.rebuild(this); - } - this.$_temp.ruleset = false; - return this; - } - $_mutateRegister(schema, { family, key } = {}) { - this._refs.register(schema, family); - this._ids.register(schema, { key }); - } - $_property(name) { - return this._definition.properties[name]; - } - $_reach(path8) { - return this._ids.reach(path8); - } - $_rootReferences() { - return this._refs.roots(); - } - $_setFlag(name, value, options2 = {}) { - assert2(name[0] === "_" || !this._inRuleset(), "Cannot set flag inside a ruleset"); - const flag = this._definition.flags[name] || {}; - if (deepEqual(value, flag.default)) { - value = void 0; - } - if (deepEqual(value, this._flags[name])) { - return this; - } - const obj = options2.clone !== false ? this.clone() : this; - if (value !== void 0) { - obj._flags[name] = value; - obj.$_mutateRegister(value); - } else { - delete obj._flags[name]; - } - if (name[0] !== "_") { - obj.$_temp.ruleset = false; - } - return obj; - } - $_parent(method, ...args) { - return this[method][Common.symbols.parent].call(this, ...args); - } - $_validate(value, state, prefs) { - return Validator.validate(value, this, state, prefs); - } - // Internals - _assign(target) { - target.type = this.type; - target.$_root = this.$_root; - target.$_temp = Object.assign({}, this.$_temp); - target.$_temp.whens = {}; - target._ids = this._ids.clone(); - target._preferences = this._preferences; - target._valids = this._valids && this._valids.clone(); - target._invalids = this._invalids && this._invalids.clone(); - target._rules = this._rules.slice(); - target._singleRules = clone2(this._singleRules, { shallow: true }); - target._refs = this._refs.clone(); - target._flags = Object.assign({}, this._flags); - target._cache = null; - target.$_terms = {}; - for (const key in this.$_terms) { - target.$_terms[key] = this.$_terms[key] ? this.$_terms[key].slice() : null; - } - target.$_super = {}; - for (const override in this.$_super) { - target.$_super[override] = this._super[override].bind(target); - } - return target; - } - _bare() { - const obj = this.clone(); - obj._reset(); - const terms = obj._definition.terms; - for (const name in terms) { - const term = terms[name]; - obj.$_terms[name] = term.init; - } - return obj.$_mutateRebuild(); - } - _default(flag, value, options2 = {}) { - Common.assertOptions(options2, "literal"); - assert2(value !== void 0, "Missing", flag, "value"); - assert2(typeof value === "function" || !options2.literal, "Only function value supports literal option"); - if (typeof value === "function" && options2.literal) { - value = { - [Common.symbols.literal]: true, - literal: value - }; - } - const obj = this.$_setFlag(flag, value); - return obj; - } - _generate(value, state, prefs) { - if (!this.$_terms.whens) { - return { schema: this }; - } - const whens = []; - const ids = []; - for (let i2 = 0; i2 < this.$_terms.whens.length; ++i2) { - const when = this.$_terms.whens[i2]; - if (when.concat) { - whens.push(when.concat); - ids.push(`${i2}.concat`); - continue; - } - const input = when.ref ? when.ref.resolve(value, state, prefs) : value; - const tests = when.is ? [when] : when.switch; - const before = ids.length; - for (let j = 0; j < tests.length; ++j) { - const { is, then, otherwise } = tests[j]; - const baseId = `${i2}${when.switch ? "." + j : ""}`; - if (is.$_match(input, state.nest(is, `${baseId}.is`), prefs)) { - if (then) { - const localState = state.localize([...state.path, `${baseId}.then`], state.ancestors, state.schemas); - const { schema: generated, id: id2 } = then._generate(value, localState, prefs); - whens.push(generated); - ids.push(`${baseId}.then${id2 ? `(${id2})` : ""}`); - break; - } - } else if (otherwise) { - const localState = state.localize([...state.path, `${baseId}.otherwise`], state.ancestors, state.schemas); - const { schema: generated, id: id2 } = otherwise._generate(value, localState, prefs); - whens.push(generated); - ids.push(`${baseId}.otherwise${id2 ? `(${id2})` : ""}`); - break; - } - } - if (when.break && ids.length > before) { - break; - } - } - const id = ids.join(", "); - state.mainstay.tracer.debug(state, "rule", "when", id); - if (!id) { - return { schema: this }; - } - if (!state.mainstay.tracer.active && this.$_temp.whens[id]) { - return { schema: this.$_temp.whens[id], id }; - } - let obj = this; - if (this._definition.generate) { - obj = this._definition.generate(this, value, state, prefs); - } - for (const when of whens) { - obj = obj.concat(when); + }); + }); + })(); } - if (this.$_root._tracer) { - this.$_root._tracer._combine(obj, [this, ...whens]); + __addLimiter__(instance) { + return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { + return new this.Promise((resolve82, reject) => { + var handler; + handler = (chan) => { + if (chan === channel) { + this.subscriber.removeListener("subscribe", handler); + this.limiters[channel] = instance; + return resolve82(); + } + }; + this.subscriber.on("subscribe", handler); + return this.subscriber.subscribe(channel); + }); + })); } - this.$_temp.whens[id] = obj; - return { schema: obj, id }; - } - _inner(type, values, options2 = {}) { - assert2(!this._inRuleset(), `Cannot set ${type} inside a ruleset`); - const obj = this.clone(); - if (!obj.$_terms[type] || options2.override) { - obj.$_terms[type] = []; + __removeLimiter__(instance) { + var _this2 = this; + return this.Promise.all([instance.channel(), instance.channel_client()].map( + /* @__PURE__ */ function() { + var _ref = _asyncToGenerator(function* (channel) { + if (!_this2.terminated) { + yield new _this2.Promise((resolve82, reject) => { + return _this2.subscriber.unsubscribe(channel, function(err, chan) { + if (err != null) { + return reject(err); + } + if (chan === channel) { + return resolve82(); + } + }); + }); + } + return delete _this2.limiters[channel]; + }); + return function(_x) { + return _ref.apply(this, arguments); + }; + }() + )); } - if (options2.single) { - obj.$_terms[type].push(values); - } else { - obj.$_terms[type].push(...values); + __scriptArgs__(name, id, args, cb) { + var keys; + keys = Scripts.keys(name, id); + return [this.shas[name], keys.length].concat(keys, args, cb); } - obj.$_temp.ruleset = false; - return obj; - } - _inRuleset() { - return this.$_temp.ruleset !== null && this.$_temp.ruleset !== false; - } - _ruleRemove(name, options2 = {}) { - if (!this._singleRules.has(name)) { - return this; + __scriptFn__(name) { + return this.client.evalsha.bind(this.client); } - const obj = options2.clone !== false ? this.clone() : this; - obj._singleRules.delete(name); - const filtered = []; - for (let i2 = 0; i2 < obj._rules.length; ++i2) { - const test = obj._rules[i2]; - if (test.name === name && !test.keep) { - if (obj._inRuleset() && i2 < obj.$_temp.ruleset) { - --obj.$_temp.ruleset; - } - continue; + disconnect(flush = true) { + var i2, k, len, ref; + ref = Object.keys(this.limiters); + for (i2 = 0, len = ref.length; i2 < len; i2++) { + k = ref[i2]; + clearInterval(this.limiters[k]._store.heartbeat); } - filtered.push(test); + this.limiters = {}; + this.terminated = true; + this.client.end(flush); + this.subscriber.end(flush); + return this.Promise.resolve(); } - obj._rules = filtered; - return obj; } - _values(values, key) { - Common.verifyFlat(values, key.slice(1, -1)); - const obj = this.clone(); - const override = values[0] === Common.symbols.override; - if (override) { - values = values.slice(1); - } - if (!obj[key] && values.length) { - obj[key] = new Values(); - } else if (override) { - obj[key] = values.length ? new Values() : null; - obj.$_mutateRebuild(); - } - if (!obj[key]) { - return obj; - } - if (override) { - obj[key].override(); + ; + RedisConnection.prototype.datastore = "redis"; + RedisConnection.prototype.defaults = { + Redis: null, + clientOptions: {}, + client: null, + Promise, + Events: null + }; + return RedisConnection; + }.call(void 0); + module.exports = RedisConnection; + } +}); +var require_IORedisConnection = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/IORedisConnection.js"(exports, module) { + "use strict"; + function _slicedToArray(arr, i2) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i2) || _nonIterableRest(); + } + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + function _iterableToArrayLimit(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; } - for (const value of values) { - assert2(value !== void 0, "Cannot call allow/valid/invalid with undefined"); - assert2(value !== Common.symbols.override, "Override must be the first value"); - const other = key === "_invalids" ? "_valids" : "_invalids"; - if (obj[other]) { - obj[other].remove(value); - if (!obj[other].length) { - assert2(key === "_valids" || !obj._flags.only, "Setting invalid value", value, "leaves schema rejecting all values due to previous valid rule"); - obj[other] = null; - } - } - obj[key].add(value, obj._refs); + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } - return obj; } - // Standard Schema - get "~standard"() { - const mapToStandardError = (error2) => { - let issues; - if (Errors.ValidationError.isError(error2)) { - issues = error2.details.map(({ message, path: path8 }) => ({ - message, - path: path8 - })); - } else { - issues = [{ - message: error2.message - }]; - } - return { - issues - }; - }; - const mapToStandardValue = (value) => ({ value }); - return { - version: 1, - vendor: "joi", - validate: (value) => { - const result = Validator.standard(value, this); - if (result instanceof Promise) { - return result.then(mapToStandardValue, mapToStandardError); - } - if (!result.error) { - return mapToStandardValue(result.value); - } - return mapToStandardError(result.error); - } - }; + return _arr; + } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - }; - internals.Base.prototype[Common.symbols.any] = { - version: Common.version, - compile: Compile.compile, - root: "$_root" - }; - internals.Base.prototype.isImmutable = true; - internals.Base.prototype.deny = internals.Base.prototype.invalid; - internals.Base.prototype.disallow = internals.Base.prototype.invalid; - internals.Base.prototype.equal = internals.Base.prototype.valid; - internals.Base.prototype.exist = internals.Base.prototype.required; - internals.Base.prototype.not = internals.Base.prototype.invalid; - internals.Base.prototype.options = internals.Base.prototype.prefs; - internals.Base.prototype.preferences = internals.Base.prototype.prefs; - module14.exports = new internals.Base(); - } -}); -var require_any2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/any.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Base = require_base2(); - var Common = require_common3(); - var Messages = require_messages2(); - module14.exports = Base.extend({ - type: "any", - flags: { - only: { default: false } - }, - terms: { - alterations: { init: null }, - examples: { init: null }, - externals: { init: null }, - metas: { init: [] }, - notes: { init: [] }, - shared: { init: null }, - tags: { init: [] }, - whens: { init: null } - }, - rules: { - custom: { - method(method, description) { - assert2(typeof method === "function", "Method must be a function"); - assert2(description === void 0 || description && typeof description === "string", "Description must be a non-empty string"); - return this.$_addRule({ name: "custom", args: { method, description } }); - }, - validate(value, helpers, { method }) { - try { - return method(value, helpers); - } catch (err) { - return helpers.error("any.custom", { error: err }); - } - }, - args: ["method", "description"], - multi: true - }, - messages: { - method(messages) { - return this.prefs({ messages }); - } - }, - shared: { - method(schema) { - assert2(Common.isSchema(schema) && schema._flags.id, "Schema must be a schema with an id"); - const obj = this.clone(); - obj.$_terms.shared = obj.$_terms.shared || []; - obj.$_terms.shared.push(schema); - obj.$_mutateRegister(schema); - return obj; - } - }, - warning: { - method(code2, local) { - assert2(code2 && typeof code2 === "string", "Invalid warning code"); - return this.$_addRule({ name: "warning", args: { code: code2, local }, warn: true }); - }, - validate(value, helpers, { code: code2, local }) { - return helpers.error(code2, local); - }, - args: ["code", "local"], - multi: true - } - }, - modifiers: { - keep(rule, enabled2 = true) { - rule.keep = enabled2; - }, - message(rule, message) { - rule.message = Messages.compile(message); - }, - warn(rule, enabled2 = true) { - rule.warn = enabled2; - } - }, - manifest: { - build(obj, desc) { - for (const key in desc) { - const values = desc[key]; - if (["examples", "externals", "metas", "notes", "tags"].includes(key)) { - for (const value of values) { - obj = obj[key.slice(0, -1)](value); - } - continue; - } - if (key === "alterations") { - const alter = {}; - for (const { target, adjuster } of values) { - alter[target] = adjuster; - } - obj = obj.alter(alter); - continue; - } - if (key === "whens") { - for (const value of values) { - const { ref, is, not, then, otherwise, concat: concat2 } = value; - if (concat2) { - obj = obj.concat(concat2); - } else if (ref) { - obj = obj.when(ref, { is, not, then, otherwise, switch: value.switch, break: value.break }); - } else { - obj = obj.when(is, { then, otherwise, break: value.break }); - } - } - continue; - } - if (key === "shared") { - for (const value of values) { - obj = obj.shared(value); - } - } - } - return obj; - } - }, - messages: { - "any.custom": "{{#label}} failed custom validation because {{#error.message}}", - "any.default": "{{#label}} threw an error when running default method", - "any.failover": "{{#label}} threw an error when running failover method", - "any.invalid": "{{#label}} contains an invalid value", - "any.only": '{{#label}} must be {if(#valids.length == 1, "", "one of ")}{{#valids}}', - "any.ref": "{{#label}} {{#arg}} references {{:#ref}} which {{#reason}}", - "any.required": "{{#label}} is required", - "any.unknown": "{{#label}} is not allowed" + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - }); - } -}); -var require_alternatives2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/alternatives.js"(exports2, module14) { - "use strict"; - var { assert: assert2, merge: merge3 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var Compile = require_compile2(); - var Errors = require_errors3(); - var Ref = require_ref2(); - var internals = {}; - module14.exports = Any.extend({ - type: "alternatives", - flags: { - match: { default: "any" } - // 'any', 'one', 'all' - }, - terms: { - matches: { init: [], register: Ref.toSibling } - }, - args(schema, ...schemas) { - if (schemas.length === 1) { - if (Array.isArray(schemas[0])) { - return schema.try(...schemas[0]); - } - } - return schema.try(...schemas); - }, - validate(value, helpers) { - const { schema, error: error2, state, prefs } = helpers; - if (schema._flags.match) { - const matched = []; - const failed = []; - for (let i2 = 0; i2 < schema.$_terms.matches.length; ++i2) { - const item = schema.$_terms.matches[i2]; - const localState = state.nest(item.schema, `match.${i2}`); - localState.snapshot(); - const result = item.schema.$_validate(value, localState, prefs); - if (!result.errors) { - matched.push(result.value); - localState.commit(); - } else { - failed.push(result.errors); - localState.restore(); - } - } - if (matched.length === 0) { - const context = { - details: failed.map((f) => Errors.details(f, { override: false })) - }; - return { errors: error2("alternatives.any", context) }; - } - if (schema._flags.match === "one") { - return matched.length === 1 ? { value: matched[0] } : { errors: error2("alternatives.one") }; - } - if (matched.length !== schema.$_terms.matches.length) { - const context = { - details: failed.map((f) => Errors.details(f, { override: false })) - }; - return { errors: error2("alternatives.all", context) }; - } - const isAnyObj = (alternative) => { - return alternative.$_terms.matches.some((v2) => { - return v2.schema.type === "object" || v2.schema.type === "alternatives" && isAnyObj(v2.schema); - }); - }; - return isAnyObj(schema) ? { value: matched.reduce((acc, v2) => merge3(acc, v2, { mergeArrays: false })) } : { value: matched[matched.length - 1] }; - } - const errors = []; - for (let i2 = 0; i2 < schema.$_terms.matches.length; ++i2) { - const item = schema.$_terms.matches[i2]; - if (item.schema) { - const localState = state.nest(item.schema, `match.${i2}`); - localState.snapshot(); - const result = item.schema.$_validate(value, localState, prefs); - if (!result.errors) { - localState.commit(); - return result; - } - localState.restore(); - errors.push({ schema: item.schema, reports: result.errors }); - continue; + } + function _asyncToGenerator(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); } - const input = item.ref ? item.ref.resolve(value, state, prefs) : value; - const tests = item.is ? [item] : item.switch; - for (let j = 0; j < tests.length; ++j) { - const test = tests[j]; - const { is, then, otherwise } = test; - const id = `match.${i2}${item.switch ? "." + j : ""}`; - if (!is.$_match(input, state.nest(is, `${id}.is`), prefs)) { - if (otherwise) { - return otherwise.$_validate(value, state.nest(otherwise, `${id}.otherwise`), prefs); - } - } else if (then) { - return then.$_validate(value, state.nest(then, `${id}.then`), prefs); - } + function _throw(err) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); } - } - return internals.errors(errors, helpers); - }, - rules: { - conditional: { - method(condition, options2) { - assert2(!this._flags._endedSwitch, "Unreachable condition"); - assert2(!this._flags.match, "Cannot combine match mode", this._flags.match, "with conditional rule"); - assert2(options2.break === void 0, "Cannot use break option with alternatives conditional"); - const obj = this.clone(); - const match = Compile.when(obj, condition, options2); - const conditions = match.is ? [match] : match.switch; - for (const item of conditions) { - if (item.then && item.otherwise) { - obj.$_setFlag("_endedSwitch", true, { clone: false }); - break; - } - } - obj.$_terms.matches.push(match); - return obj.$_mutateRebuild(); + _next(void 0); + }); + }; + } + var Events; + var IORedisConnection; + var Scripts; + var parser; + parser = require_parser2(); + Events = require_Events(); + Scripts = require_Scripts(); + IORedisConnection = function() { + class IORedisConnection { + constructor(options = {}) { + parser.load(options, this.defaults, this); + if (this.Redis == null) { + this.Redis = eval("require")("ioredis"); } - }, - match: { - method(mode) { - assert2(["any", "one", "all"].includes(mode), "Invalid alternatives match mode", mode); - if (mode !== "any") { - for (const match of this.$_terms.matches) { - assert2(match.schema, "Cannot combine match mode", mode, "with conditional rules"); - } - } - return this.$_setFlag("match", mode); + if (this.Events == null) { + this.Events = new Events(this); } - }, - try: { - method(...schemas) { - assert2(schemas.length, "Missing alternative schemas"); - Common.verifyFlat(schemas, "try"); - assert2(!this._flags._endedSwitch, "Unreachable condition"); - const obj = this.clone(); - for (const schema of schemas) { - obj.$_terms.matches.push({ schema: obj.$_compile(schema) }); + this.terminated = false; + if (this.clusterNodes != null) { + this.client = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); + this.subscriber = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); + } else if (this.client != null && this.client.duplicate == null) { + this.subscriber = new this.Redis.Cluster(this.client.startupNodes, this.client.options); + } else { + if (this.client == null) { + this.client = new this.Redis(this.clientOptions); } - return obj.$_mutateRebuild(); + this.subscriber = this.client.duplicate(); } + this.limiters = {}; + this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { + this._loadScripts(); + return { + client: this.client, + subscriber: this.subscriber + }; + }); } - }, - overrides: { - label(name) { - const obj = this.$_parent("label", name); - const each = (item, source) => { - return source.path[0] !== "is" && typeof item._flags.label !== "string" ? item.label(name) : void 0; - }; - return obj.$_modify({ each, ref: false }); - }, - isAsync() { - if (this.$_terms.externals?.length) { - return true; - } - for (const match of this.$_terms.matches) { - if (match.schema?.isAsync()) { - return true; - } - if (match.then?.isAsync()) { - return true; + _setup(client, sub) { + client.setMaxListeners(0); + return new this.Promise((resolve82, reject) => { + client.on("error", (e2) => { + return this.Events.trigger("error", e2); + }); + if (sub) { + client.on("message", (channel, message) => { + var ref; + return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; + }); } - if (match.otherwise?.isAsync()) { - return true; + if (client.status === "ready") { + return resolve82(); + } else { + return client.once("ready", resolve82); } - } - return false; + }); } - }, - rebuild(schema) { - const each = (item) => { - if (Common.isSchema(item) && item.type === "array") { - schema.$_setFlag("_arrayItems", true, { clone: false }); - } - }; - schema.$_modify({ each }); - }, - manifest: { - build(obj, desc) { - if (desc.matches) { - for (const match of desc.matches) { - const { schema, ref, is, not, then, otherwise } = match; - if (schema) { - obj = obj.try(schema); - } else if (ref) { - obj = obj.conditional(ref, { is, then, not, otherwise, switch: match.switch }); - } else { - obj = obj.conditional(is, { then, otherwise }); - } - } - } - return obj; + _loadScripts() { + return Scripts.names.forEach((name) => { + return this.client.defineCommand(name, { + lua: Scripts.payload(name) + }); + }); } - }, - messages: { - "alternatives.all": "{{#label}} does not match all of the required types", - "alternatives.any": "{{#label}} does not match any of the allowed types", - "alternatives.match": "{{#label}} does not match any of the allowed types", - "alternatives.one": "{{#label}} matches more than one allowed type", - "alternatives.types": "{{#label}} must be one of {{#types}}" - } - }); - internals.errors = function(failures, { error: error2, state }) { - if (!failures.length) { - return { errors: error2("alternatives.any") }; - } - if (failures.length === 1) { - return { errors: failures[0].reports }; - } - const valids = /* @__PURE__ */ new Set(); - const complex = []; - for (const { reports, schema } of failures) { - if (reports.length > 1) { - return internals.unmatched(failures, error2); + __runCommand__(cmd) { + var _this = this; + return _asyncToGenerator(function* () { + var _, deleted; + yield _this.ready; + var _ref = yield _this.client.pipeline([cmd]).exec(); + var _ref2 = _slicedToArray(_ref, 1); + var _ref2$ = _slicedToArray(_ref2[0], 2); + _ = _ref2$[0]; + deleted = _ref2$[1]; + return deleted; + })(); } - const report = reports[0]; - if (report instanceof Errors.Report === false) { - return internals.unmatched(failures, error2); + __addLimiter__(instance) { + return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { + return new this.Promise((resolve82, reject) => { + return this.subscriber.subscribe(channel, () => { + this.limiters[channel] = instance; + return resolve82(); + }); + }); + })); } - if (report.state.path.length !== state.path.length) { - complex.push({ type: schema.type, report }); - continue; + __removeLimiter__(instance) { + var _this2 = this; + return [instance.channel(), instance.channel_client()].forEach( + /* @__PURE__ */ function() { + var _ref3 = _asyncToGenerator(function* (channel) { + if (!_this2.terminated) { + yield _this2.subscriber.unsubscribe(channel); + } + return delete _this2.limiters[channel]; + }); + return function(_x) { + return _ref3.apply(this, arguments); + }; + }() + ); } - if (report.code === "any.only") { - for (const valid of report.local.valids) { - valids.add(valid); - } - continue; + __scriptArgs__(name, id, args, cb) { + var keys; + keys = Scripts.keys(name, id); + return [keys.length].concat(keys, args, cb); } - const [type, code2] = report.code.split("."); - if (code2 !== "base") { - complex.push({ type: schema.type, report }); - } else if (report.code === "object.base") { - valids.add(report.local.type); - } else { - valids.add(type); + __scriptFn__(name) { + return this.client[name].bind(this.client); + } + disconnect(flush = true) { + var i2, k, len, ref; + ref = Object.keys(this.limiters); + for (i2 = 0, len = ref.length; i2 < len; i2++) { + k = ref[i2]; + clearInterval(this.limiters[k]._store.heartbeat); + } + this.limiters = {}; + this.terminated = true; + if (flush) { + return this.Promise.all([this.client.quit(), this.subscriber.quit()]); + } else { + this.client.disconnect(); + this.subscriber.disconnect(); + return this.Promise.resolve(); + } } } - if (!complex.length) { - return { errors: error2("alternatives.types", { types: [...valids] }) }; - } - if (complex.length === 1) { - return { errors: complex[0].report }; - } - return internals.unmatched(failures, error2); - }; - internals.unmatched = function(failures, error2) { - const errors = []; - for (const failure of failures) { - errors.push(...failure.reports); - } - return { errors: error2("alternatives.match", Errors.details(errors, { override: false })) }; - }; + ; + IORedisConnection.prototype.datastore = "ioredis"; + IORedisConnection.prototype.defaults = { + Redis: null, + clientOptions: {}, + clusterNodes: null, + client: null, + Promise, + Events: null + }; + return IORedisConnection; + }.call(void 0); + module.exports = IORedisConnection; } }); -var require_array2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/array.js"(exports2, module14) { +var require_RedisDatastore = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisDatastore.js"(exports2, module14) { "use strict"; - var { assert: assert2, deepEqual, reach } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var Compile = require_compile2(); - var internals = {}; - module14.exports = Any.extend({ - type: "array", - flags: { - single: { default: false }, - sparse: { default: false } - }, - terms: { - items: { init: [], manifest: "schema" }, - ordered: { init: [], manifest: "schema" }, - _exclusions: { init: [] }, - _inclusions: { init: [] }, - _requireds: { init: [] } - }, - coerce: { - from: "object", - method(value, { schema, state, prefs }) { - if (!Array.isArray(value)) { - return; + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + } + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; + } + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - const sort = schema.$_getRule("sort"); - if (!sort) { - return; + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } - return internals.sort(schema, value, sort.args.options, state, prefs); + _next(void 0); + }); + }; + } + var BottleneckError; + var IORedisConnection2; + var RedisConnection2; + var RedisDatastore; + var parser3; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + RedisConnection2 = require_RedisConnection(); + IORedisConnection2 = require_IORedisConnection(); + RedisDatastore = class RedisDatastore { + constructor(instance, storeOptions, storeInstanceOptions) { + this.instance = instance; + this.storeOptions = storeOptions; + this.originalId = this.instance.id; + this.clientId = this.instance._randomIndex(); + parser3.load(storeInstanceOptions, storeInstanceOptions, this); + this.clients = {}; + this.capacityPriorityCounters = {}; + this.sharedConnection = this.connection != null; + if (this.connection == null) { + this.connection = this.instance.datastore === "redis" ? new RedisConnection2({ + Redis: this.Redis, + clientOptions: this.clientOptions, + Promise: this.Promise, + Events: this.instance.Events + }) : this.instance.datastore === "ioredis" ? new IORedisConnection2({ + Redis: this.Redis, + clientOptions: this.clientOptions, + clusterNodes: this.clusterNodes, + Promise: this.Promise, + Events: this.instance.Events + }) : void 0; } - }, - validate(value, { schema, error: error2 }) { - if (!Array.isArray(value)) { - if (schema._flags.single) { - const single = [value]; - single[Common.symbols.arraySingle] = true; - return { value: single }; + this.instance.connection = this.connection; + this.instance.datastore = this.connection.datastore; + this.ready = this.connection.ready.then((clients) => { + this.clients = clients; + return this.runScript("init", this.prepareInitSettings(this.clearDatastore)); + }).then(() => { + return this.connection.__addLimiter__(this.instance); + }).then(() => { + return this.runScript("register_client", [this.instance.queued()]); + }).then(() => { + var base2; + if (typeof (base2 = this.heartbeat = setInterval(() => { + return this.runScript("heartbeat", []).catch((e2) => { + return this.instance.Events.trigger("error", e2); + }); + }, this.heartbeatInterval)).unref === "function") { + base2.unref(); } - return { errors: error2("array.base") }; - } - if (!schema.$_getRule("items") && !schema.$_terms.externals) { - return; - } - return { value: value.slice() }; - }, - rules: { - has: { - method(schema) { - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.$_addRule({ name: "has", args: { schema } }); - obj.$_mutateRegister(schema); - return obj; - }, - validate(value, { state, prefs, error: error2 }, { schema: has2 }) { - const ancestors = [value, ...state.ancestors]; - for (let i2 = 0; i2 < value.length; ++i2) { - const localState = state.localize([...state.path, i2], ancestors, has2); - if (has2.$_match(value[i2], localState, prefs)) { - return value; - } - } - const patternLabel = has2._flags.label; - if (patternLabel) { - return error2("array.hasKnown", { patternLabel }); - } - return error2("array.hasUnknown", null); - }, - multi: true - }, - items: { - method(...schemas) { - Common.verifyFlat(schemas, "items"); - const obj = this.$_addRule("items"); - for (let i2 = 0; i2 < schemas.length; ++i2) { - const type = Common.tryWithPath(() => this.$_compile(schemas[i2]), i2, { append: true }); - obj.$_terms.items.push(type); - } - return obj.$_mutateRebuild(); - }, - validate(value, { schema, error: error2, state, prefs, errorsArray }) { - const requireds = schema.$_terms._requireds.slice(); - const ordereds = schema.$_terms.ordered.slice(); - const inclusions = [...schema.$_terms._inclusions, ...requireds]; - const wasArray = !value[Common.symbols.arraySingle]; - delete value[Common.symbols.arraySingle]; - const errors = errorsArray(); - let il = value.length; - for (let i2 = 0; i2 < il; ++i2) { - const item = value[i2]; - let errored = false; - let isValid = false; - const key = wasArray ? i2 : new Number(i2); - const path8 = [...state.path, key]; - if (!schema._flags.sparse && item === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - ordereds.shift(); - continue; - } - const ancestors = [value, ...state.ancestors]; - for (const exclusion of schema.$_terms._exclusions) { - if (!exclusion.$_match(item, state.localize(path8, ancestors, exclusion), prefs, { presence: "ignore" })) { - continue; - } - errors.push(error2("array.excludes", { pos: i2, value: item }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - errored = true; - ordereds.shift(); - break; - } - if (errored) { - continue; - } - if (schema.$_terms.ordered.length) { - if (ordereds.length) { - const ordered = ordereds.shift(); - const res = ordered.$_validate(item, state.localize(path8, ancestors, ordered), prefs); - if (!res.errors) { - if (ordered._flags.result === "strip") { - internals.fastSplice(value, i2); - --i2; - --il; - } else if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - continue; - } else { - value[i2] = res.value; - } - } else { - errors.push(...res.errors); - if (prefs.abortEarly) { - return errors; - } - } - continue; - } else if (!schema.$_terms.items.length) { - errors.push(error2("array.orderedLength", { pos: i2, limit: schema.$_terms.ordered.length })); - if (prefs.abortEarly) { - return errors; - } - break; - } - } - const requiredChecks = []; - let jl = requireds.length; - for (let j = 0; j < jl; ++j) { - const localState = state.localize(path8, ancestors, requireds[j]); - localState.snapshot(); - const res = requireds[j].$_validate(item, localState, prefs); - requiredChecks[j] = res; - if (!res.errors) { - localState.commit(); - value[i2] = res.value; - isValid = true; - internals.fastSplice(requireds, j); - --j; - --jl; - if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - } - break; - } - localState.restore(); - } - if (isValid) { - continue; - } - const stripUnknown = prefs.stripUnknown && !!prefs.stripUnknown.arrays || false; - jl = inclusions.length; - for (const inclusion of inclusions) { - let res; - const previousCheck = requireds.indexOf(inclusion); - if (previousCheck !== -1) { - res = requiredChecks[previousCheck]; - } else { - const localState = state.localize(path8, ancestors, inclusion); - localState.snapshot(); - res = inclusion.$_validate(item, localState, prefs); - if (!res.errors) { - localState.commit(); - if (inclusion._flags.result === "strip") { - internals.fastSplice(value, i2); - --i2; - --il; - } else if (!schema._flags.sparse && res.value === void 0) { - errors.push(error2("array.sparse", { key, path: path8, pos: i2, value: void 0 }, state.localize(path8))); - errored = true; - } else { - value[i2] = res.value; + return this.clients; + }); + } + __publish__(message) { + var _this = this; + return _asyncToGenerator2(function* () { + var client; + var _ref = yield _this.ready; + client = _ref.client; + return client.publish(_this.instance.channel(), `message:${message.toString()}`); + })(); + } + onMessage(channel, message) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var capacity, counter, data, drained, e2, newCapacity, pos, priorityClient, rawCapacity, type; + try { + pos = message.indexOf(":"); + var _ref2 = [message.slice(0, pos), message.slice(pos + 1)]; + type = _ref2[0]; + data = _ref2[1]; + if (type === "capacity") { + return yield _this2.instance._drainAll(data.length > 0 ? ~~data : void 0); + } else if (type === "capacity-priority") { + var _data$split = data.split(":"); + var _data$split2 = _slicedToArray2(_data$split, 3); + rawCapacity = _data$split2[0]; + priorityClient = _data$split2[1]; + counter = _data$split2[2]; + capacity = rawCapacity.length > 0 ? ~~rawCapacity : void 0; + if (priorityClient === _this2.clientId) { + drained = yield _this2.instance._drainAll(capacity); + newCapacity = capacity != null ? capacity - (drained || 0) : ""; + return yield _this2.clients.client.publish(_this2.instance.channel(), `capacity-priority:${newCapacity}::${counter}`); + } else if (priorityClient === "") { + clearTimeout(_this2.capacityPriorityCounters[counter]); + delete _this2.capacityPriorityCounters[counter]; + return _this2.instance._drainAll(capacity); + } else { + return _this2.capacityPriorityCounters[counter] = setTimeout( + /* @__PURE__ */ _asyncToGenerator2(function* () { + var e3; + try { + delete _this2.capacityPriorityCounters[counter]; + yield _this2.runScript("blacklist_client", [priorityClient]); + return yield _this2.instance._drainAll(capacity); + } catch (error2) { + e3 = error2; + return _this2.instance.Events.trigger("error", e3); } - isValid = true; - break; - } - localState.restore(); - } - if (jl === 1) { - if (stripUnknown) { - internals.fastSplice(value, i2); - --i2; - --il; - isValid = true; - break; - } - errors.push(...res.errors); - if (prefs.abortEarly) { - return errors; - } - errored = true; - break; - } - } - if (errored) { - continue; - } - if ((schema.$_terms._inclusions.length || schema.$_terms._requireds.length) && !isValid) { - if (stripUnknown) { - internals.fastSplice(value, i2); - --i2; - --il; - continue; - } - errors.push(error2("array.includes", { pos: i2, value: item }, state.localize(path8))); - if (prefs.abortEarly) { - return errors; - } - } - } - if (requireds.length) { - internals.fillMissedErrors(schema, errors, requireds, value, state, prefs); - } - if (ordereds.length) { - internals.fillOrderedErrors(schema, errors, ordereds, value, state, prefs); - if (!errors.length) { - internals.fillDefault(ordereds, value, state, prefs); + }), + 1e3 + ); } + } else if (type === "message") { + return _this2.instance.Events.trigger("message", data); + } else if (type === "blocked") { + return yield _this2.instance._dropAllQueued(); } - return errors.length ? errors : value; - }, - priority: true, - manifest: false - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value.length, limit, operator)) { - return value; - } - return helpers.error("array." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } - }, - ordered: { - method(...schemas) { - Common.verifyFlat(schemas, "ordered"); - const obj = this.$_addRule("items"); - for (let i2 = 0; i2 < schemas.length; ++i2) { - const type = Common.tryWithPath(() => this.$_compile(schemas[i2]), i2, { append: true }); - internals.validateSingle(type, obj); - obj.$_mutateRegister(type); - obj.$_terms.ordered.push(type); - } - return obj.$_mutateRebuild(); - } - }, - single: { - method(enabled2) { - const value = enabled2 === void 0 ? true : !!enabled2; - assert2(!value || !this._flags._arrayItems, "Cannot specify single rule when array has array items"); - return this.$_setFlag("single", value); + } catch (error2) { + e2 = error2; + return _this2.instance.Events.trigger("error", e2); } - }, - sort: { - method(options2 = {}) { - Common.assertOptions(options2, ["by", "order"]); - const settings = { - order: options2.order || "ascending" - }; - if (options2.by) { - settings.by = Compile.ref(options2.by, { ancestor: 0 }); - assert2(!settings.by.ancestor, "Cannot sort by ancestor"); - } - return this.$_addRule({ name: "sort", args: { options: settings } }); - }, - validate(value, { error: error2, state, prefs, schema }, { options: options2 }) { - const { value: sorted, errors } = internals.sort(schema, value, options2, state, prefs); - if (errors) { - return errors; - } - for (let i2 = 0; i2 < value.length; ++i2) { - if (value[i2] !== sorted[i2]) { - return error2("array.sort", { order: options2.order, by: options2.by ? options2.by.key : "value" }); - } - } - return value; - }, - convert: true - }, - sparse: { - method(enabled2) { - const value = enabled2 === void 0 ? true : !!enabled2; - if (this._flags.sparse === value) { - return this; - } - const obj = value ? this.clone() : this.$_addRule("items"); - return obj.$_setFlag("sparse", value, { clone: false }); + })(); + } + __disconnect__(flush) { + clearInterval(this.heartbeat); + if (this.sharedConnection) { + return this.connection.__removeLimiter__(this.instance); + } else { + return this.connection.disconnect(flush); + } + } + runScript(name, args) { + var _this3 = this; + return _asyncToGenerator2(function* () { + if (!(name === "init" || name === "register_client")) { + yield _this3.ready; } - }, - unique: { - method(comparator, options2 = {}) { - assert2(!comparator || typeof comparator === "function" || typeof comparator === "string", "comparator must be a function or a string"); - Common.assertOptions(options2, ["ignoreUndefined", "separator"]); - const rule = { name: "unique", args: { options: options2, comparator } }; - if (comparator) { - if (typeof comparator === "string") { - const separator = Common.default(options2.separator, "."); - rule.path = separator ? comparator.split(separator) : [comparator]; - } else { - rule.comparator = comparator; + return new _this3.Promise((resolve82, reject) => { + var all_args, arr; + all_args = [Date.now(), _this3.clientId].concat(args); + _this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args); + arr = _this3.connection.__scriptArgs__(name, _this3.originalId, all_args, function(err, replies) { + if (err != null) { + return reject(err); } - } - return this.$_addRule(rule); - }, - validate(value, { state, error: error2, schema }, { comparator: raw, options: options2 }, { comparator, path: path8 }) { - const found = { - string: /* @__PURE__ */ Object.create(null), - number: /* @__PURE__ */ Object.create(null), - undefined: /* @__PURE__ */ Object.create(null), - boolean: /* @__PURE__ */ Object.create(null), - bigint: /* @__PURE__ */ Object.create(null), - object: /* @__PURE__ */ new Map(), - function: /* @__PURE__ */ new Map(), - custom: /* @__PURE__ */ new Map() - }; - const compare = comparator || deepEqual; - const ignoreUndefined = options2.ignoreUndefined; - for (let i2 = 0; i2 < value.length; ++i2) { - const item = path8 ? reach(value[i2], path8) : value[i2]; - const records = comparator ? found.custom : found[typeof item]; - assert2(records, "Failed to find unique map container for type", typeof item); - if (records instanceof Map) { - const entries = records.entries(); - let current; - while (!(current = entries.next()).done) { - if (compare(current.value[0], item)) { - const localState = state.localize([...state.path, i2], [value, ...state.ancestors]); - const context = { - pos: i2, - value: value[i2], - dupePos: current.value[1], - dupeValue: value[current.value[1]] - }; - if (path8) { - context.path = raw; - } - return error2("array.unique", context, localState); - } - } - records.set(item, i2); + return resolve82(replies); + }); + return _this3.connection.__scriptFn__(name)(...arr); + }).catch((e2) => { + if (e2.message === "SETTINGS_KEY_NOT_FOUND") { + if (name === "heartbeat") { + return _this3.Promise.resolve(); } else { - if ((!ignoreUndefined || item !== void 0) && records[item] !== void 0) { - const context = { - pos: i2, - value: value[i2], - dupePos: records[item], - dupeValue: value[records[item]] - }; - if (path8) { - context.path = raw; - } - const localState = state.localize([...state.path, i2], [value, ...state.ancestors]); - return error2("array.unique", context, localState); - } - records[item] = i2; + return _this3.runScript("init", _this3.prepareInitSettings(false)).then(() => { + return _this3.runScript(name, args); + }); } + } else if (e2.message === "UNKNOWN_CLIENT") { + return _this3.runScript("register_client", [_this3.instance.queued()]).then(() => { + return _this3.runScript(name, args); + }); + } else { + return _this3.Promise.reject(e2); } - return value; - }, - args: ["comparator", "options"], - multi: true - } - }, - overrides: { - isAsync() { - if (this.$_terms.externals?.length) { - return true; - } - for (const item of this.$_terms.items) { - if (item.isAsync()) { - return true; - } - } - for (const item of this.$_terms.ordered) { - if (item.isAsync()) { - return true; - } - } - return false; - } - }, - cast: { - set: { - from: Array.isArray, - to(value, helpers) { - return new Set(value); - } - } - }, - rebuild(schema) { - schema.$_terms._inclusions = []; - schema.$_terms._exclusions = []; - schema.$_terms._requireds = []; - for (const type of schema.$_terms.items) { - internals.validateSingle(type, schema); - if (type._flags.presence === "required") { - schema.$_terms._requireds.push(type); - } else if (type._flags.presence === "forbidden") { - schema.$_terms._exclusions.push(type); - } else { - schema.$_terms._inclusions.push(type); - } - } - for (const type of schema.$_terms.ordered) { - internals.validateSingle(type, schema); - } - }, - manifest: { - build(obj, desc) { - if (desc.items) { - obj = obj.items(...desc.items); - } - if (desc.ordered) { - obj = obj.ordered(...desc.ordered); - } - return obj; - } - }, - messages: { - "array.base": "{{#label}} must be an array", - "array.excludes": "{{#label}} contains an excluded value", - "array.hasKnown": "{{#label}} does not contain at least one required match for type {:#patternLabel}", - "array.hasUnknown": "{{#label}} does not contain at least one required match", - "array.includes": "{{#label}} does not match any of the allowed types", - "array.includesRequiredBoth": "{{#label}} does not contain {{#knownMisses}} and {{#unknownMisses}} other required value(s)", - "array.includesRequiredKnowns": "{{#label}} does not contain {{#knownMisses}}", - "array.includesRequiredUnknowns": "{{#label}} does not contain {{#unknownMisses}} required value(s)", - "array.length": "{{#label}} must contain {{#limit}} items", - "array.max": "{{#label}} must contain less than or equal to {{#limit}} items", - "array.min": "{{#label}} must contain at least {{#limit}} items", - "array.orderedLength": "{{#label}} must contain at most {{#limit}} items", - "array.sort": "{{#label}} must be sorted in {#order} order by {{#by}}", - "array.sort.mismatching": "{{#label}} cannot be sorted due to mismatching types", - "array.sort.unsupported": "{{#label}} cannot be sorted due to unsupported type {#type}", - "array.sparse": "{{#label}} must not be a sparse array item", - "array.unique": "{{#label}} contains a duplicate value" + }); + })(); } - }); - internals.fillMissedErrors = function(schema, errors, requireds, value, state, prefs) { - const knownMisses = []; - let unknownMisses = 0; - for (const required2 of requireds) { - const label = required2._flags.label; - if (label) { - knownMisses.push(label); - } else { - ++unknownMisses; + prepareArray(arr) { + var i2, len, results, x3; + results = []; + for (i2 = 0, len = arr.length; i2 < len; i2++) { + x3 = arr[i2]; + results.push(x3 != null ? x3.toString() : ""); } + return results; } - if (knownMisses.length) { - if (unknownMisses) { - errors.push(schema.$_createError("array.includesRequiredBoth", value, { knownMisses, unknownMisses }, state, prefs)); - } else { - errors.push(schema.$_createError("array.includesRequiredKnowns", value, { knownMisses }, state, prefs)); + prepareObject(obj) { + var arr, k, v2; + arr = []; + for (k in obj) { + v2 = obj[k]; + arr.push(k, v2 != null ? v2.toString() : ""); } - } else { - errors.push(schema.$_createError("array.includesRequiredUnknowns", value, { unknownMisses }, state, prefs)); + return arr; + } + prepareInitSettings(clear) { + var args; + args = this.prepareObject(Object.assign({}, this.storeOptions, { + id: this.originalId, + version: this.instance.version, + groupTimeout: this.timeout, + clientTimeout: this.clientTimeout + })); + args.unshift(clear ? 1 : 0, this.instance.version); + return args; } - }; - internals.fillOrderedErrors = function(schema, errors, ordereds, value, state, prefs) { - const requiredOrdereds = []; - for (const ordered of ordereds) { - if (ordered._flags.presence === "required") { - requiredOrdereds.push(ordered); - } + convertBool(b) { + return !!b; } - if (requiredOrdereds.length) { - internals.fillMissedErrors(schema, errors, requiredOrdereds, value, state, prefs); + __updateSettings__(options2) { + var _this4 = this; + return _asyncToGenerator2(function* () { + yield _this4.runScript("update_settings", _this4.prepareObject(options2)); + return parser3.overwrite(options2, options2, _this4.storeOptions); + })(); } - }; - internals.fillDefault = function(ordereds, value, state, prefs) { - const overrides = []; - let trailingUndefined = true; - for (let i2 = ordereds.length - 1; i2 >= 0; --i2) { - const ordered = ordereds[i2]; - const ancestors = [value, ...state.ancestors]; - const override = ordered.$_validate(void 0, state.localize(state.path, ancestors, ordered), prefs).value; - if (trailingUndefined) { - if (override === void 0) { - continue; - } - trailingUndefined = false; - } - overrides.unshift(override); + __running__() { + return this.runScript("running", []); } - if (overrides.length) { - value.push(...overrides); + __queued__() { + return this.runScript("queued", []); } - }; - internals.fastSplice = function(arr, i2) { - let pos = i2; - while (pos < arr.length) { - arr[pos++] = arr[pos]; + __done__() { + return this.runScript("done", []); } - --arr.length; - }; - internals.validateSingle = function(type, obj) { - if (type.type === "array" || type._flags._arrayItems) { - assert2(!obj._flags.single, "Cannot specify array item with single rule enabled"); - obj.$_setFlag("_arrayItems", true, { clone: false }); + __groupCheck__() { + var _this5 = this; + return _asyncToGenerator2(function* () { + return _this5.convertBool(yield _this5.runScript("group_check", [])); + })(); } - }; - internals.sort = function(schema, value, settings, state, prefs) { - const order = settings.order === "ascending" ? 1 : -1; - const aFirst = -1 * order; - const bFirst = order; - const sort = (a, b) => { - let compare = internals.compare(a, b, aFirst, bFirst); - if (compare !== null) { - return compare; - } - if (settings.by) { - a = settings.by.resolve(a, state, prefs); - b = settings.by.resolve(b, state, prefs); - } - compare = internals.compare(a, b, aFirst, bFirst); - if (compare !== null) { - return compare; - } - const type = typeof a; - if (type !== typeof b) { - throw schema.$_createError("array.sort.mismatching", value, null, state, prefs); - } - if (type !== "number" && type !== "string") { - throw schema.$_createError("array.sort.unsupported", value, { type }, state, prefs); - } - if (type === "number") { - return (a - b) * order; - } - return a < b ? aFirst : bFirst; - }; - try { - return { value: value.slice().sort(sort) }; - } catch (err) { - return { errors: err }; + __incrementReservoir__(incr) { + return this.runScript("increment_reservoir", [incr]); } - }; - internals.compare = function(a, b, aFirst, bFirst) { - if (a === b) { - return 0; + __currentReservoir__() { + return this.runScript("current_reservoir", []); } - if (a === void 0) { - return 1; + __check__(weight) { + var _this6 = this; + return _asyncToGenerator2(function* () { + return _this6.convertBool(yield _this6.runScript("check", _this6.prepareArray([weight]))); + })(); } - if (b === void 0) { - return -1; + __register__(index, weight, expiration) { + var _this7 = this; + return _asyncToGenerator2(function* () { + var reservoir, success, wait; + var _ref4 = yield _this7.runScript("register", _this7.prepareArray([index, weight, expiration])); + var _ref5 = _slicedToArray2(_ref4, 3); + success = _ref5[0]; + wait = _ref5[1]; + reservoir = _ref5[2]; + return { + success: _this7.convertBool(success), + wait, + reservoir + }; + })(); } - if (a === null) { - return bFirst; + __submit__(queueLength, weight) { + var _this8 = this; + return _asyncToGenerator2(function* () { + var blocked, e2, maxConcurrent, overweight, reachedHWM, strategy; + try { + var _ref6 = yield _this8.runScript("submit", _this8.prepareArray([queueLength, weight])); + var _ref7 = _slicedToArray2(_ref6, 3); + reachedHWM = _ref7[0]; + blocked = _ref7[1]; + strategy = _ref7[2]; + return { + reachedHWM: _this8.convertBool(reachedHWM), + blocked: _this8.convertBool(blocked), + strategy + }; + } catch (error2) { + e2 = error2; + if (e2.message.indexOf("OVERWEIGHT") === 0) { + var _e$message$split = e2.message.split(":"); + var _e$message$split2 = _slicedToArray2(_e$message$split, 3); + overweight = _e$message$split2[0]; + weight = _e$message$split2[1]; + maxConcurrent = _e$message$split2[2]; + throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${maxConcurrent}`); + } else { + throw e2; + } + } + })(); } - if (b === null) { - return aFirst; + __free__(index, weight) { + var _this9 = this; + return _asyncToGenerator2(function* () { + var running; + running = yield _this9.runScript("free", _this9.prepareArray([index])); + return { + running + }; + })(); } - return null; }; + module14.exports = RedisDatastore; } }); -var require_boolean2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/boolean.js"(exports2, module14) { +var require_States = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/States.js"(exports2, module14) { "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var Values = require_values2(); - var internals = {}; - internals.isBool = function(value) { - return typeof value === "boolean"; - }; - module14.exports = Any.extend({ - type: "boolean", - flags: { - sensitive: { default: false } - }, - terms: { - falsy: { - init: null, - manifest: "values" - }, - truthy: { - init: null, - manifest: "values" - } - }, - coerce(value, { schema }) { - if (typeof value === "boolean") { - return; - } - if (typeof value === "string") { - const normalized = schema._flags.sensitive ? value : value.toLowerCase(); - value = normalized === "true" ? true : normalized === "false" ? false : value; - } - if (typeof value !== "boolean") { - value = schema.$_terms.truthy && schema.$_terms.truthy.has(value, null, null, !schema._flags.sensitive) || (schema.$_terms.falsy && schema.$_terms.falsy.has(value, null, null, !schema._flags.sensitive) ? false : value); - } - return { value }; - }, - validate(value, { error: error2 }) { - if (typeof value !== "boolean") { - return { value, errors: error2("boolean.base") }; - } - }, - rules: { - truthy: { - method(...values) { - Common.verifyFlat(values, "truthy"); - const obj = this.clone(); - obj.$_terms.truthy = obj.$_terms.truthy || new Values(); - for (let i2 = 0; i2 < values.length; ++i2) { - const value = values[i2]; - assert2(value !== void 0, "Cannot call truthy with undefined"); - obj.$_terms.truthy.add(value); - } - return obj; - } - }, - falsy: { - method(...values) { - Common.verifyFlat(values, "falsy"); - const obj = this.clone(); - obj.$_terms.falsy = obj.$_terms.falsy || new Values(); - for (let i2 = 0; i2 < values.length; ++i2) { - const value = values[i2]; - assert2(value !== void 0, "Cannot call falsy with undefined"); - obj.$_terms.falsy.add(value); - } - return obj; - } - }, - sensitive: { - method(enabled2 = true) { - return this.$_setFlag("sensitive", enabled2); - } - } - }, - cast: { - number: { - from: internals.isBool, - to(value, helpers) { - return value ? 1 : 0; - } - }, - string: { - from: internals.isBool, - to(value, helpers) { - return value ? "true" : "false"; - } - } - }, - manifest: { - build(obj, desc) { - if (desc.truthy) { - obj = obj.truthy(...desc.truthy); - } - if (desc.falsy) { - obj = obj.falsy(...desc.falsy); - } - return obj; - } - }, - messages: { - "boolean.base": "{{#label}} must be a boolean" + var BottleneckError; + var States; + BottleneckError = require_BottleneckError(); + States = class States { + constructor(status1) { + this.status = status1; + this._jobs = {}; + this.counts = this.status.map(function() { + return 0; + }); } - }); - } -}); -var require_date2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/date.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var Template = require_template2(); - var internals = {}; - internals.isDate = function(value) { - return value instanceof Date; - }; - module14.exports = Any.extend({ - type: "date", - coerce: { - from: ["number", "string"], - method(value, { schema }) { - return { value: internals.parse(value, schema._flags.format) || value }; - } - }, - validate(value, { schema, error: error2, prefs }) { - if (value instanceof Date && !isNaN(value.getTime())) { - return; - } - const format52 = schema._flags.format; - if (!prefs.convert || !format52 || typeof value !== "string") { - return { value, errors: error2("date.base") }; - } - return { value, errors: error2("date.format", { format: format52 }) }; - }, - rules: { - compare: { - method: false, - validate(value, helpers, { date: date3 }, { name, operator, args }) { - const to = date3 === "now" ? Date.now() : date3.getTime(); - if (Common.compare(value.getTime(), to, operator)) { - return value; - } - return helpers.error("date." + name, { limit: args.date, value }); - }, - args: [ - { - name: "date", - ref: true, - normalize: (date3) => { - return date3 === "now" ? date3 : internals.parse(date3); - }, - assert: (date3) => date3 !== null, - message: "must have a valid date format" - } - ] - }, - format: { - method(format52) { - assert2(["iso", "javascript", "unix"].includes(format52), "Unknown date format", format52); - return this.$_setFlag("format", format52); - } - }, - greater: { - method(date3) { - return this.$_addRule({ name: "greater", method: "compare", args: { date: date3 }, operator: ">" }); - } - }, - iso: { - method() { - return this.format("iso"); - } - }, - less: { - method(date3) { - return this.$_addRule({ name: "less", method: "compare", args: { date: date3 }, operator: "<" }); - } - }, - max: { - method(date3) { - return this.$_addRule({ name: "max", method: "compare", args: { date: date3 }, operator: "<=" }); - } - }, - min: { - method(date3) { - return this.$_addRule({ name: "min", method: "compare", args: { date: date3 }, operator: ">=" }); - } - }, - timestamp: { - method(type = "javascript") { - assert2(["javascript", "unix"].includes(type), '"type" must be one of "javascript, unix"'); - return this.format(type); - } - } - }, - cast: { - number: { - from: internals.isDate, - to(value, helpers) { - return value.getTime(); - } - }, - string: { - from: internals.isDate, - to(value, { prefs }) { - return Template.date(value, prefs); - } + next(id) { + var current, next; + current = this._jobs[id]; + next = current + 1; + if (current != null && next < this.status.length) { + this.counts[current]--; + this.counts[next]++; + return this._jobs[id]++; + } else if (current != null) { + this.counts[current]--; + return delete this._jobs[id]; } - }, - messages: { - "date.base": "{{#label}} must be a valid date", - "date.format": '{{#label}} must be in {msg("date.format." + #format) || #format} format', - "date.greater": "{{#label}} must be greater than {{:#limit}}", - "date.less": "{{#label}} must be less than {{:#limit}}", - "date.max": "{{#label}} must be less than or equal to {{:#limit}}", - "date.min": "{{#label}} must be greater than or equal to {{:#limit}}", - // Messages used in date.format - "date.format.iso": "ISO 8601 date", - "date.format.javascript": "timestamp or number of milliseconds", - "date.format.unix": "timestamp or number of seconds" - } - }); - internals.parse = function(value, format52) { - if (value instanceof Date) { - return value; - } - if (typeof value !== "string" && (isNaN(value) || !isFinite(value))) { - return null; } - if (/^\s*$/.test(value)) { - return null; + start(id) { + var initial; + initial = 0; + this._jobs[id] = initial; + return this.counts[initial]++; } - if (format52 === "iso") { - if (!Common.isIsoDate(value)) { - return null; + remove(id) { + var current; + current = this._jobs[id]; + if (current != null) { + this.counts[current]--; + delete this._jobs[id]; } - return internals.date(value.toString()); + return current != null; } - const original = value; - if (typeof value === "string" && /^[+-]?\d+(\.\d+)?$/.test(value)) { - value = parseFloat(value); + jobStatus(id) { + var ref; + return (ref = this.status[this._jobs[id]]) != null ? ref : null; } - if (format52) { - if (format52 === "javascript") { - return internals.date(1 * value); - } - if (format52 === "unix") { - return internals.date(1e3 * value); - } - if (typeof original === "string") { - return null; + statusJobs(status) { + var k, pos, ref, results, v2; + if (status != null) { + pos = this.status.indexOf(status); + if (pos < 0) { + throw new BottleneckError(`status must be one of ${this.status.join(", ")}`); + } + ref = this._jobs; + results = []; + for (k in ref) { + v2 = ref[k]; + if (v2 === pos) { + results.push(k); + } + } + return results; + } else { + return Object.keys(this._jobs); } } - return internals.date(value); - }; - internals.date = function(value) { - const date3 = new Date(value); - if (!isNaN(date3.getTime())) { - return date3; + statusCounts() { + return this.counts.reduce((acc, v2, i2) => { + acc[this.status[i2]] = v2; + return acc; + }, {}); } - return null; }; + module14.exports = States; } }); -var require_keys2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/keys.js"(exports2, module14) { +var require_Sync = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Sync.js"(exports2, module14) { "use strict"; - var { applyToDefaults, assert: assert2, clone: Clone } = require_lib(); - var Topo = require_lib8(); - var Any = require_any2(); - var Common = require_common3(); - var Compile = require_compile2(); - var Errors = require_errors3(); - var Ref = require_ref2(); - var Template = require_template2(); - var internals = { - renameDefaults: { - alias: false, - // Keep old value in place - multiple: false, - // Allow renaming multiple keys into the same target - override: false - // Overrides an existing key + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - }; - module14.exports = Any.extend({ - type: "_keys", - properties: { - typeof: "object" - }, - flags: { - unknown: { default: void 0 } - }, - terms: { - dependencies: { init: null }, - keys: { init: null, manifest: { mapped: { from: "schema", to: "key" } } }, - patterns: { init: null }, - renames: { init: null } - }, - args(schema, keys) { - return schema.keys(keys); - }, - validate(value, { schema, error: error2, state, prefs }) { - if (!value || typeof value !== schema.$_property("typeof") || Array.isArray(value)) { - return { value, errors: error2("object.base", { type: schema.$_property("typeof") }) }; - } - if (!schema.$_terms.renames && !schema.$_terms.dependencies && !schema.$_terms.keys && // null allows any keys - !schema.$_terms.patterns && !schema.$_terms.externals) { - return; - } - value = internals.clone(value, prefs); - const errors = []; - if (schema.$_terms.renames && !internals.rename(schema, value, state, prefs, errors)) { - return { value, errors }; - } - if (!schema.$_terms.keys && // null allows any keys - !schema.$_terms.patterns && !schema.$_terms.dependencies) { - return { value, errors }; - } - const unprocessed = new Set(Object.keys(value)); - if (schema.$_terms.keys) { - const ancestors = [value, ...state.ancestors]; - for (const child of schema.$_terms.keys) { - const key = child.key; - const item = value[key]; - unprocessed.delete(key); - const localState = state.localize([...state.path, key], ancestors, child); - const result = child.schema.$_validate(item, localState, prefs); - if (result.errors) { - if (prefs.abortEarly) { - return { value, errors: result.errors }; - } - if (result.value !== void 0) { - value[key] = result.value; - } - errors.push(...result.errors); - } else if (child.schema._flags.result === "strip" || result.value === void 0 && item !== void 0) { - delete value[key]; - } else if (result.value !== void 0) { - value[key] = result.value; - } - } - } - if (unprocessed.size || schema._flags._hasPatternMatch) { - const early = internals.unknown(schema, value, unprocessed, errors, state, prefs); - if (early) { - return early; - } - } - if (schema.$_terms.dependencies) { - for (const dep of schema.$_terms.dependencies) { - if (dep.key !== null && internals.isPresent(dep.options)(dep.key.resolve(value, state, prefs, null, { shadow: false })) === false) { - continue; - } - const failed = internals.dependencies[dep.rel](schema, dep, value, state, prefs); - if (failed) { - const report = schema.$_createError(failed.code, value, failed.context, state, prefs); - if (prefs.abortEarly) { - return { value, errors: report }; - } - errors.push(report); - } - } - } - return { value, errors }; - }, - rules: { - and: { - method(...peers) { - Common.verifyFlat(peers, "and"); - return internals.dependency(this, "and", null, peers); - } - }, - append: { - method(schema) { - if (schema === null || schema === void 0 || Object.keys(schema).length === 0) { - return this; - } - return this.keys(schema); - } - }, - assert: { - method(subject, schema, message) { - if (!Template.isTemplate(subject)) { - subject = Compile.ref(subject); - } - assert2(message === void 0 || typeof message === "string", "Message must be a string"); - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.$_addRule({ name: "assert", args: { subject, schema, message } }); - obj.$_mutateRegister(subject); - obj.$_mutateRegister(schema); - return obj; - }, - validate(value, { error: error2, prefs, state }, { subject, schema, message }) { - const about = subject.resolve(value, state, prefs); - const path8 = Ref.isRef(subject) ? subject.absolute(state) : []; - if (schema.$_match(about, state.localize(path8, [value, ...state.ancestors], schema), prefs)) { - return value; - } - return error2("object.assert", { subject, message }); - }, - args: ["subject", "schema", "message"], - multi: true - }, - instance: { - method(constructor, name) { - assert2(typeof constructor === "function", "constructor must be a function"); - name = name || constructor.name; - return this.$_addRule({ name: "instance", args: { constructor, name } }); - }, - validate(value, helpers, { constructor, name }) { - if (value instanceof constructor) { - return value; - } - return helpers.error("object.instance", { type: name, value }); - }, - args: ["constructor", "name"] - }, - keys: { - method(schema) { - assert2(schema === void 0 || typeof schema === "object", "Object schema must be a valid object"); - assert2(!Common.isSchema(schema), "Object schema cannot be a joi schema"); - const obj = this.clone(); - if (!schema) { - obj.$_terms.keys = null; - } else if (!Object.keys(schema).length) { - obj.$_terms.keys = new internals.Keys(); - } else { - obj.$_terms.keys = obj.$_terms.keys ? obj.$_terms.keys.filter((child) => !schema.hasOwnProperty(child.key)) : new internals.Keys(); - for (const key in schema) { - Common.tryWithPath(() => obj.$_terms.keys.push({ key, schema: this.$_compile(schema[key]) }), key); - } - } - return obj.$_mutateRebuild(); - } - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(Object.keys(value).length, limit, operator)) { - return value; - } - return helpers.error("object." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } - }, - nand: { - method(...peers) { - Common.verifyFlat(peers, "nand"); - return internals.dependency(this, "nand", null, peers); - } - }, - or: { - method(...peers) { - Common.verifyFlat(peers, "or"); - return internals.dependency(this, "or", null, peers); - } - }, - oxor: { - method(...peers) { - return internals.dependency(this, "oxor", null, peers); - } - }, - pattern: { - method(pattern, schema, options2 = {}) { - const isRegExp = pattern instanceof RegExp; - if (!isRegExp) { - pattern = this.$_compile(pattern, { appendPath: true }); - } - assert2(schema !== void 0, "Invalid rule"); - Common.assertOptions(options2, ["fallthrough", "matches"]); - if (isRegExp) { - assert2(!pattern.flags.includes("g") && !pattern.flags.includes("y"), "pattern should not use global or sticky mode"); - } - schema = this.$_compile(schema, { appendPath: true }); - const obj = this.clone(); - obj.$_terms.patterns = obj.$_terms.patterns || []; - const config2 = { [isRegExp ? "regex" : "schema"]: pattern, rule: schema }; - if (options2.matches) { - config2.matches = this.$_compile(options2.matches); - if (config2.matches.type !== "array") { - config2.matches = config2.matches.$_root.array().items(config2.matches); - } - obj.$_mutateRegister(config2.matches); - obj.$_setFlag("_hasPatternMatch", true, { clone: false }); - } - if (options2.fallthrough) { - config2.fallthrough = true; - } - obj.$_terms.patterns.push(config2); - obj.$_mutateRegister(schema); - return obj; - } - }, - ref: { - method() { - return this.$_addRule("ref"); - }, - validate(value, helpers) { - if (Ref.isRef(value)) { - return value; - } - return helpers.error("object.refType", { value }); - } - }, - regex: { - method() { - return this.$_addRule("regex"); - }, - validate(value, helpers) { - if (value instanceof RegExp) { - return value; - } - return helpers.error("object.regex", { value }); - } - }, - rename: { - method(from3, to, options2 = {}) { - assert2(typeof from3 === "string" || from3 instanceof RegExp, "Rename missing the from argument"); - assert2(typeof to === "string" || to instanceof Template, "Invalid rename to argument"); - assert2(to !== from3, "Cannot rename key to same name:", from3); - Common.assertOptions(options2, ["alias", "ignoreUndefined", "override", "multiple"]); - const obj = this.clone(); - obj.$_terms.renames = obj.$_terms.renames || []; - for (const rename of obj.$_terms.renames) { - assert2(rename.from !== from3, "Cannot rename the same key multiple times"); - } - if (to instanceof Template) { - obj.$_mutateRegister(to); - } - obj.$_terms.renames.push({ - from: from3, - to, - options: applyToDefaults(internals.renameDefaults, options2) - }); - return obj; - } - }, - schema: { - method(type = "any") { - return this.$_addRule({ name: "schema", args: { type } }); - }, - validate(value, helpers, { type }) { - if (Common.isSchema(value) && (type === "any" || value.type === type)) { - return value; - } - return helpers.error("object.schema", { type }); - } - }, - unknown: { - method(allow) { - return this.$_setFlag("unknown", allow !== false); - } - }, - with: { - method(key, peers, options2 = {}) { - return internals.dependency(this, "with", key, peers, options2); - } - }, - without: { - method(key, peers, options2 = {}) { - return internals.dependency(this, "without", key, peers, options2); - } - }, - xor: { - method(...peers) { - Common.verifyFlat(peers, "xor"); - return internals.dependency(this, "xor", null, peers); - } - } - }, - overrides: { - default(value, options2) { - if (value === void 0) { - value = Common.symbols.deepDefault; - } - return this.$_parent("default", value, options2); - }, - isAsync() { - if (this.$_terms.externals?.length) { - return true; + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - if (this.$_terms.keys?.length) { - for (const key of this.$_terms.keys) { - if (key.schema.isAsync()) { - return true; - } - } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } - if (this.$_terms.patterns?.length) { - for (const pattern of this.$_terms.patterns) { - if (pattern.rule.isAsync()) { - return true; + _next(void 0); + }); + }; + } + var DLList; + var Sync; + DLList = require_DLList(); + Sync = class Sync { + constructor(name, Promise2) { + this.schedule = this.schedule.bind(this); + this.name = name; + this.Promise = Promise2; + this._running = 0; + this._queue = new DLList(); + } + isEmpty() { + return this._queue.length === 0; + } + _tryToRun() { + var _this = this; + return _asyncToGenerator2(function* () { + var args, cb, error2, reject, resolve82, returned, task; + if (_this._running < 1 && _this._queue.length > 0) { + _this._running++; + var _this$_queue$shift = _this._queue.shift(); + task = _this$_queue$shift.task; + args = _this$_queue$shift.args; + resolve82 = _this$_queue$shift.resolve; + reject = _this$_queue$shift.reject; + cb = yield _asyncToGenerator2(function* () { + try { + returned = yield task(...args); + return function() { + return resolve82(returned); + }; + } catch (error1) { + error2 = error1; + return function() { + return reject(error2); + }; } - } - } - return false; - } - }, - rebuild(schema) { - if (schema.$_terms.keys) { - const topo = new Topo.Sorter(); - for (const child of schema.$_terms.keys) { - Common.tryWithPath(() => topo.add(child, { after: child.schema.$_rootReferences(), group: child.key }), child.key); - } - schema.$_terms.keys = new internals.Keys(...topo.nodes); - } - }, - manifest: { - build(obj, desc) { - if (desc.keys) { - obj = obj.keys(desc.keys); - } - if (desc.dependencies) { - for (const { rel, key = null, peers, options: options2 } of desc.dependencies) { - obj = internals.dependency(obj, rel, key, peers, options2); - } - } - if (desc.patterns) { - for (const { regex, schema, rule, fallthrough, matches } of desc.patterns) { - obj = obj.pattern(regex || schema, rule, { fallthrough, matches }); - } - } - if (desc.renames) { - for (const { from: from3, to, options: options2 } of desc.renames) { - obj = obj.rename(from3, to, options2); - } + })(); + _this._running--; + _this._tryToRun(); + return cb(); } - return obj; - } - }, - messages: { - "object.and": "{{#label}} contains {{#presentWithLabels}} without its required peers {{#missingWithLabels}}", - "object.assert": '{{#label}} is invalid because {if(#subject.key, `"` + #subject.key + `" failed to ` + (#message || "pass the assertion test"), #message || "the assertion failed")}', - "object.base": "{{#label}} must be of type {{#type}}", - "object.instance": "{{#label}} must be an instance of {{:#type}}", - "object.length": '{{#label}} must have {{#limit}} key{if(#limit == 1, "", "s")}', - "object.max": '{{#label}} must have less than or equal to {{#limit}} key{if(#limit == 1, "", "s")}', - "object.min": '{{#label}} must have at least {{#limit}} key{if(#limit == 1, "", "s")}', - "object.missing": "{{#label}} must contain at least one of {{#peersWithLabels}}", - "object.nand": "{{:#mainWithLabel}} must not exist simultaneously with {{#peersWithLabels}}", - "object.oxor": "{{#label}} contains a conflict between optional exclusive peers {{#peersWithLabels}}", - "object.pattern.match": "{{#label}} keys failed to match pattern requirements", - "object.refType": "{{#label}} must be a Joi reference", - "object.regex": "{{#label}} must be a RegExp object", - "object.rename.multiple": "{{#label}} cannot rename {{:#from}} because multiple renames are disabled and another key was already renamed to {{:#to}}", - "object.rename.override": "{{#label}} cannot rename {{:#from}} because override is disabled and target {{:#to}} exists", - "object.schema": "{{#label}} must be a Joi schema of {{#type}} type", - "object.unknown": "{{#label}} is not allowed", - "object.with": "{{:#mainWithLabel}} missing required peer {{:#peerWithLabel}}", - "object.without": "{{:#mainWithLabel}} conflict with forbidden peer {{:#peerWithLabel}}", - "object.xor": "{{#label}} contains a conflict between exclusive peers {{#peersWithLabels}}" + })(); } - }); - internals.clone = function(value, prefs) { - if (typeof value === "object") { - if (prefs.nonEnumerables) { - return Clone(value, { shallow: true }); - } - const clone3 = Object.create(Object.getPrototypeOf(value)); - Object.assign(clone3, value); - return clone3; + schedule(task, ...args) { + var promise, reject, resolve82; + resolve82 = reject = null; + promise = new this.Promise(function(_resolve, _reject) { + resolve82 = _resolve; + return reject = _reject; + }); + this._queue.push({ + task, + args, + resolve: resolve82, + reject + }); + this._tryToRun(); + return promise; } - const clone2 = function(...args) { - return value.apply(this, args); - }; - clone2.prototype = Clone(value.prototype); - Object.defineProperty(clone2, "name", { value: value.name, writable: false }); - Object.defineProperty(clone2, "length", { value: value.length, writable: false }); - Object.assign(clone2, value); - return clone2; - }; - internals.dependency = function(schema, rel, key, peers, options2) { - assert2(key === null || typeof key === "string", rel, "key must be a strings"); - if (!options2) { - options2 = peers.length > 1 && typeof peers[peers.length - 1] === "object" ? peers.pop() : {}; - } - Common.assertOptions(options2, ["separator", "isPresent"]); - peers = [].concat(peers); - const separator = Common.default(options2.separator, "."); - const paths = []; - for (const peer of peers) { - assert2(typeof peer === "string", rel, "peers must be strings"); - paths.push(Compile.ref(peer, { separator, ancestor: 0, prefix: false })); - } - if (key !== null) { - key = Compile.ref(key, { separator, ancestor: 0, prefix: false }); - } - const obj = schema.clone(); - obj.$_terms.dependencies = obj.$_terms.dependencies || []; - obj.$_terms.dependencies.push(new internals.Dependency(rel, key, paths, peers, options2)); - return obj; }; - internals.dependencies = { - and(schema, dep, value, state, prefs) { - const missing = []; - const present = []; - const count = dep.peers.length; - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false })) === false) { - missing.push(peer.key); - } else { - present.push(peer.key); - } - } - if (missing.length !== count && present.length !== count) { - return { - code: "object.and", - context: { - present, - presentWithLabels: internals.keysToLabels(schema, present), - missing, - missingWithLabels: internals.keysToLabels(schema, missing) - } - }; - } - }, - nand(schema, dep, value, state, prefs) { - const present = []; - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false }))) { - present.push(peer.key); - } - } - if (present.length !== dep.peers.length) { - return; - } - const main = dep.paths[0]; - const values = dep.paths.slice(1); - return { - code: "object.nand", - context: { - main, - mainWithLabel: internals.keysToLabels(schema, main), - peers: values, - peersWithLabels: internals.keysToLabels(schema, values) - } - }; - }, - or(schema, dep, value, state, prefs) { - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false }))) { - return; - } - } - return { - code: "object.missing", - context: { - peers: dep.paths, - peersWithLabels: internals.keysToLabels(schema, dep.paths) - } - }; - }, - oxor(schema, dep, value, state, prefs) { - const present = []; - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false }))) { - present.push(peer.key); - } - } - if (!present.length || present.length === 1) { - return; - } - const context = { peers: dep.paths, peersWithLabels: internals.keysToLabels(schema, dep.paths) }; - context.present = present; - context.presentWithLabels = internals.keysToLabels(schema, present); - return { code: "object.oxor", context }; - }, - with(schema, dep, value, state, prefs) { - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false })) === false) { - return { - code: "object.with", - context: { - main: dep.key.key, - mainWithLabel: internals.keysToLabels(schema, dep.key.key), - peer: peer.key, - peerWithLabel: internals.keysToLabels(schema, peer.key) - } - }; - } - } - }, - without(schema, dep, value, state, prefs) { - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false }))) { - return { - code: "object.without", - context: { - main: dep.key.key, - mainWithLabel: internals.keysToLabels(schema, dep.key.key), - peer: peer.key, - peerWithLabel: internals.keysToLabels(schema, peer.key) - } - }; - } - } - }, - xor(schema, dep, value, state, prefs) { - const present = []; - const isPresent = internals.isPresent(dep.options); - for (const peer of dep.peers) { - if (isPresent(peer.resolve(value, state, prefs, null, { shadow: false }))) { - present.push(peer.key); - } - } - if (present.length === 1) { - return; + module14.exports = Sync; + } +}); +var require_version = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/version.json"(exports2, module14) { + module14.exports = { version: "2.19.5" }; + } +}); +var require_Group = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Group.js"(exports2, module14) { + "use strict"; + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + } + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; } - const context = { peers: dep.paths, peersWithLabels: internals.keysToLabels(schema, dep.paths) }; - if (present.length === 0) { - return { code: "object.missing", context }; + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } - context.present = present; - context.presentWithLabels = internals.keysToLabels(schema, present); - return { code: "object.xor", context }; } - }; - internals.keysToLabels = function(schema, keys) { - if (Array.isArray(keys)) { - return keys.map((key) => schema.$_mapLabels(key)); + return _arr; + } + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - return schema.$_mapLabels(keys); - }; - internals.isPresent = function(options2) { - return typeof options2.isPresent === "function" ? options2.isPresent : (resolved) => resolved !== void 0; - }; - internals.rename = function(schema, value, state, prefs, errors) { - const renamed = {}; - for (const rename of schema.$_terms.renames) { - const matches = []; - const pattern = typeof rename.from !== "string"; - if (!pattern) { - if (Object.prototype.hasOwnProperty.call(value, rename.from) && (value[rename.from] !== void 0 || !rename.options.ignoreUndefined)) { - matches.push(rename); + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - } else { - for (const from3 in value) { - if (value[from3] === void 0 && rename.options.ignoreUndefined) { - continue; - } - if (from3 === rename.to) { - continue; - } - const match = rename.from.exec(from3); - if (!match) { - continue; + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; + } + var Events2; + var Group; + var IORedisConnection2; + var RedisConnection2; + var Scripts2; + var parser3; + parser3 = require_parser2(); + Events2 = require_Events(); + RedisConnection2 = require_RedisConnection(); + IORedisConnection2 = require_IORedisConnection(); + Scripts2 = require_Scripts(); + Group = function() { + class Group2 { + constructor(limiterOptions = {}) { + this.deleteKey = this.deleteKey.bind(this); + this.limiterOptions = limiterOptions; + parser3.load(this.limiterOptions, this.defaults, this); + this.Events = new Events2(this); + this.instances = {}; + this.Bottleneck = require_Bottleneck(); + this._startAutoCleanup(); + this.sharedConnection = this.connection != null; + if (this.connection == null) { + if (this.limiterOptions.datastore === "redis") { + this.connection = new RedisConnection2(Object.assign({}, this.limiterOptions, { + Events: this.Events + })); + } else if (this.limiterOptions.datastore === "ioredis") { + this.connection = new IORedisConnection2(Object.assign({}, this.limiterOptions, { + Events: this.Events + })); } - matches.push({ from: from3, to: rename.to, match }); } } - for (const match of matches) { - const from3 = match.from; - let to = match.to; - if (to instanceof Template) { - to = to.render(value, state, prefs, match.match); - } - if (from3 === to) { - continue; - } - if (!rename.options.multiple && renamed[to]) { - errors.push(schema.$_createError("object.rename.multiple", value, { from: from3, to, pattern }, state, prefs)); - if (prefs.abortEarly) { - return false; + key(key = "") { + var ref; + return (ref = this.instances[key]) != null ? ref : (() => { + var limiter; + limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { + id: `${this.id}-${key}`, + timeout: this.timeout, + connection: this.connection + })); + this.Events.trigger("created", limiter, key); + return limiter; + })(); + } + deleteKey(key = "") { + var _this = this; + return _asyncToGenerator2(function* () { + var deleted, instance; + instance = _this.instances[key]; + if (_this.connection) { + deleted = yield _this.connection.__runCommand__(["del", ...Scripts2.allKeys(`${_this.id}-${key}`)]); } - } - if (Object.prototype.hasOwnProperty.call(value, to) && !rename.options.override && !renamed[to]) { - errors.push(schema.$_createError("object.rename.override", value, { from: from3, to, pattern }, state, prefs)); - if (prefs.abortEarly) { - return false; + if (instance != null) { + delete _this.instances[key]; + yield instance.disconnect(); } - } - if (value[from3] === void 0) { - delete value[to]; - } else { - value[to] = value[from3]; - } - renamed[to] = true; - if (!rename.options.alias) { - delete value[from3]; - } + return instance != null || deleted > 0; + })(); } - } - return true; - }; - internals.unknown = function(schema, value, unprocessed, errors, state, prefs) { - if (schema.$_terms.patterns) { - let hasMatches = false; - const matches = schema.$_terms.patterns.map((pattern) => { - if (pattern.matches) { - hasMatches = true; - return []; + limiters() { + var k, ref, results, v2; + ref = this.instances; + results = []; + for (k in ref) { + v2 = ref[k]; + results.push({ + key: k, + limiter: v2 + }); } - }); - const ancestors = [value, ...state.ancestors]; - for (const key of unprocessed) { - const item = value[key]; - const path8 = [...state.path, key]; - for (let i2 = 0; i2 < schema.$_terms.patterns.length; ++i2) { - const pattern = schema.$_terms.patterns[i2]; - if (pattern.regex) { - const match = pattern.regex.test(key); - state.mainstay.tracer.debug(state, "rule", `pattern.${i2}`, match ? "pass" : "error"); - if (!match) { - continue; - } - } else { - if (!pattern.schema.$_match(key, state.nest(pattern.schema, `pattern.${i2}`), prefs)) { - continue; - } + return results; + } + keys() { + return Object.keys(this.instances); + } + clusterKeys() { + var _this2 = this; + return _asyncToGenerator2(function* () { + var cursor, end, found, i2, k, keys, len, next, start; + if (_this2.connection == null) { + return _this2.Promise.resolve(_this2.keys()); } - unprocessed.delete(key); - const localState = state.localize(path8, ancestors, { schema: pattern.rule, key }); - const result = pattern.rule.$_validate(item, localState, prefs); - if (result.errors) { - if (prefs.abortEarly) { - return { value, errors: result.errors }; + keys = []; + cursor = null; + start = `b_${_this2.id}-`.length; + end = "_settings".length; + while (cursor !== 0) { + var _ref = yield _this2.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${_this2.id}-*_settings`, "count", 1e4]); + var _ref2 = _slicedToArray2(_ref, 2); + next = _ref2[0]; + found = _ref2[1]; + cursor = ~~next; + for (i2 = 0, len = found.length; i2 < len; i2++) { + k = found[i2]; + keys.push(k.slice(start, -end)); } - errors.push(...result.errors); } - if (pattern.matches) { - matches[i2].push(key); - } - value[key] = result.value; - if (!pattern.fallthrough) { - break; - } - } + return keys; + })(); } - if (hasMatches) { - for (let i2 = 0; i2 < matches.length; ++i2) { - const match = matches[i2]; - if (!match) { - continue; - } - const stpm = schema.$_terms.patterns[i2].matches; - const localState = state.localize(state.path, ancestors, stpm); - const result = stpm.$_validate(match, localState, prefs); - if (result.errors) { - const details = Errors.details(result.errors, { override: false }); - details.matches = match; - const report = schema.$_createError("object.pattern.match", value, details, state, prefs); - if (prefs.abortEarly) { - return { value, errors: report }; + _startAutoCleanup() { + var _this3 = this; + var base2; + clearInterval(this.interval); + return typeof (base2 = this.interval = setInterval( + /* @__PURE__ */ _asyncToGenerator2(function* () { + var e2, k, ref, results, time3, v2; + time3 = Date.now(); + ref = _this3.instances; + results = []; + for (k in ref) { + v2 = ref[k]; + try { + if (yield v2._store.__groupCheck__(time3)) { + results.push(_this3.deleteKey(k)); + } else { + results.push(void 0); + } + } catch (error2) { + e2 = error2; + results.push(v2.Events.trigger("error", e2)); + } } - errors.push(report); - } - } + return results; + }), + this.timeout / 2 + )).unref === "function" ? base2.unref() : void 0; } - } - if (!unprocessed.size || !schema.$_terms.keys && !schema.$_terms.patterns) { - return; - } - if (prefs.stripUnknown && typeof schema._flags.unknown === "undefined" || prefs.skipFunctions) { - const stripUnknown = prefs.stripUnknown ? prefs.stripUnknown === true ? true : !!prefs.stripUnknown.objects : false; - for (const key of unprocessed) { - if (stripUnknown) { - delete value[key]; - unprocessed.delete(key); - } else if (typeof value[key] === "function") { - unprocessed.delete(key); + updateSettings(options2 = {}) { + parser3.overwrite(options2, this.defaults, this); + parser3.overwrite(options2, options2, this.limiterOptions); + if (options2.timeout != null) { + return this._startAutoCleanup(); } } - } - const forbidUnknown = !Common.default(schema._flags.unknown, prefs.allowUnknown); - if (forbidUnknown) { - for (const unprocessedKey of unprocessed) { - const localState = state.localize([...state.path, unprocessedKey], []); - const report = schema.$_createError("object.unknown", value[unprocessedKey], { child: unprocessedKey }, localState, prefs, { flags: false }); - if (prefs.abortEarly) { - return { value, errors: report }; + disconnect(flush = true) { + var ref; + if (!this.sharedConnection) { + return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; } - errors.push(report); } } - }; - internals.Dependency = class { - constructor(rel, key, peers, paths, options2) { - this.rel = rel; - this.key = key; - this.peers = peers; - this.paths = paths; - this.options = options2; - } - describe() { - const desc = { - rel: this.rel, - peers: this.paths - }; - if (this.key !== null) { - desc.key = this.key.key; - } - if (this.peers[0].separator !== ".") { - desc.options = { ...desc.options, separator: this.peers[0].separator }; + ; + Group2.prototype.defaults = { + timeout: 1e3 * 60 * 5, + connection: null, + Promise, + id: "group-key" + }; + return Group2; + }.call(void 0); + module14.exports = Group; + } +}); +var require_Batcher = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Batcher.js"(exports2, module14) { + "use strict"; + var Batcher; + var Events2; + var parser3; + parser3 = require_parser2(); + Events2 = require_Events(); + Batcher = function() { + class Batcher2 { + constructor(options2 = {}) { + this.options = options2; + parser3.load(this.options, this.defaults, this); + this.Events = new Events2(this); + this._arr = []; + this._resetPromise(); + this._lastFlush = Date.now(); } - if (this.options.isPresent) { - desc.options = { ...desc.options, isPresent: this.options.isPresent }; + _resetPromise() { + return this._promise = new this.Promise((res, rej) => { + return this._resolve = res; + }); } - return desc; - } - }; - internals.Keys = class extends Array { - concat(source) { - const result = this.slice(); - const keys = /* @__PURE__ */ new Map(); - for (let i2 = 0; i2 < result.length; ++i2) { - keys.set(result[i2].key, i2); + _flush() { + clearTimeout(this._timeout); + this._lastFlush = Date.now(); + this._resolve(); + this.Events.trigger("batch", this._arr); + this._arr = []; + return this._resetPromise(); } - for (const item of source) { - const key = item.key; - const pos = keys.get(key); - if (pos !== void 0) { - result[pos] = { key, schema: result[pos].schema.concat(item.schema) }; - } else { - result.push(item); + add(data) { + var ret; + this._arr.push(data); + ret = this._promise; + if (this._arr.length === this.maxSize) { + this._flush(); + } else if (this.maxTime != null && this._arr.length === 1) { + this._timeout = setTimeout(() => { + return this._flush(); + }, this.maxTime); } + return ret; } - return result; } - }; + ; + Batcher2.prototype.defaults = { + maxTime: null, + maxSize: null, + Promise + }; + return Batcher2; + }.call(void 0); + module14.exports = Batcher; } }); -var require_function2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/function.js"(exports2, module14) { +var require_Bottleneck = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Bottleneck.js"(exports2, module14) { "use strict"; - var { assert: assert2 } = require_lib(); - var Keys = require_keys2(); - module14.exports = Keys.extend({ - type: "function", - properties: { - typeof: "function" - }, - rules: { - arity: { - method(n) { - assert2(Number.isSafeInteger(n) && n >= 0, "n must be a positive integer"); - return this.$_addRule({ name: "arity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length === n) { - return value; - } - return helpers.error("function.arity", { n }); - } - }, - class: { - method() { - return this.$_addRule("class"); - }, - validate(value, helpers) { - if (/^\s*class\s/.test(value.toString())) { - return value; - } - return helpers.error("function.class", { value }); - } - }, - minArity: { - method(n) { - assert2(Number.isSafeInteger(n) && n > 0, "n must be a strict positive integer"); - return this.$_addRule({ name: "minArity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length >= n) { - return value; - } - return helpers.error("function.minArity", { n }); - } - }, - maxArity: { - method(n) { - assert2(Number.isSafeInteger(n) && n >= 0, "n must be a positive integer"); - return this.$_addRule({ name: "maxArity", args: { n } }); - }, - validate(value, helpers, { n }) { - if (value.length <= n) { - return value; - } - return helpers.error("function.maxArity", { n }); - } - } - }, - messages: { - "function.arity": "{{#label}} must have an arity of {{#n}}", - "function.class": "{{#label}} must be a class", - "function.maxArity": "{{#label}} must have an arity lesser or equal to {{#n}}", - "function.minArity": "{{#label}} must have an arity greater or equal to {{#n}}" - } - }); - } -}); -var require_link2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/link.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var Compile = require_compile2(); - var Errors = require_errors3(); - var internals = {}; - module14.exports = Any.extend({ - type: "link", - properties: { - schemaChain: true - }, - terms: { - link: { init: null, manifest: "single", register: false } - }, - args(schema, ref) { - return schema.ref(ref); - }, - validate(value, { schema, state, prefs }) { - assert2(schema.$_terms.link, "Uninitialized link schema"); - const linked = internals.generate(schema, value, state, prefs); - const ref = schema.$_terms.link[0].ref; - return linked.$_validate(value, state.nest(linked, `link:${ref.display}:${linked.type}`), prefs); - }, - generate(schema, value, state, prefs) { - return internals.generate(schema, value, state, prefs); - }, - rules: { - ref: { - method(ref) { - assert2(!this.$_terms.link, "Cannot reinitialize schema"); - ref = Compile.ref(ref); - assert2(ref.type === "value" || ref.type === "local", "Invalid reference type:", ref.type); - assert2(ref.type === "local" || ref.ancestor === "root" || ref.ancestor > 0, "Link cannot reference itself"); - const obj = this.clone(); - obj.$_terms.link = [{ ref }]; - return obj; - } - }, - relative: { - method(enabled2 = true) { - return this.$_setFlag("relative", enabled2); - } - } - }, - overrides: { - concat(source) { - assert2(this.$_terms.link, "Uninitialized link schema"); - assert2(Common.isSchema(source), "Invalid schema object"); - assert2(source.type !== "link", "Cannot merge type link with another link"); - const obj = this.clone(); - if (!obj.$_terms.whens) { - obj.$_terms.whens = []; - } - obj.$_terms.whens.push({ concat: source }); - return obj.$_mutateRebuild(); + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + } + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; } - }, - manifest: { - build(obj, desc) { - assert2(desc.link, "Invalid link description missing link"); - return obj.ref(desc.link); + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } } - }); - internals.generate = function(schema, value, state, prefs) { - let linked = state.mainstay.links.get(schema); - if (linked) { - return linked._generate(value, state, prefs).schema; - } - const ref = schema.$_terms.link[0].ref; - const { perspective, path: path8 } = internals.perspective(ref, state); - internals.assert(perspective, "which is outside of schema boundaries", ref, schema, state, prefs); + return _arr; + } + function _toArray(arr) { + return _arrayWithHoles2(arr) || _iterableToArray(arr) || _nonIterableRest2(); + } + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); + } + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { try { - linked = path8.length ? perspective.$_reach(path8) : perspective; - } catch { - internals.assert(false, "to non-existing schema", ref, schema, state, prefs); - } - internals.assert(linked.type !== "link", "which is another link", ref, schema, state, prefs); - if (!schema._flags.relative) { - state.mainstay.links.set(schema, linked); - } - return linked._generate(value, state, prefs).schema; - }; - internals.perspective = function(ref, state) { - if (ref.type === "local") { - for (const { schema, key } of state.schemas) { - const id = schema._flags.id || key; - if (id === ref.path[0]) { - return { perspective: schema, path: ref.path.slice(1) }; - } - if (schema.$_terms.shared) { - for (const shared of schema.$_terms.shared) { - if (shared._flags.id === ref.path[0]) { - return { perspective: shared, path: ref.path.slice(1) }; - } - } - } - } - return { perspective: null, path: null }; - } - if (ref.ancestor === "root") { - return { perspective: state.schemas[state.schemas.length - 1].schema, path: ref.path }; - } - return { perspective: state.schemas[ref.ancestor] && state.schemas[ref.ancestor].schema, path: ref.path }; - }; - internals.assert = function(condition, message, ref, schema, state, prefs) { - if (condition) { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); return; } - assert2(false, `"${Errors.label(schema._flags, state, prefs)}" contains link reference "${ref.display}" ${message}`); - }; - } -}); -var require_number2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/number.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - var internals = { - numberRx: /^\s*[+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e([+-]?\d+))?\s*$/i, - precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/, - exponentialPartRegex: /[eE][+-]?\d+$/, - leadingSignAndZerosRegex: /^[+-]?(0*)?/, - dotRegex: /\./, - trailingZerosRegex: /0+$/, - decimalPlaces(value) { - const str = value.toString(); - const dindex = str.indexOf("."); - const eindex = str.indexOf("e"); - return (dindex < 0 ? 0 : (eindex < 0 ? str.length : eindex) - dindex - 1) + (eindex < 0 ? 0 : Math.max(0, -parseInt(str.slice(eindex + 1)))); + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - }; - module14.exports = Any.extend({ - type: "number", - flags: { - unsafe: { default: false } - }, - coerce: { - from: "string", - method(value, { schema, error: error2 }) { - const matches = value.match(internals.numberRx); - if (!matches) { - return; + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - value = value.trim(); - const result = { value: parseFloat(value) }; - if (result.value === 0) { - result.value = 0; + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } - if (!schema._flags.unsafe) { - if (value.match(/e/i)) { - if (internals.extractSignificantDigits(value) !== internals.extractSignificantDigits(String(result.value))) { - result.errors = error2("number.unsafe"); - return result; - } + _next(void 0); + }); + }; + } + var Bottleneck2; + var DEFAULT_PRIORITY; + var Events2; + var Job; + var LocalDatastore; + var NUM_PRIORITIES; + var Queues; + var RedisDatastore; + var States; + var Sync; + var parser3; + var splice = [].splice; + NUM_PRIORITIES = 10; + DEFAULT_PRIORITY = 5; + parser3 = require_parser2(); + Queues = require_Queues(); + Job = require_Job(); + LocalDatastore = require_LocalDatastore(); + RedisDatastore = require_RedisDatastore(); + Events2 = require_Events(); + States = require_States(); + Sync = require_Sync(); + Bottleneck2 = function() { + class Bottleneck3 { + constructor(options2 = {}, ...invalid) { + var storeInstanceOptions, storeOptions; + this._addToQueue = this._addToQueue.bind(this); + this._validateOptions(options2, invalid); + parser3.load(options2, this.instanceDefaults, this); + this._queues = new Queues(NUM_PRIORITIES); + this._scheduled = {}; + this._states = new States(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); + this._limiter = null; + this.Events = new Events2(this); + this._submitLock = new Sync("submit", this.Promise); + this._registerLock = new Sync("register", this.Promise); + storeOptions = parser3.load(options2, this.storeDefaults, {}); + this._store = function() { + if (this.datastore === "redis" || this.datastore === "ioredis" || this.connection != null) { + storeInstanceOptions = parser3.load(options2, this.redisStoreDefaults, {}); + return new RedisDatastore(this, storeOptions, storeInstanceOptions); + } else if (this.datastore === "local") { + storeInstanceOptions = parser3.load(options2, this.localStoreDefaults, {}); + return new LocalDatastore(this, storeOptions, storeInstanceOptions); } else { - const string3 = result.value.toString(); - if (string3.match(/e/i)) { - return result; - } - if (string3 !== internals.normalizeDecimal(value)) { - result.errors = error2("number.unsafe"); - return result; - } - } - } - return result; - } - }, - validate(value, { schema, error: error2, prefs }) { - if (value === Infinity || value === -Infinity) { - return { value, errors: error2("number.infinity") }; - } - if (!Common.isNumber(value)) { - return { value, errors: error2("number.base") }; - } - const result = { value }; - if (prefs.convert) { - const rule = schema.$_getRule("precision"); - if (rule) { - const precision = Math.pow(10, rule.args.limit); - result.value = Math.round(result.value * precision) / precision; - } - } - if (result.value === 0) { - result.value = 0; - } - if (!schema._flags.unsafe && (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER)) { - result.errors = error2("number.unsafe"); - } - return result; - }, - rules: { - compare: { - method: false, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value, limit, operator)) { - return value; - } - return helpers.error("number." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.isNumber, - message: "must be a number" - } - ] - }, - greater: { - method(limit) { - return this.$_addRule({ name: "greater", method: "compare", args: { limit }, operator: ">" }); - } - }, - integer: { - method() { - return this.$_addRule("integer"); - }, - validate(value, helpers) { - if (Math.trunc(value) - value === 0) { - return value; - } - return helpers.error("number.integer"); - } - }, - less: { - method(limit) { - return this.$_addRule({ name: "less", method: "compare", args: { limit }, operator: "<" }); - } - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "compare", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "compare", args: { limit }, operator: ">=" }); - } - }, - multiple: { - method(base2) { - const baseDecimalPlace = typeof base2 === "number" ? internals.decimalPlaces(base2) : null; - const pfactor = Math.pow(10, baseDecimalPlace); - return this.$_addRule({ - name: "multiple", - args: { - base: base2, - baseDecimalPlace, - pfactor - } - }); - }, - validate(value, helpers, { base: base2, baseDecimalPlace, pfactor }, options2) { - const valueDecimalPlace = internals.decimalPlaces(value); - if (valueDecimalPlace > baseDecimalPlace) { - return helpers.error("number.multiple", { multiple: options2.args.base, value }); - } - return Math.round(pfactor * value) % Math.round(pfactor * base2) === 0 ? value : helpers.error("number.multiple", { multiple: options2.args.base, value }); - }, - args: [ - { - name: "base", - ref: true, - assert: (value) => typeof value === "number" && isFinite(value) && value > 0, - message: "must be a positive number" - }, - "baseDecimalPlace", - "pfactor" - ], - multi: true - }, - negative: { - method() { - return this.sign("negative"); - } - }, - port: { - method() { - return this.$_addRule("port"); - }, - validate(value, helpers) { - if (Number.isSafeInteger(value) && value >= 0 && value <= 65535) { - return value; - } - return helpers.error("number.port"); - } - }, - positive: { - method() { - return this.sign("positive"); - } - }, - precision: { - method(limit) { - assert2(Number.isSafeInteger(limit), "limit must be an integer"); - return this.$_addRule({ name: "precision", args: { limit } }); - }, - validate(value, helpers, { limit }) { - const places = value.toString().match(internals.precisionRx); - const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0); - if (decimals <= limit) { - return value; - } - return helpers.error("number.precision", { limit, value }); - }, - convert: true - }, - sign: { - method(sign2) { - assert2(["negative", "positive"].includes(sign2), "Invalid sign", sign2); - return this.$_addRule({ name: "sign", args: { sign: sign2 } }); - }, - validate(value, helpers, { sign: sign2 }) { - if (sign2 === "negative" && value < 0 || sign2 === "positive" && value > 0) { - return value; + throw new Bottleneck3.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); } - return helpers.error(`number.${sign2}`); - } - }, - unsafe: { - method(enabled2 = true) { - assert2(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_setFlag("unsafe", enabled2); - } - } - }, - cast: { - string: { - from: (value) => typeof value === "number", - to(value, helpers) { - return value.toString(); - } + }.call(this); + this._queues.on("leftzero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.ref === "function" ? ref.ref() : void 0 : void 0; + }); + this._queues.on("zero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.unref === "function" ? ref.unref() : void 0 : void 0; + }); } - }, - messages: { - "number.base": "{{#label}} must be a number", - "number.greater": "{{#label}} must be greater than {{#limit}}", - "number.infinity": "{{#label}} cannot be infinity", - "number.integer": "{{#label}} must be an integer", - "number.less": "{{#label}} must be less than {{#limit}}", - "number.max": "{{#label}} must be less than or equal to {{#limit}}", - "number.min": "{{#label}} must be greater than or equal to {{#limit}}", - "number.multiple": "{{#label}} must be a multiple of {{#multiple}}", - "number.negative": "{{#label}} must be a negative number", - "number.port": "{{#label}} must be a valid port", - "number.positive": "{{#label}} must be a positive number", - "number.precision": "{{#label}} must have no more than {{#limit}} decimal places", - "number.unsafe": "{{#label}} must be a safe number" - } - }); - internals.extractSignificantDigits = function(value) { - return value.replace(internals.exponentialPartRegex, "").replace(internals.dotRegex, "").replace(internals.trailingZerosRegex, "").replace(internals.leadingSignAndZerosRegex, ""); - }; - internals.normalizeDecimal = function(str) { - str = str.replace(/^\+/, "").replace(/\.0*$/, "").replace(/^(-?)\.([^\.]*)$/, "$10.$2").replace(/^(-?)0+([0-9])/, "$1$2"); - if (str.includes(".") && str.endsWith("0")) { - str = str.replace(/0+$/, ""); - } - if (str === "-0") { - return "0"; - } - return str; - }; - } -}); -var require_object2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/object.js"(exports2, module14) { - "use strict"; - var Keys = require_keys2(); - module14.exports = Keys.extend({ - type: "object", - cast: { - map: { - from: (value) => value && typeof value === "object", - to(value, helpers) { - return new Map(Object.entries(value)); + _validateOptions(options2, invalid) { + if (!(options2 != null && typeof options2 === "object" && invalid.length === 0)) { + throw new Bottleneck3.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); } } - } - }); - } -}); -var require_errors4 = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/errors.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.errorCode = exports2.errorCodes = void 0; - exports2.errorCodes = { - EMPTY_STRING: "Address must be a non-empty string", - FORBIDDEN_UNICODE: "Address contains forbidden Unicode characters", - MULTIPLE_AT_CHAR: "Address cannot contain more than one @ character", - MISSING_AT_CHAR: "Address must contain one @ character", - EMPTY_LOCAL: "Address local part cannot be empty", - ADDRESS_TOO_LONG: "Address too long", - LOCAL_TOO_LONG: "Address local part too long", - EMPTY_LOCAL_SEGMENT: "Address local part contains empty dot-separated segment", - INVALID_LOCAL_CHARS: "Address local part contains invalid character", - DOMAIN_NON_EMPTY_STRING: "Domain must be a non-empty string", - DOMAIN_TOO_LONG: "Domain too long", - DOMAIN_INVALID_UNICODE_CHARS: "Domain contains forbidden Unicode characters", - DOMAIN_INVALID_CHARS: "Domain contains invalid character", - DOMAIN_INVALID_TLDS_CHARS: "Domain contains invalid tld character", - DOMAIN_SEGMENTS_COUNT: "Domain lacks the minimum required number of segments", - DOMAIN_SEGMENTS_COUNT_MAX: "Domain contains too many segments", - DOMAIN_FORBIDDEN_TLDS: "Domain uses forbidden TLD", - DOMAIN_EMPTY_SEGMENT: "Domain contains empty dot-separated segment", - DOMAIN_LONG_SEGMENT: "Domain contains dot-separated segment that is too long" - }; - function errorCode(code2) { - return { code: code2, error: exports2.errorCodes[code2] }; - } - exports2.errorCode = errorCode; - } -}); -var require_domain = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/domain.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.validateDomainOptions = exports2.isDomainValid = exports2.analyzeDomain = void 0; - var Url = __require2("url"); - var errors_1 = require_errors4(); - var MIN_DOMAIN_SEGMENTS = 2; - var NON_ASCII_RX = /[^\x00-\x7f]/; - var DOMAIN_CONTROL_RX = /[\x00-\x20@\:\/\\#!\$&\'\(\)\*\+,;=\?]/; - var TLD_SEGMENT_RX = /^[a-zA-Z](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/; - var DOMAIN_SEGMENT_RX = /^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/; - var DOMAIN_UNDERSCORE_SEGMENT_RX = /^[a-zA-Z0-9_](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/; - var URL_IMPL = Url.URL || URL; - function isTldsAllow(tlds) { - return !!tlds.allow; - } - function analyzeDomain(domain, options2 = {}) { - if (!domain) { - return (0, errors_1.errorCode)("DOMAIN_NON_EMPTY_STRING"); - } - if (typeof domain !== "string") { - throw new Error("Invalid input: domain must be a string"); - } - if (domain.length > 256) { - return (0, errors_1.errorCode)("DOMAIN_TOO_LONG"); - } - const ascii = !NON_ASCII_RX.test(domain); - if (!ascii) { - if (options2.allowUnicode === false) { - return (0, errors_1.errorCode)("DOMAIN_INVALID_UNICODE_CHARS"); - } - domain = domain.normalize("NFC"); - } - if (DOMAIN_CONTROL_RX.test(domain)) { - return (0, errors_1.errorCode)("DOMAIN_INVALID_CHARS"); - } - domain = punycode(domain); - if (options2.allowFullyQualified && domain[domain.length - 1] === ".") { - domain = domain.slice(0, -1); - } - const minDomainSegments = options2.minDomainSegments || MIN_DOMAIN_SEGMENTS; - const segments = domain.split("."); - if (segments.length < minDomainSegments) { - return (0, errors_1.errorCode)("DOMAIN_SEGMENTS_COUNT"); - } - if (options2.maxDomainSegments) { - if (segments.length > options2.maxDomainSegments) { - return (0, errors_1.errorCode)("DOMAIN_SEGMENTS_COUNT_MAX"); - } - } - const tlds = options2.tlds; - if (tlds) { - const tld = segments[segments.length - 1].toLowerCase(); - if (isTldsAllow(tlds)) { - if (!tlds.allow.has(tld)) { - return (0, errors_1.errorCode)("DOMAIN_FORBIDDEN_TLDS"); - } - } else if (tlds.deny.has(tld)) { - return (0, errors_1.errorCode)("DOMAIN_FORBIDDEN_TLDS"); + ready() { + return this._store.ready; } - } - for (let i2 = 0; i2 < segments.length; ++i2) { - const segment = segments[i2]; - if (!segment.length) { - return (0, errors_1.errorCode)("DOMAIN_EMPTY_SEGMENT"); + clients() { + return this._store.clients; } - if (segment.length > 63) { - return (0, errors_1.errorCode)("DOMAIN_LONG_SEGMENT"); - } - if (i2 < segments.length - 1) { - if (options2.allowUnderscore) { - if (!DOMAIN_UNDERSCORE_SEGMENT_RX.test(segment)) { - return (0, errors_1.errorCode)("DOMAIN_INVALID_CHARS"); - } - } else { - if (!DOMAIN_SEGMENT_RX.test(segment)) { - return (0, errors_1.errorCode)("DOMAIN_INVALID_CHARS"); - } - } - } else { - if (!TLD_SEGMENT_RX.test(segment)) { - return (0, errors_1.errorCode)("DOMAIN_INVALID_TLDS_CHARS"); - } + channel() { + return `b_${this.id}`; } - } - return null; - } - exports2.analyzeDomain = analyzeDomain; - function isDomainValid(domain, options2) { - return !analyzeDomain(domain, options2); - } - exports2.isDomainValid = isDomainValid; - function punycode(domain) { - if (domain.includes("%")) { - domain = domain.replace(/%/g, "%25"); - } - try { - return new URL_IMPL(`http://${domain}`).host; - } catch (err) { - return domain; - } - } - function validateDomainOptions(options2) { - if (!options2) { - return; - } - if (typeof options2.tlds !== "object") { - throw new Error("Invalid options: tlds must be a boolean or an object"); - } - if (isTldsAllow(options2.tlds)) { - if (options2.tlds.allow instanceof Set === false) { - throw new Error("Invalid options: tlds.allow must be a Set object or true"); + channel_client() { + return `b_${this.id}_${this._store.clientId}`; } - if (options2.tlds.deny) { - throw new Error("Invalid options: cannot specify both tlds.allow and tlds.deny lists"); + publish(message) { + return this._store.__publish__(message); } - } else { - if (options2.tlds.deny instanceof Set === false) { - throw new Error("Invalid options: tlds.deny must be a Set object"); + disconnect(flush = true) { + return this._store.__disconnect__(flush); } - } - } - exports2.validateDomainOptions = validateDomainOptions; - } -}); -var require_email = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/email.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.isEmailValid = exports2.analyzeEmail = void 0; - var Util = __require2("util"); - var domain_1 = require_domain(); - var errors_1 = require_errors4(); - var NON_ASCII_RX = /[^\x00-\x7f]/; - var ENCODER_IMPL = new (Util.TextEncoder || TextEncoder)(); - function analyzeEmail(email2, options2) { - return validateEmail(email2, options2); - } - exports2.analyzeEmail = analyzeEmail; - function isEmailValid(email2, options2) { - return !validateEmail(email2, options2); - } - exports2.isEmailValid = isEmailValid; - function validateEmail(email2, options2 = {}) { - if (typeof email2 !== "string") { - throw new Error("Invalid input: email must be a string"); - } - if (!email2) { - return (0, errors_1.errorCode)("EMPTY_STRING"); - } - const ascii = !NON_ASCII_RX.test(email2); - if (!ascii) { - if (options2.allowUnicode === false) { - return (0, errors_1.errorCode)("FORBIDDEN_UNICODE"); + chain(_limiter) { + this._limiter = _limiter; + return this; } - email2 = email2.normalize("NFC"); - } - const parts = email2.split("@"); - if (parts.length !== 2) { - return parts.length > 2 ? (0, errors_1.errorCode)("MULTIPLE_AT_CHAR") : (0, errors_1.errorCode)("MISSING_AT_CHAR"); - } - const [local, domain] = parts; - if (!local) { - return (0, errors_1.errorCode)("EMPTY_LOCAL"); - } - if (!options2.ignoreLength) { - if (email2.length > 254) { - return (0, errors_1.errorCode)("ADDRESS_TOO_LONG"); + queued(priority) { + return this._queues.queued(priority); } - if (ENCODER_IMPL.encode(local).length > 64) { - return (0, errors_1.errorCode)("LOCAL_TOO_LONG"); + clusterQueued() { + return this._store.__queued__(); } - } - return validateLocal(local, ascii) || (0, domain_1.analyzeDomain)(domain, options2); - } - function validateLocal(local, ascii) { - const segments = local.split("."); - for (const segment of segments) { - if (!segment.length) { - return (0, errors_1.errorCode)("EMPTY_LOCAL_SEGMENT"); + empty() { + return this.queued() === 0 && this._submitLock.isEmpty(); } - if (ascii) { - if (!ATEXT_RX.test(segment)) { - return (0, errors_1.errorCode)("INVALID_LOCAL_CHARS"); - } - continue; + running() { + return this._store.__running__(); } - for (const char of segment) { - if (ATEXT_RX.test(char)) { - continue; - } - const binary = toBinary(char); - if (!ATOM_RX.test(binary)) { - return (0, errors_1.errorCode)("INVALID_LOCAL_CHARS"); - } + done() { + return this._store.__done__(); } - } - return null; - } - function toBinary(char) { - return Array.from(ENCODER_IMPL.encode(char), (v2) => String.fromCharCode(v2)).join(""); - } - var ATEXT_RX = /^[\w!#\$%&'\*\+\-/=\?\^`\{\|\}~]+$/; - var ATOM_RX = new RegExp([ - // %xC2-DF UTF8-tail - "(?:[\\xc2-\\xdf][\\x80-\\xbf])", - // %xE0 %xA0-BF UTF8-tail %xE1-EC 2( UTF8-tail ) %xED %x80-9F UTF8-tail %xEE-EF 2( UTF8-tail ) - "(?:\\xe0[\\xa0-\\xbf][\\x80-\\xbf])|(?:[\\xe1-\\xec][\\x80-\\xbf]{2})|(?:\\xed[\\x80-\\x9f][\\x80-\\xbf])|(?:[\\xee-\\xef][\\x80-\\xbf]{2})", - // %xF0 %x90-BF 2( UTF8-tail ) %xF1-F3 3( UTF8-tail ) %xF4 %x80-8F 2( UTF8-tail ) - "(?:\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2})|(?:[\\xf1-\\xf3][\\x80-\\xbf]{3})|(?:\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})" - ].join("|")); - } -}); -var require_uri = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/uri.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.uriRegex = exports2.ipVersions = void 0; - var hoek_1 = require_lib(); - function generate() { - const rfc39862 = {}; - const hexDigit = "\\dA-Fa-f"; - const hexDigitOnly = "[" + hexDigit + "]"; - const unreserved = "\\w-\\.~"; - const subDelims = "!\\$&'\\(\\)\\*\\+,;="; - const pctEncoded = "%" + hexDigit; - const pchar = unreserved + pctEncoded + subDelims + ":@"; - const pcharOnly = "[" + pchar + "]"; - const decOctect = "(?:0{0,2}\\d|0?[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])"; - rfc39862.ipv4address = "(?:" + decOctect + "\\.){3}" + decOctect; - const h16 = hexDigitOnly + "{1,4}"; - const ls32 = "(?:" + h16 + ":" + h16 + "|" + rfc39862.ipv4address + ")"; - const IPv6SixHex = "(?:" + h16 + ":){6}" + ls32; - const IPv6FiveHex = "::(?:" + h16 + ":){5}" + ls32; - const IPv6FourHex = "(?:" + h16 + ")?::(?:" + h16 + ":){4}" + ls32; - const IPv6ThreeHex = "(?:(?:" + h16 + ":){0,1}" + h16 + ")?::(?:" + h16 + ":){3}" + ls32; - const IPv6TwoHex = "(?:(?:" + h16 + ":){0,2}" + h16 + ")?::(?:" + h16 + ":){2}" + ls32; - const IPv6OneHex = "(?:(?:" + h16 + ":){0,3}" + h16 + ")?::" + h16 + ":" + ls32; - const IPv6NoneHex = "(?:(?:" + h16 + ":){0,4}" + h16 + ")?::" + ls32; - const IPv6NoneHex2 = "(?:(?:" + h16 + ":){0,5}" + h16 + ")?::" + h16; - const IPv6NoneHex3 = "(?:(?:" + h16 + ":){0,6}" + h16 + ")?::"; - rfc39862.ipv4Cidr = "(?:\\d|[1-2]\\d|3[0-2])"; - rfc39862.ipv6Cidr = "(?:0{0,2}\\d|0?[1-9]\\d|1[01]\\d|12[0-8])"; - rfc39862.ipv6address = "(?:" + IPv6SixHex + "|" + IPv6FiveHex + "|" + IPv6FourHex + "|" + IPv6ThreeHex + "|" + IPv6TwoHex + "|" + IPv6OneHex + "|" + IPv6NoneHex + "|" + IPv6NoneHex2 + "|" + IPv6NoneHex3 + ")"; - rfc39862.ipvFuture = "v" + hexDigitOnly + "+\\.[" + unreserved + subDelims + ":]+"; - rfc39862.scheme = "[a-zA-Z][a-zA-Z\\d+-\\.]*"; - rfc39862.schemeRegex = new RegExp(rfc39862.scheme); - const userinfo = "[" + unreserved + pctEncoded + subDelims + ":]*"; - const IPLiteral = "\\[(?:" + rfc39862.ipv6address + "|" + rfc39862.ipvFuture + ")\\]"; - const regName = "[" + unreserved + pctEncoded + subDelims + "]{1,255}"; - const host = "(?:" + IPLiteral + "|" + rfc39862.ipv4address + "|" + regName + ")"; - const port = "\\d*"; - const authority = "(?:" + userinfo + "@)?" + host + "(?::" + port + ")?"; - const authorityCapture = "(?:" + userinfo + "@)?(" + host + ")(?::" + port + ")?"; - const segment = pcharOnly + "*"; - const segmentNz = pcharOnly + "+"; - const segmentNzNc = "[" + unreserved + pctEncoded + subDelims + "@]+"; - const pathEmpty = ""; - const pathAbEmpty = "(?:\\/" + segment + ")*"; - const pathAbsolute = "\\/(?:" + segmentNz + pathAbEmpty + ")?"; - const pathRootless = segmentNz + pathAbEmpty; - const pathNoScheme = segmentNzNc + pathAbEmpty; - const pathAbNoAuthority = "(?:\\/\\/\\/" + segment + pathAbEmpty + ")"; - rfc39862.hierPart = "(?:(?:\\/\\/" + authority + pathAbEmpty + ")|" + pathAbsolute + "|" + pathRootless + "|" + pathAbNoAuthority + ")"; - rfc39862.hierPartCapture = "(?:(?:\\/\\/" + authorityCapture + pathAbEmpty + ")|" + pathAbsolute + "|" + pathRootless + ")"; - rfc39862.relativeRef = "(?:(?:\\/\\/" + authority + pathAbEmpty + ")|" + pathAbsolute + "|" + pathNoScheme + "|" + pathEmpty + ")"; - rfc39862.relativeRefCapture = "(?:(?:\\/\\/" + authorityCapture + pathAbEmpty + ")|" + pathAbsolute + "|" + pathNoScheme + "|" + pathEmpty + ")"; - rfc39862.query = "[" + pchar + "\\/\\?]*(?=#|$)"; - rfc39862.queryWithSquareBrackets = "[" + pchar + "\\[\\]\\/\\?]*(?=#|$)"; - rfc39862.fragment = "[" + pchar + "\\/\\?]*"; - return rfc39862; - } - var rfc3986 = generate(); - exports2.ipVersions = { - v4Cidr: rfc3986.ipv4Cidr, - v6Cidr: rfc3986.ipv6Cidr, - ipv4: rfc3986.ipv4address, - ipv6: rfc3986.ipv6address, - ipvfuture: rfc3986.ipvFuture - }; - function createRegex(options2) { - const rfc = rfc3986; - const query = options2.allowQuerySquareBrackets ? rfc.queryWithSquareBrackets : rfc.query; - const suffix = "(?:\\?" + query + ")?(?:#" + rfc.fragment + ")?"; - const relative32 = options2.domain ? rfc.relativeRefCapture : rfc.relativeRef; - if (options2.relativeOnly) { - return wrap2(relative32 + suffix); - } - let customScheme = ""; - if (options2.scheme) { - (0, hoek_1.assert)(options2.scheme instanceof RegExp || typeof options2.scheme === "string" || Array.isArray(options2.scheme), "scheme must be a RegExp, String, or Array"); - const schemes = [].concat(options2.scheme); - (0, hoek_1.assert)(schemes.length >= 1, "scheme must have at least 1 scheme specified"); - const selections = []; - for (let i2 = 0; i2 < schemes.length; ++i2) { - const scheme2 = schemes[i2]; - (0, hoek_1.assert)(scheme2 instanceof RegExp || typeof scheme2 === "string", "scheme at position " + i2 + " must be a RegExp or String"); - if (scheme2 instanceof RegExp) { - selections.push(scheme2.source.toString()); - } else { - (0, hoek_1.assert)(rfc.schemeRegex.test(scheme2), "scheme at position " + i2 + " must be a valid scheme"); - selections.push((0, hoek_1.escapeRegex)(scheme2)); - } + jobStatus(id) { + return this._states.jobStatus(id); } - customScheme = selections.join("|"); - } - const scheme = customScheme ? "(?:" + customScheme + ")" : rfc.scheme; - const absolute = "(?:" + scheme + ":" + (options2.domain ? rfc.hierPartCapture : rfc.hierPart) + ")"; - const prefix = options2.allowRelative ? "(?:" + absolute + "|" + relative32 + ")" : absolute; - return wrap2(prefix + suffix, customScheme); - } - function wrap2(raw, scheme = null) { - raw = `(?=.)(?!https?:/(?:$|[^/]))(?!https?:///)(?!https?:[^/])${raw}`; - return { - raw, - regex: new RegExp(`^${raw}$`), - scheme - }; - } - var genericUriRegex = createRegex({}); - function uriRegex(options2 = {}) { - if (options2.scheme || options2.allowRelative || options2.relativeOnly || options2.allowQuerySquareBrackets || options2.domain) { - return createRegex(options2); - } - return genericUriRegex; - } - exports2.uriRegex = uriRegex; - } -}); -var require_ip = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/ip.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.ipRegex = void 0; - var hoek_1 = require_lib(); - var uri_1 = require_uri(); - function ipRegex(options2 = {}) { - const cidr = options2.cidr || "optional"; - (0, hoek_1.assert)(["required", "optional", "forbidden"].includes(cidr), "options.cidr must be one of required, optional, forbidden"); - (0, hoek_1.assert)(options2.version === void 0 || typeof options2.version === "string" || Array.isArray(options2.version), "options.version must be a string or an array of string"); - let versions = options2.version || ["ipv4", "ipv6", "ipvfuture"]; - if (!Array.isArray(versions)) { - versions = [versions]; - } - (0, hoek_1.assert)(versions.length >= 1, "options.version must have at least 1 version specified"); - for (const version3 of versions) { - (0, hoek_1.assert)(typeof version3 === "string" && version3 === version3.toLowerCase(), "Invalid options.version value"); - (0, hoek_1.assert)(["ipv4", "ipv6", "ipvfuture"].includes(version3), "options.version contains unknown version " + version3 + " - must be one of ipv4, ipv6, ipvfuture"); - } - versions = Array.from(new Set(versions)); - const parts = versions.map((version3) => { - if (cidr === "forbidden") { - return uri_1.ipVersions[version3]; + jobs(status) { + return this._states.statusJobs(status); } - const cidrpart = `\\/${version3 === "ipv4" ? uri_1.ipVersions.v4Cidr : uri_1.ipVersions.v6Cidr}`; - if (cidr === "required") { - return `${uri_1.ipVersions[version3]}${cidrpart}`; + counts() { + return this._states.statusCounts(); } - return `${uri_1.ipVersions[version3]}(?:${cidrpart})?`; - }); - const raw = `(?:${parts.join("|")})`; - const regex = new RegExp(`^${raw}$`); - return { cidr, versions, regex, raw }; - } - exports2.ipRegex = ipRegex; - } -}); -var require_decode2 = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/decode.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.uriDecode = void 0; - var HEX = { - "0": 0, - "1": 1, - "2": 2, - "3": 3, - "4": 4, - "5": 5, - "6": 6, - "7": 7, - "8": 8, - "9": 9, - a: 10, - A: 10, - b: 11, - B: 11, - c: 12, - C: 12, - d: 13, - D: 13, - e: 14, - E: 14, - f: 15, - F: 15 - }; - var UTF8 = { - accept: 12, - reject: 0, - data: [ - // Maps bytes to character to a transition - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 2, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 3, - 4, - 4, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 5, - 6, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 7, - 8, - 7, - 7, - 10, - 9, - 9, - 9, - 11, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - 4, - // Maps a state to a new state when adding a transition - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 12, - 0, - 0, - 0, - 0, - 24, - 36, - 48, - 60, - 72, - 84, - 96, - 0, - 12, - 12, - 12, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 24, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 24, - 24, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 48, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 48, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // Maps the current transition to a mask that needs to apply to the byte - 127, - 63, - 63, - 63, - 0, - 31, - 15, - 15, - 15, - 7, - 7, - 7 - ] - }; - function uriDecode(string3) { - let percentPos = string3.indexOf("%"); - if (percentPos === -1) { - return string3; - } - let decoded = ""; - let last = 0; - let codepoint = 0; - let startOfOctets = percentPos; - let state = UTF8.accept; - while (percentPos > -1 && percentPos < string3.length) { - const high = resolveHex(string3[percentPos + 1], 4); - const low = resolveHex(string3[percentPos + 2], 0); - const byte = high | low; - const type = UTF8.data[byte]; - state = UTF8.data[256 + state + type]; - codepoint = codepoint << 6 | byte & UTF8.data[364 + type]; - if (state === UTF8.accept) { - decoded += string3.slice(last, startOfOctets); - decoded += codepoint <= 65535 ? String.fromCharCode(codepoint) : String.fromCharCode(55232 + (codepoint >> 10), 56320 + (codepoint & 1023)); - codepoint = 0; - last = percentPos + 3; - percentPos = string3.indexOf("%", last); - startOfOctets = percentPos; - continue; + _randomIndex() { + return Math.random().toString(36).slice(2); } - if (state === UTF8.reject) { - return null; + check(weight = 1) { + return this._store.__check__(weight); } - percentPos += 3; - if (percentPos >= string3.length || string3[percentPos] !== "%") { - return null; + _clearGlobalState(index) { + if (this._scheduled[index] != null) { + clearTimeout(this._scheduled[index].expiration); + delete this._scheduled[index]; + return true; + } else { + return false; + } } - } - return decoded + string3.slice(last); - } - exports2.uriDecode = uriDecode; - function resolveHex(char, shift) { - const i2 = HEX[char]; - return i2 === void 0 ? 255 : i2 << shift; - } - } -}); -var require_dist3 = __commonJS({ - "node_modules/.deno/@hapi+address@5.1.1/node_modules/@hapi/address/dist/index.js"(exports2) { - "use strict"; - var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m3, k); - if (!desc || ("get" in desc ? !m3.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { - return m3[k]; - } }; - } - Object.defineProperty(o2, k2, desc); - } : function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - o2[k2] = m3[k]; - }); - var __exportStar = exports2 && exports2.__exportStar || function(m3, exports3) { - for (var p in m3) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports3, p)) __createBinding(exports3, m3, p); - }; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.uriDecode = exports2.uriRegex = exports2.ipRegex = exports2.errorCodes = void 0; - __exportStar(require_domain(), exports2); - __exportStar(require_email(), exports2); - var errors_1 = require_errors4(); - Object.defineProperty(exports2, "errorCodes", { enumerable: true, get: function() { - return errors_1.errorCodes; - } }); - var ip_1 = require_ip(); - Object.defineProperty(exports2, "ipRegex", { enumerable: true, get: function() { - return ip_1.ipRegex; - } }); - var uri_1 = require_uri(); - Object.defineProperty(exports2, "uriRegex", { enumerable: true, get: function() { - return uri_1.uriRegex; - } }); - var decode_1 = require_decode2(); - Object.defineProperty(exports2, "uriDecode", { enumerable: true, get: function() { - return decode_1.uriDecode; - } }); - } -}); -var require_tlds = __commonJS({ - "node_modules/.deno/@hapi+tlds@1.1.3/node_modules/@hapi/tlds/dist/commonjs/tlds.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.TLDS = void 0; - exports2.TLDS = [ - "AAA", - "AARP", - "ABB", - "ABBOTT", - "ABBVIE", - "ABC", - "ABLE", - "ABOGADO", - "ABUDHABI", - "AC", - "ACADEMY", - "ACCENTURE", - "ACCOUNTANT", - "ACCOUNTANTS", - "ACO", - "ACTOR", - "AD", - "ADS", - "ADULT", - "AE", - "AEG", - "AERO", - "AETNA", - "AF", - "AFL", - "AFRICA", - "AG", - "AGAKHAN", - "AGENCY", - "AI", - "AIG", - "AIRBUS", - "AIRFORCE", - "AIRTEL", - "AKDN", - "AL", - "ALIBABA", - "ALIPAY", - "ALLFINANZ", - "ALLSTATE", - "ALLY", - "ALSACE", - "ALSTOM", - "AM", - "AMAZON", - "AMERICANEXPRESS", - "AMERICANFAMILY", - "AMEX", - "AMFAM", - "AMICA", - "AMSTERDAM", - "ANALYTICS", - "ANDROID", - "ANQUAN", - "ANZ", - "AO", - "AOL", - "APARTMENTS", - "APP", - "APPLE", - "AQ", - "AQUARELLE", - "AR", - "ARAB", - "ARAMCO", - "ARCHI", - "ARMY", - "ARPA", - "ART", - "ARTE", - "AS", - "ASDA", - "ASIA", - "ASSOCIATES", - "AT", - "ATHLETA", - "ATTORNEY", - "AU", - "AUCTION", - "AUDI", - "AUDIBLE", - "AUDIO", - "AUSPOST", - "AUTHOR", - "AUTO", - "AUTOS", - "AW", - "AWS", - "AX", - "AXA", - "AZ", - "AZURE", - "BA", - "BABY", - "BAIDU", - "BANAMEX", - "BAND", - "BANK", - "BAR", - "BARCELONA", - "BARCLAYCARD", - "BARCLAYS", - "BAREFOOT", - "BARGAINS", - "BASEBALL", - "BASKETBALL", - "BAUHAUS", - "BAYERN", - "BB", - "BBC", - "BBT", - "BBVA", - "BCG", - "BCN", - "BD", - "BE", - "BEATS", - "BEAUTY", - "BEER", - "BERLIN", - "BEST", - "BESTBUY", - "BET", - "BF", - "BG", - "BH", - "BHARTI", - "BI", - "BIBLE", - "BID", - "BIKE", - "BING", - "BINGO", - "BIO", - "BIZ", - "BJ", - "BLACK", - "BLACKFRIDAY", - "BLOCKBUSTER", - "BLOG", - "BLOOMBERG", - "BLUE", - "BM", - "BMS", - "BMW", - "BN", - "BNPPARIBAS", - "BO", - "BOATS", - "BOEHRINGER", - "BOFA", - "BOM", - "BOND", - "BOO", - "BOOK", - "BOOKING", - "BOSCH", - "BOSTIK", - "BOSTON", - "BOT", - "BOUTIQUE", - "BOX", - "BR", - "BRADESCO", - "BRIDGESTONE", - "BROADWAY", - "BROKER", - "BROTHER", - "BRUSSELS", - "BS", - "BT", - "BUILD", - "BUILDERS", - "BUSINESS", - "BUY", - "BUZZ", - "BV", - "BW", - "BY", - "BZ", - "BZH", - "CA", - "CAB", - "CAFE", - "CAL", - "CALL", - "CALVINKLEIN", - "CAM", - "CAMERA", - "CAMP", - "CANON", - "CAPETOWN", - "CAPITAL", - "CAPITALONE", - "CAR", - "CARAVAN", - "CARDS", - "CARE", - "CAREER", - "CAREERS", - "CARS", - "CASA", - "CASE", - "CASH", - "CASINO", - "CAT", - "CATERING", - "CATHOLIC", - "CBA", - "CBN", - "CBRE", - "CC", - "CD", - "CENTER", - "CEO", - "CERN", - "CF", - "CFA", - "CFD", - "CG", - "CH", - "CHANEL", - "CHANNEL", - "CHARITY", - "CHASE", - "CHAT", - "CHEAP", - "CHINTAI", - "CHRISTMAS", - "CHROME", - "CHURCH", - "CI", - "CIPRIANI", - "CIRCLE", - "CISCO", - "CITADEL", - "CITI", - "CITIC", - "CITY", - "CK", - "CL", - "CLAIMS", - "CLEANING", - "CLICK", - "CLINIC", - "CLINIQUE", - "CLOTHING", - "CLOUD", - "CLUB", - "CLUBMED", - "CM", - "CN", - "CO", - "COACH", - "CODES", - "COFFEE", - "COLLEGE", - "COLOGNE", - "COM", - "COMMBANK", - "COMMUNITY", - "COMPANY", - "COMPARE", - "COMPUTER", - "COMSEC", - "CONDOS", - "CONSTRUCTION", - "CONSULTING", - "CONTACT", - "CONTRACTORS", - "COOKING", - "COOL", - "COOP", - "CORSICA", - "COUNTRY", - "COUPON", - "COUPONS", - "COURSES", - "CPA", - "CR", - "CREDIT", - "CREDITCARD", - "CREDITUNION", - "CRICKET", - "CROWN", - "CRS", - "CRUISE", - "CRUISES", - "CU", - "CUISINELLA", - "CV", - "CW", - "CX", - "CY", - "CYMRU", - "CYOU", - "CZ", - "DAD", - "DANCE", - "DATA", - "DATE", - "DATING", - "DATSUN", - "DAY", - "DCLK", - "DDS", - "DE", - "DEAL", - "DEALER", - "DEALS", - "DEGREE", - "DELIVERY", - "DELL", - "DELOITTE", - "DELTA", - "DEMOCRAT", - "DENTAL", - "DENTIST", - "DESI", - "DESIGN", - "DEV", - "DHL", - "DIAMONDS", - "DIET", - "DIGITAL", - "DIRECT", - "DIRECTORY", - "DISCOUNT", - "DISCOVER", - "DISH", - "DIY", - "DJ", - "DK", - "DM", - "DNP", - "DO", - "DOCS", - "DOCTOR", - "DOG", - "DOMAINS", - "DOT", - "DOWNLOAD", - "DRIVE", - "DTV", - "DUBAI", - "DUNLOP", - "DUPONT", - "DURBAN", - "DVAG", - "DVR", - "DZ", - "EARTH", - "EAT", - "EC", - "ECO", - "EDEKA", - "EDU", - "EDUCATION", - "EE", - "EG", - "EMAIL", - "EMERCK", - "ENERGY", - "ENGINEER", - "ENGINEERING", - "ENTERPRISES", - "EPSON", - "EQUIPMENT", - "ER", - "ERICSSON", - "ERNI", - "ES", - "ESQ", - "ESTATE", - "ET", - "EU", - "EUROVISION", - "EUS", - "EVENTS", - "EXCHANGE", - "EXPERT", - "EXPOSED", - "EXPRESS", - "EXTRASPACE", - "FAGE", - "FAIL", - "FAIRWINDS", - "FAITH", - "FAMILY", - "FAN", - "FANS", - "FARM", - "FARMERS", - "FASHION", - "FAST", - "FEDEX", - "FEEDBACK", - "FERRARI", - "FERRERO", - "FI", - "FIDELITY", - "FIDO", - "FILM", - "FINAL", - "FINANCE", - "FINANCIAL", - "FIRE", - "FIRESTONE", - "FIRMDALE", - "FISH", - "FISHING", - "FIT", - "FITNESS", - "FJ", - "FK", - "FLICKR", - "FLIGHTS", - "FLIR", - "FLORIST", - "FLOWERS", - "FLY", - "FM", - "FO", - "FOO", - "FOOD", - "FOOTBALL", - "FORD", - "FOREX", - "FORSALE", - "FORUM", - "FOUNDATION", - "FOX", - "FR", - "FREE", - "FRESENIUS", - "FRL", - "FROGANS", - "FRONTIER", - "FTR", - "FUJITSU", - "FUN", - "FUND", - "FURNITURE", - "FUTBOL", - "FYI", - "GA", - "GAL", - "GALLERY", - "GALLO", - "GALLUP", - "GAME", - "GAMES", - "GAP", - "GARDEN", - "GAY", - "GB", - "GBIZ", - "GD", - "GDN", - "GE", - "GEA", - "GENT", - "GENTING", - "GEORGE", - "GF", - "GG", - "GGEE", - "GH", - "GI", - "GIFT", - "GIFTS", - "GIVES", - "GIVING", - "GL", - "GLASS", - "GLE", - "GLOBAL", - "GLOBO", - "GM", - "GMAIL", - "GMBH", - "GMO", - "GMX", - "GN", - "GODADDY", - "GOLD", - "GOLDPOINT", - "GOLF", - "GOO", - "GOODYEAR", - "GOOG", - "GOOGLE", - "GOP", - "GOT", - "GOV", - "GP", - "GQ", - "GR", - "GRAINGER", - "GRAPHICS", - "GRATIS", - "GREEN", - "GRIPE", - "GROCERY", - "GROUP", - "GS", - "GT", - "GU", - "GUCCI", - "GUGE", - "GUIDE", - "GUITARS", - "GURU", - "GW", - "GY", - "HAIR", - "HAMBURG", - "HANGOUT", - "HAUS", - "HBO", - "HDFC", - "HDFCBANK", - "HEALTH", - "HEALTHCARE", - "HELP", - "HELSINKI", - "HERE", - "HERMES", - "HIPHOP", - "HISAMITSU", - "HITACHI", - "HIV", - "HK", - "HKT", - "HM", - "HN", - "HOCKEY", - "HOLDINGS", - "HOLIDAY", - "HOMEDEPOT", - "HOMEGOODS", - "HOMES", - "HOMESENSE", - "HONDA", - "HORSE", - "HOSPITAL", - "HOST", - "HOSTING", - "HOT", - "HOTELS", - "HOTMAIL", - "HOUSE", - "HOW", - "HR", - "HSBC", - "HT", - "HU", - "HUGHES", - "HYATT", - "HYUNDAI", - "IBM", - "ICBC", - "ICE", - "ICU", - "ID", - "IE", - "IEEE", - "IFM", - "IKANO", - "IL", - "IM", - "IMAMAT", - "IMDB", - "IMMO", - "IMMOBILIEN", - "IN", - "INC", - "INDUSTRIES", - "INFINITI", - "INFO", - "ING", - "INK", - "INSTITUTE", - "INSURANCE", - "INSURE", - "INT", - "INTERNATIONAL", - "INTUIT", - "INVESTMENTS", - "IO", - "IPIRANGA", - "IQ", - "IR", - "IRISH", - "IS", - "ISMAILI", - "IST", - "ISTANBUL", - "IT", - "ITAU", - "ITV", - "JAGUAR", - "JAVA", - "JCB", - "JE", - "JEEP", - "JETZT", - "JEWELRY", - "JIO", - "JLL", - "JM", - "JMP", - "JNJ", - "JO", - "JOBS", - "JOBURG", - "JOT", - "JOY", - "JP", - "JPMORGAN", - "JPRS", - "JUEGOS", - "JUNIPER", - "KAUFEN", - "KDDI", - "KE", - "KERRYHOTELS", - "KERRYPROPERTIES", - "KFH", - "KG", - "KH", - "KI", - "KIA", - "KIDS", - "KIM", - "KINDLE", - "KITCHEN", - "KIWI", - "KM", - "KN", - "KOELN", - "KOMATSU", - "KOSHER", - "KP", - "KPMG", - "KPN", - "KR", - "KRD", - "KRED", - "KUOKGROUP", - "KW", - "KY", - "KYOTO", - "KZ", - "LA", - "LACAIXA", - "LAMBORGHINI", - "LAMER", - "LAND", - "LANDROVER", - "LANXESS", - "LASALLE", - "LAT", - "LATINO", - "LATROBE", - "LAW", - "LAWYER", - "LB", - "LC", - "LDS", - "LEASE", - "LECLERC", - "LEFRAK", - "LEGAL", - "LEGO", - "LEXUS", - "LGBT", - "LI", - "LIDL", - "LIFE", - "LIFEINSURANCE", - "LIFESTYLE", - "LIGHTING", - "LIKE", - "LILLY", - "LIMITED", - "LIMO", - "LINCOLN", - "LINK", - "LIVE", - "LIVING", - "LK", - "LLC", - "LLP", - "LOAN", - "LOANS", - "LOCKER", - "LOCUS", - "LOL", - "LONDON", - "LOTTE", - "LOTTO", - "LOVE", - "LPL", - "LPLFINANCIAL", - "LR", - "LS", - "LT", - "LTD", - "LTDA", - "LU", - "LUNDBECK", - "LUXE", - "LUXURY", - "LV", - "LY", - "MA", - "MADRID", - "MAIF", - "MAISON", - "MAKEUP", - "MAN", - "MANAGEMENT", - "MANGO", - "MAP", - "MARKET", - "MARKETING", - "MARKETS", - "MARRIOTT", - "MARSHALLS", - "MATTEL", - "MBA", - "MC", - "MCKINSEY", - "MD", - "ME", - "MED", - "MEDIA", - "MEET", - "MELBOURNE", - "MEME", - "MEMORIAL", - "MEN", - "MENU", - "MERCKMSD", - "MG", - "MH", - "MIAMI", - "MICROSOFT", - "MIL", - "MINI", - "MINT", - "MIT", - "MITSUBISHI", - "MK", - "ML", - "MLB", - "MLS", - "MM", - "MMA", - "MN", - "MO", - "MOBI", - "MOBILE", - "MODA", - "MOE", - "MOI", - "MOM", - "MONASH", - "MONEY", - "MONSTER", - "MORMON", - "MORTGAGE", - "MOSCOW", - "MOTO", - "MOTORCYCLES", - "MOV", - "MOVIE", - "MP", - "MQ", - "MR", - "MS", - "MSD", - "MT", - "MTN", - "MTR", - "MU", - "MUSEUM", - "MUSIC", - "MV", - "MW", - "MX", - "MY", - "MZ", - "NA", - "NAB", - "NAGOYA", - "NAME", - "NAVY", - "NBA", - "NC", - "NE", - "NEC", - "NET", - "NETBANK", - "NETFLIX", - "NETWORK", - "NEUSTAR", - "NEW", - "NEWS", - "NEXT", - "NEXTDIRECT", - "NEXUS", - "NF", - "NFL", - "NG", - "NGO", - "NHK", - "NI", - "NICO", - "NIKE", - "NIKON", - "NINJA", - "NISSAN", - "NISSAY", - "NL", - "NO", - "NOKIA", - "NORTON", - "NOW", - "NOWRUZ", - "NOWTV", - "NP", - "NR", - "NRA", - "NRW", - "NTT", - "NU", - "NYC", - "NZ", - "OBI", - "OBSERVER", - "OFFICE", - "OKINAWA", - "OLAYAN", - "OLAYANGROUP", - "OLLO", - "OM", - "OMEGA", - "ONE", - "ONG", - "ONL", - "ONLINE", - "OOO", - "OPEN", - "ORACLE", - "ORANGE", - "ORG", - "ORGANIC", - "ORIGINS", - "OSAKA", - "OTSUKA", - "OTT", - "OVH", - "PA", - "PAGE", - "PANASONIC", - "PARIS", - "PARS", - "PARTNERS", - "PARTS", - "PARTY", - "PAY", - "PCCW", - "PE", - "PET", - "PF", - "PFIZER", - "PG", - "PH", - "PHARMACY", - "PHD", - "PHILIPS", - "PHONE", - "PHOTO", - "PHOTOGRAPHY", - "PHOTOS", - "PHYSIO", - "PICS", - "PICTET", - "PICTURES", - "PID", - "PIN", - "PING", - "PINK", - "PIONEER", - "PIZZA", - "PK", - "PL", - "PLACE", - "PLAY", - "PLAYSTATION", - "PLUMBING", - "PLUS", - "PM", - "PN", - "PNC", - "POHL", - "POKER", - "POLITIE", - "PORN", - "POST", - "PR", - "PRAXI", - "PRESS", - "PRIME", - "PRO", - "PROD", - "PRODUCTIONS", - "PROF", - "PROGRESSIVE", - "PROMO", - "PROPERTIES", - "PROPERTY", - "PROTECTION", - "PRU", - "PRUDENTIAL", - "PS", - "PT", - "PUB", - "PW", - "PWC", - "PY", - "QA", - "QPON", - "QUEBEC", - "QUEST", - "RACING", - "RADIO", - "RE", - "READ", - "REALESTATE", - "REALTOR", - "REALTY", - "RECIPES", - "RED", - "REDUMBRELLA", - "REHAB", - "REISE", - "REISEN", - "REIT", - "RELIANCE", - "REN", - "RENT", - "RENTALS", - "REPAIR", - "REPORT", - "REPUBLICAN", - "REST", - "RESTAURANT", - "REVIEW", - "REVIEWS", - "REXROTH", - "RICH", - "RICHARDLI", - "RICOH", - "RIL", - "RIO", - "RIP", - "RO", - "ROCKS", - "RODEO", - "ROGERS", - "ROOM", - "RS", - "RSVP", - "RU", - "RUGBY", - "RUHR", - "RUN", - "RW", - "RWE", - "RYUKYU", - "SA", - "SAARLAND", - "SAFE", - "SAFETY", - "SAKURA", - "SALE", - "SALON", - "SAMSCLUB", - "SAMSUNG", - "SANDVIK", - "SANDVIKCOROMANT", - "SANOFI", - "SAP", - "SARL", - "SAS", - "SAVE", - "SAXO", - "SB", - "SBI", - "SBS", - "SC", - "SCB", - "SCHAEFFLER", - "SCHMIDT", - "SCHOLARSHIPS", - "SCHOOL", - "SCHULE", - "SCHWARZ", - "SCIENCE", - "SCOT", - "SD", - "SE", - "SEARCH", - "SEAT", - "SECURE", - "SECURITY", - "SEEK", - "SELECT", - "SENER", - "SERVICES", - "SEVEN", - "SEW", - "SEX", - "SEXY", - "SFR", - "SG", - "SH", - "SHANGRILA", - "SHARP", - "SHELL", - "SHIA", - "SHIKSHA", - "SHOES", - "SHOP", - "SHOPPING", - "SHOUJI", - "SHOW", - "SI", - "SILK", - "SINA", - "SINGLES", - "SITE", - "SJ", - "SK", - "SKI", - "SKIN", - "SKY", - "SKYPE", - "SL", - "SLING", - "SM", - "SMART", - "SMILE", - "SN", - "SNCF", - "SO", - "SOCCER", - "SOCIAL", - "SOFTBANK", - "SOFTWARE", - "SOHU", - "SOLAR", - "SOLUTIONS", - "SONG", - "SONY", - "SOY", - "SPA", - "SPACE", - "SPORT", - "SPOT", - "SR", - "SRL", - "SS", - "ST", - "STADA", - "STAPLES", - "STAR", - "STATEBANK", - "STATEFARM", - "STC", - "STCGROUP", - "STOCKHOLM", - "STORAGE", - "STORE", - "STREAM", - "STUDIO", - "STUDY", - "STYLE", - "SU", - "SUCKS", - "SUPPLIES", - "SUPPLY", - "SUPPORT", - "SURF", - "SURGERY", - "SUZUKI", - "SV", - "SWATCH", - "SWISS", - "SX", - "SY", - "SYDNEY", - "SYSTEMS", - "SZ", - "TAB", - "TAIPEI", - "TALK", - "TAOBAO", - "TARGET", - "TATAMOTORS", - "TATAR", - "TATTOO", - "TAX", - "TAXI", - "TC", - "TCI", - "TD", - "TDK", - "TEAM", - "TECH", - "TECHNOLOGY", - "TEL", - "TEMASEK", - "TENNIS", - "TEVA", - "TF", - "TG", - "TH", - "THD", - "THEATER", - "THEATRE", - "TIAA", - "TICKETS", - "TIENDA", - "TIPS", - "TIRES", - "TIROL", - "TJ", - "TJMAXX", - "TJX", - "TK", - "TKMAXX", - "TL", - "TM", - "TMALL", - "TN", - "TO", - "TODAY", - "TOKYO", - "TOOLS", - "TOP", - "TORAY", - "TOSHIBA", - "TOTAL", - "TOURS", - "TOWN", - "TOYOTA", - "TOYS", - "TR", - "TRADE", - "TRADING", - "TRAINING", - "TRAVEL", - "TRAVELERS", - "TRAVELERSINSURANCE", - "TRUST", - "TRV", - "TT", - "TUBE", - "TUI", - "TUNES", - "TUSHU", - "TV", - "TVS", - "TW", - "TZ", - "UA", - "UBANK", - "UBS", - "UG", - "UK", - "UNICOM", - "UNIVERSITY", - "UNO", - "UOL", - "UPS", - "US", - "UY", - "UZ", - "VA", - "VACATIONS", - "VANA", - "VANGUARD", - "VC", - "VE", - "VEGAS", - "VENTURES", - "VERISIGN", - "VERSICHERUNG", - "VET", - "VG", - "VI", - "VIAJES", - "VIDEO", - "VIG", - "VIKING", - "VILLAS", - "VIN", - "VIP", - "VIRGIN", - "VISA", - "VISION", - "VIVA", - "VIVO", - "VLAANDEREN", - "VN", - "VODKA", - "VOLVO", - "VOTE", - "VOTING", - "VOTO", - "VOYAGE", - "VU", - "WALES", - "WALMART", - "WALTER", - "WANG", - "WANGGOU", - "WATCH", - "WATCHES", - "WEATHER", - "WEATHERCHANNEL", - "WEBCAM", - "WEBER", - "WEBSITE", - "WED", - "WEDDING", - "WEIBO", - "WEIR", - "WF", - "WHOSWHO", - "WIEN", - "WIKI", - "WILLIAMHILL", - "WIN", - "WINDOWS", - "WINE", - "WINNERS", - "WME", - "WOLTERSKLUWER", - "WOODSIDE", - "WORK", - "WORKS", - "WORLD", - "WOW", - "WS", - "WTC", - "WTF", - "XBOX", - "XEROX", - "XIHUAN", - "XIN", - "XN--11B4C3D", - "XN--1CK2E1B", - "XN--1QQW23A", - "XN--2SCRJ9C", - "XN--30RR7Y", - "XN--3BST00M", - "XN--3DS443G", - "XN--3E0B707E", - "XN--3HCRJ9C", - "XN--3PXU8K", - "XN--42C2D9A", - "XN--45BR5CYL", - "XN--45BRJ9C", - "XN--45Q11C", - "XN--4DBRK0CE", - "XN--4GBRIM", - "XN--54B7FTA0CC", - "XN--55QW42G", - "XN--55QX5D", - "XN--5SU34J936BGSG", - "XN--5TZM5G", - "XN--6FRZ82G", - "XN--6QQ986B3XL", - "XN--80ADXHKS", - "XN--80AO21A", - "XN--80AQECDR1A", - "XN--80ASEHDB", - "XN--80ASWG", - "XN--8Y0A063A", - "XN--90A3AC", - "XN--90AE", - "XN--90AIS", - "XN--9DBQ2A", - "XN--9ET52U", - "XN--9KRT00A", - "XN--B4W605FERD", - "XN--BCK1B9A5DRE4C", - "XN--C1AVG", - "XN--C2BR7G", - "XN--CCK2B3B", - "XN--CCKWCXETD", - "XN--CG4BKI", - "XN--CLCHC0EA0B2G2A9GCD", - "XN--CZR694B", - "XN--CZRS0T", - "XN--CZRU2D", - "XN--D1ACJ3B", - "XN--D1ALF", - "XN--E1A4C", - "XN--ECKVDTC9D", - "XN--EFVY88H", - "XN--FCT429K", - "XN--FHBEI", - "XN--FIQ228C5HS", - "XN--FIQ64B", - "XN--FIQS8S", - "XN--FIQZ9S", - "XN--FJQ720A", - "XN--FLW351E", - "XN--FPCRJ9C3D", - "XN--FZC2C9E2C", - "XN--FZYS8D69UVGM", - "XN--G2XX48C", - "XN--GCKR3F0F", - "XN--GECRJ9C", - "XN--GK3AT1E", - "XN--H2BREG3EVE", - "XN--H2BRJ9C", - "XN--H2BRJ9C8C", - "XN--HXT814E", - "XN--I1B6B1A6A2E", - "XN--IMR513N", - "XN--IO0A7I", - "XN--J1AEF", - "XN--J1AMH", - "XN--J6W193G", - "XN--JLQ480N2RG", - "XN--JVR189M", - "XN--KCRX77D1X4A", - "XN--KPRW13D", - "XN--KPRY57D", - "XN--KPUT3I", - "XN--L1ACC", - "XN--LGBBAT1AD8J", - "XN--MGB9AWBF", - "XN--MGBA3A3EJT", - "XN--MGBA3A4F16A", - "XN--MGBA7C0BBN0A", - "XN--MGBAAM7A8H", - "XN--MGBAB2BD", - "XN--MGBAH1A3HJKRD", - "XN--MGBAI9AZGQP6J", - "XN--MGBAYH7GPA", - "XN--MGBBH1A", - "XN--MGBBH1A71E", - "XN--MGBC0A9AZCG", - "XN--MGBCA7DZDO", - "XN--MGBCPQ6GPA1A", - "XN--MGBERP4A5D4AR", - "XN--MGBGU82A", - "XN--MGBI4ECEXP", - "XN--MGBPL2FH", - "XN--MGBT3DHD", - "XN--MGBTX2B", - "XN--MGBX4CD0AB", - "XN--MIX891F", - "XN--MK1BU44C", - "XN--MXTQ1M", - "XN--NGBC5AZD", - "XN--NGBE9E0A", - "XN--NGBRX", - "XN--NODE", - "XN--NQV7F", - "XN--NQV7FS00EMA", - "XN--NYQY26A", - "XN--O3CW4H", - "XN--OGBPF8FL", - "XN--OTU796D", - "XN--P1ACF", - "XN--P1AI", - "XN--PGBS0DH", - "XN--PSSY2U", - "XN--Q7CE6A", - "XN--Q9JYB4C", - "XN--QCKA1PMC", - "XN--QXA6A", - "XN--QXAM", - "XN--RHQV96G", - "XN--ROVU88B", - "XN--RVC1E0AM3E", - "XN--S9BRJ9C", - "XN--SES554G", - "XN--T60B56A", - "XN--TCKWE", - "XN--TIQ49XQYJ", - "XN--UNUP4Y", - "XN--VERMGENSBERATER-CTB", - "XN--VERMGENSBERATUNG-PWB", - "XN--VHQUV", - "XN--VUQ861B", - "XN--W4R85EL8FHU5DNRA", - "XN--W4RS40L", - "XN--WGBH1C", - "XN--WGBL6A", - "XN--XHQ521B", - "XN--XKC2AL3HYE2A", - "XN--XKC2DL3A5EE0H", - "XN--Y9A3AQ", - "XN--YFRO4I67O", - "XN--YGBI2AMMX", - "XN--ZFR164B", - "XXX", - "XYZ", - "YACHTS", - "YAHOO", - "YAMAXUN", - "YANDEX", - "YE", - "YODOBASHI", - "YOGA", - "YOKOHAMA", - "YOU", - "YOUTUBE", - "YT", - "YUN", - "ZA", - "ZAPPOS", - "ZARA", - "ZERO", - "ZIP", - "ZM", - "ZONE", - "ZUERICH", - "ZW" - ]; - } -}); -var require_commonjs = __commonJS({ - "node_modules/.deno/@hapi+tlds@1.1.3/node_modules/@hapi/tlds/dist/commonjs/index.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.tlds = void 0; - var tlds_js_1 = require_tlds(); - exports2.tlds = new Set(tlds_js_1.TLDS.map((tld) => tld.toLowerCase())); - } -}); -var require_string2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/string.js"(exports2, module14) { - "use strict"; - var { assert: assert2, escapeRegex: escapeRegex2 } = require_lib(); - var { isDomainValid, isEmailValid, ipRegex, uriRegex } = require_dist3(); - var Tlds = require_commonjs(); - var Any = require_any2(); - var Common = require_common3(); - var internals = { - tlds: Tlds.tlds instanceof Set ? { tlds: { allow: Tlds.tlds, deny: null } } : false, - // $lab:coverage:ignore$ - base64Regex: { - // paddingRequired - true: { - // urlSafe - true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}==|[\w\-]{3}=)?$/, - false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/ - }, - false: { - true: /^(?:[\w\-]{2}[\w\-]{2})*(?:[\w\-]{2}(==)?|[\w\-]{3}=?)?$/, - false: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/ - } - }, - dataUriRegex: /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/, - hexRegex: { - withPrefix: /^0x[0-9a-f]+$/i, - withOptionalPrefix: /^(?:0x)?[0-9a-f]+$/i, - withoutPrefix: /^[0-9a-f]+$/i - }, - ipRegex: ipRegex({ cidr: "forbidden" }).regex, - isoDurationRegex: /^P(?!$)(\d+Y)?(\d+M)?(\d+W)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?(\d+S)?)?$/, - guidBrackets: { - "{": "}", - "[": "]", - "(": ")", - "": "" - }, - guidVersions: { - uuidv1: "1", - uuidv2: "2", - uuidv3: "3", - uuidv4: "4", - uuidv5: "5", - uuidv6: "6", - uuidv7: "7", - uuidv8: "8" - }, - guidSeparators: /* @__PURE__ */ new Set([void 0, true, false, "-", ":"]), - normalizationForms: ["NFC", "NFD", "NFKC", "NFKD"] - }; - module14.exports = Any.extend({ - type: "string", - flags: { - insensitive: { default: false }, - truncate: { default: false } - }, - terms: { - replacements: { init: null } - }, - coerce: { - from: "string", - method(value, { schema, state, prefs }) { - const normalize32 = schema.$_getRule("normalize"); - if (normalize32) { - value = value.normalize(normalize32.args.form); - } - const casing = schema.$_getRule("case"); - if (casing) { - value = casing.args.direction === "upper" ? value.toLocaleUpperCase() : value.toLocaleLowerCase(); - } - const trim = schema.$_getRule("trim"); - if (trim && trim.args.enabled) { - value = value.trim(); - } - if (schema.$_terms.replacements) { - for (const replacement of schema.$_terms.replacements) { - value = value.replace(replacement.pattern, replacement.replacement); - } - } - const hex = schema.$_getRule("hex"); - if (hex && hex.args.options.byteAligned && value.length % 2 !== 0) { - value = `0${value}`; - } - if (schema.$_getRule("isoDate")) { - const iso = internals.isoDate(value); - if (iso) { - value = iso; - } - } - if (schema._flags.truncate) { - const rule = schema.$_getRule("max"); - if (rule) { - let limit = rule.args.limit; - if (Common.isResolvable(limit)) { - limit = limit.resolve(value, state, prefs); - if (!Common.limit(limit)) { - return { value, errors: schema.$_createError("any.ref", limit, { ref: rule.args.limit, arg: "limit", reason: "must be a positive integer" }, state, prefs) }; - } + _free(index, job, options2, eventInfo) { + var _this = this; + return _asyncToGenerator2(function* () { + var e2, running; + try { + var _ref = yield _this._store.__free__(index, options2.weight); + running = _ref.running; + _this.Events.trigger("debug", `Freed ${options2.id}`, eventInfo); + if (running === 0 && _this.empty()) { + return _this.Events.trigger("idle"); } - value = value.slice(0, limit); + } catch (error1) { + e2 = error1; + return _this.Events.trigger("error", e2); } - } - return { value }; - } - }, - validate(value, { schema, error: error2 }) { - if (typeof value !== "string") { - return { value, errors: error2("string.base") }; + })(); } - if (value === "") { - const min = schema.$_getRule("min"); - if (min && min.args.limit === 0) { - return; - } - return { value, errors: error2("string.empty") }; + _run(index, job, wait) { + var clearGlobalState, free, run2; + job.doRun(); + clearGlobalState = this._clearGlobalState.bind(this, index); + run2 = this._run.bind(this, index, job); + free = this._free.bind(this, index, job); + return this._scheduled[index] = { + timeout: setTimeout(() => { + return job.doExecute(this._limiter, clearGlobalState, run2, free); + }, wait), + expiration: job.options.expiration != null ? setTimeout(function() { + return job.doExpire(clearGlobalState, run2, free); + }, wait + job.options.expiration) : void 0, + job + }; } - }, - rules: { - alphanum: { - method() { - return this.$_addRule("alphanum"); - }, - validate(value, helpers) { - if (/^[a-zA-Z0-9]+$/.test(value)) { - return value; - } - return helpers.error("string.alphanum"); - } - }, - base64: { - method(options2 = {}) { - Common.assertOptions(options2, ["paddingRequired", "urlSafe"]); - options2 = { urlSafe: false, paddingRequired: true, ...options2 }; - assert2(typeof options2.paddingRequired === "boolean", "paddingRequired must be boolean"); - assert2(typeof options2.urlSafe === "boolean", "urlSafe must be boolean"); - return this.$_addRule({ name: "base64", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - const regex = internals.base64Regex[options2.paddingRequired][options2.urlSafe]; - if (regex.test(value)) { - return value; - } - return helpers.error("string.base64"); - } - }, - case: { - method(direction) { - assert2(["lower", "upper"].includes(direction), "Invalid case:", direction); - return this.$_addRule({ name: "case", args: { direction } }); - }, - validate(value, helpers, { direction }) { - if (direction === "lower" && value === value.toLocaleLowerCase() || direction === "upper" && value === value.toLocaleUpperCase()) { - return value; - } - return helpers.error(`string.${direction}case`); - }, - convert: true - }, - creditCard: { - method() { - return this.$_addRule("creditCard"); - }, - validate(value, helpers) { - let i2 = value.length; - let sum = 0; - let mul = 1; - while (i2--) { - const char = value.charAt(i2) * mul; - sum = sum + (char - (char > 9) * 9); - mul = mul ^ 3; - } - if (sum > 0 && sum % 10 === 0) { - return value; - } - return helpers.error("string.creditCard"); - } - }, - dataUri: { - method(options2 = {}) { - Common.assertOptions(options2, ["paddingRequired"]); - options2 = { paddingRequired: true, ...options2 }; - assert2(typeof options2.paddingRequired === "boolean", "paddingRequired must be boolean"); - return this.$_addRule({ name: "dataUri", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - const matches = value.match(internals.dataUriRegex); - if (matches) { - if (!matches[2]) { - return value; - } - if (matches[2] !== "base64") { - return value; - } - const base64regex = internals.base64Regex[options2.paddingRequired].false; - if (base64regex.test(matches[3])) { - return value; - } - } - return helpers.error("string.dataUri"); - } - }, - domain: { - method(options2) { - if (options2) { - Common.assertOptions(options2, ["allowFullyQualified", "allowUnicode", "allowUnderscore", "maxDomainSegments", "minDomainSegments", "tlds"]); - } - const address = internals.addressOptions(options2); - return this.$_addRule({ name: "domain", args: { options: options2 }, address }); - }, - validate(value, helpers, args, { address }) { - if (isDomainValid(value, address)) { - return value; - } - return helpers.error("string.domain"); - } - }, - email: { - method(options2 = {}) { - Common.assertOptions(options2, ["allowFullyQualified", "allowUnicode", "ignoreLength", "maxDomainSegments", "minDomainSegments", "multiple", "separator", "tlds"]); - assert2(options2.multiple === void 0 || typeof options2.multiple === "boolean", "multiple option must be an boolean"); - const address = internals.addressOptions(options2); - const regex = new RegExp(`\\s*[${options2.separator ? escapeRegex2(options2.separator) : ","}]\\s*`); - return this.$_addRule({ name: "email", args: { options: options2 }, regex, address }); - }, - validate(value, helpers, { options: options2 }, { regex, address }) { - const emails = options2.multiple ? value.split(regex) : [value]; - const invalids = []; - for (const email2 of emails) { - if (!isEmailValid(email2, address)) { - invalids.push(email2); - } + _drainOne(capacity) { + return this._registerLock.schedule(() => { + var args, index, next, options2, queue; + if (this.queued() === 0) { + return this.Promise.resolve(null); } - if (!invalids.length) { - return value; + queue = this._queues.getFirst(); + var _next2 = next = queue.first(); + options2 = _next2.options; + args = _next2.args; + if (capacity != null && options2.weight > capacity) { + return this.Promise.resolve(null); } - return helpers.error("string.email", { value, invalids }); - } - }, - guid: { - alias: "uuid", - method(options2 = {}) { - Common.assertOptions(options2, ["version", "separator", "wrapper"]); - assert2( - options2.wrapper === void 0 || typeof options2.wrapper === "boolean" || typeof options2.wrapper === "string" && typeof internals.guidBrackets[options2.wrapper] === "string", - `"wrapper" must be true, false, or one of "${Object.keys(internals.guidBrackets).filter(Boolean).join('", "')}"` - ); - let versionNumbers = ""; - if (options2.version) { - const versions = [].concat(options2.version); - assert2(versions.length >= 1, "version must have at least 1 valid version specified"); - const set = /* @__PURE__ */ new Set(); - for (let i2 = 0; i2 < versions.length; ++i2) { - const version3 = versions[i2]; - assert2(typeof version3 === "string", "version at position " + i2 + " must be a string"); - const versionNumber = internals.guidVersions[version3.toLowerCase()]; - assert2(versionNumber, "version at position " + i2 + " must be one of " + Object.keys(internals.guidVersions).join(", ")); - assert2(!set.has(versionNumber), "version at position " + i2 + " must not be a duplicate"); - versionNumbers += versionNumber; - set.add(versionNumber); + this.Events.trigger("debug", `Draining ${options2.id}`, { + args, + options: options2 + }); + index = this._randomIndex(); + return this._store.__register__(index, options2.weight, options2.expiration).then(({ + success, + wait, + reservoir + }) => { + var empty2; + this.Events.trigger("debug", `Drained ${options2.id}`, { + success, + args, + options: options2 + }); + if (success) { + queue.shift(); + empty2 = this.empty(); + if (empty2) { + this.Events.trigger("empty"); + } + if (reservoir === 0) { + this.Events.trigger("depleted", empty2); + } + this._run(index, next, wait); + return this.Promise.resolve(options2.weight); + } else { + return this.Promise.resolve(null); } - } - assert2(internals.guidSeparators.has(options2.separator), 'separator must be one of true, false, "-", or ":"'); - const separator = options2.separator === void 0 ? "[:-]?" : options2.separator === true ? "[:-]" : options2.separator === false ? "[]?" : `\\${options2.separator}`; - let wrapperStart; - let wrapperEnd; - if (options2.wrapper === void 0) { - wrapperStart = "[\\[{\\(]?"; - wrapperEnd = "[\\]}\\)]?"; - } else if (options2.wrapper === true) { - wrapperStart = "[\\[{\\(]"; - wrapperEnd = "[\\]}\\)]"; - } else if (options2.wrapper === false) { - wrapperStart = ""; - wrapperEnd = ""; + }); + }); + } + _drainAll(capacity, total = 0) { + return this._drainOne(capacity).then((drained) => { + var newCapacity; + if (drained != null) { + newCapacity = capacity != null ? capacity - drained : capacity; + return this._drainAll(newCapacity, total + drained); } else { - wrapperStart = escapeRegex2(options2.wrapper); - wrapperEnd = escapeRegex2(internals.guidBrackets[options2.wrapper]); - } - const regex = new RegExp( - `^(${wrapperStart})[0-9A-F]{8}(${separator})[0-9A-F]{4}\\2?[${versionNumbers || "0-9A-F"}][0-9A-F]{3}\\2?[${versionNumbers ? "89AB" : "0-9A-F"}][0-9A-F]{3}\\2?[0-9A-F]{12}(${wrapperEnd})$`, - "i" - ); - return this.$_addRule({ name: "guid", args: { options: options2 }, regex }); - }, - validate(value, helpers, args, { regex }) { - const results = regex.exec(value); - if (!results) { - return helpers.error("string.guid"); - } - const open = results[1]; - const close = results[results.length - 1]; - if ((open || close) && internals.guidBrackets[open] !== close) { - return helpers.error("string.guid"); - } - return value; - } - }, - hex: { - method(options2 = {}) { - Common.assertOptions(options2, ["byteAligned", "prefix"]); - options2 = { byteAligned: false, prefix: false, ...options2 }; - assert2(typeof options2.byteAligned === "boolean", "byteAligned must be boolean"); - assert2(typeof options2.prefix === "boolean" || options2.prefix === "optional", 'prefix must be boolean or "optional"'); - return this.$_addRule({ name: "hex", args: { options: options2 } }); - }, - validate(value, helpers, { options: options2 }) { - const re = options2.prefix === "optional" ? internals.hexRegex.withOptionalPrefix : options2.prefix === true ? internals.hexRegex.withPrefix : internals.hexRegex.withoutPrefix; - if (!re.test(value)) { - return helpers.error("string.hex"); - } - if (options2.byteAligned && value.length % 2 !== 0) { - return helpers.error("string.hexAlign"); - } - return value; - } - }, - hostname: { - method() { - return this.$_addRule("hostname"); - }, - validate(value, helpers) { - if (isDomainValid(value, { minDomainSegments: 1 }) || internals.ipRegex.test(value)) { - return value; - } - return helpers.error("string.hostname"); - } - }, - insensitive: { - method() { - return this.$_setFlag("insensitive", true); - } - }, - ip: { - method(options2 = {}) { - Common.assertOptions(options2, ["cidr", "version"]); - const { cidr, versions, regex } = ipRegex(options2); - const version3 = options2.version ? versions : void 0; - return this.$_addRule({ name: "ip", args: { options: { cidr, version: version3 } }, regex }); - }, - validate(value, helpers, { options: options2 }, { regex }) { - if (regex.test(value)) { - return value; - } - if (options2.version) { - return helpers.error("string.ipVersion", { value, cidr: options2.cidr, version: options2.version }); - } - return helpers.error("string.ip", { value, cidr: options2.cidr }); - } - }, - isoDate: { - method() { - return this.$_addRule("isoDate"); - }, - validate(value, { error: error2 }) { - if (internals.isoDate(value)) { - return value; - } - return error2("string.isoDate"); - } - }, - isoDuration: { - method() { - return this.$_addRule("isoDuration"); - }, - validate(value, helpers) { - if (internals.isoDurationRegex.test(value)) { - return value; - } - return helpers.error("string.isoDuration"); - } - }, - length: { - method(limit, encoding) { - return internals.length(this, "length", limit, "=", encoding); - }, - validate(value, helpers, { limit, encoding }, { name, operator, args }) { - const length2 = encoding ? Buffer && Buffer.byteLength(value, encoding) : value.length; - if (Common.compare(length2, limit, operator)) { - return value; - } - return helpers.error("string." + name, { limit: args.limit, value, encoding }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" - }, - "encoding" - ] - }, - lowercase: { - method() { - return this.case("lower"); - } - }, - max: { - method(limit, encoding) { - return internals.length(this, "max", limit, "<=", encoding); - }, - args: ["limit", "encoding"] - }, - min: { - method(limit, encoding) { - return internals.length(this, "min", limit, ">=", encoding); - }, - args: ["limit", "encoding"] - }, - normalize: { - method(form = "NFC") { - assert2(internals.normalizationForms.includes(form), "normalization form must be one of " + internals.normalizationForms.join(", ")); - return this.$_addRule({ name: "normalize", args: { form } }); - }, - validate(value, { error: error2 }, { form }) { - if (value === value.normalize(form)) { - return value; - } - return error2("string.normalize", { value, form }); - }, - convert: true - }, - pattern: { - alias: "regex", - method(regex, options2 = {}) { - assert2(regex instanceof RegExp, "regex must be a RegExp"); - assert2(!regex.flags.includes("g") && !regex.flags.includes("y"), "regex should not use global or sticky mode"); - if (typeof options2 === "string") { - options2 = { name: options2 }; - } - Common.assertOptions(options2, ["invert", "name"]); - const errorCode = ["string.pattern", options2.invert ? ".invert" : "", options2.name ? ".name" : ".base"].join(""); - return this.$_addRule({ name: "pattern", args: { regex, options: options2 }, errorCode }); - }, - validate(value, helpers, { regex, options: options2 }, { errorCode }) { - const patternMatch = regex.test(value); - if (patternMatch ^ options2.invert) { - return value; - } - return helpers.error(errorCode, { name: options2.name, regex, value }); - }, - args: ["regex", "options"], - multi: true - }, - replace: { - method(pattern, replacement) { - if (typeof pattern === "string") { - pattern = new RegExp(escapeRegex2(pattern), "g"); - } - assert2(pattern instanceof RegExp, "pattern must be a RegExp"); - assert2(typeof replacement === "string", "replacement must be a String"); - const obj = this.clone(); - if (!obj.$_terms.replacements) { - obj.$_terms.replacements = []; - } - obj.$_terms.replacements.push({ pattern, replacement }); - return obj; - } - }, - token: { - method() { - return this.$_addRule("token"); - }, - validate(value, helpers) { - if (/^\w+$/.test(value)) { - return value; - } - return helpers.error("string.token"); - } - }, - trim: { - method(enabled2 = true) { - assert2(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_addRule({ name: "trim", args: { enabled: enabled2 } }); - }, - validate(value, helpers, { enabled: enabled2 }) { - if (!enabled2 || value === value.trim()) { - return value; - } - return helpers.error("string.trim"); - }, - convert: true - }, - truncate: { - method(enabled2 = true) { - assert2(typeof enabled2 === "boolean", "enabled must be a boolean"); - return this.$_setFlag("truncate", enabled2); - } - }, - uppercase: { - method() { - return this.case("upper"); - } - }, - uri: { - method(options2 = {}) { - Common.assertOptions(options2, ["allowRelative", "allowQuerySquareBrackets", "domain", "relativeOnly", "scheme", "encodeUri"]); - if (options2.domain) { - Common.assertOptions(options2.domain, ["allowFullyQualified", "allowUnicode", "maxDomainSegments", "minDomainSegments", "tlds"]); - } - const { regex, scheme } = uriRegex(options2); - const domain = options2.domain ? internals.addressOptions(options2.domain) : null; - return this.$_addRule({ name: "uri", args: { options: options2 }, regex, domain, scheme }); - }, - validate(value, helpers, { options: options2 }, { regex, domain, scheme }) { - if (["http:/", "https:/"].includes(value)) { - return helpers.error("string.uri"); - } - let match = regex.exec(value); - if (!match && helpers.prefs.convert && options2.encodeUri) { - const encoded = encodeURI(value); - match = regex.exec(encoded); - if (match) { - value = encoded; - } - } - if (match) { - const matched = match[1] || match[2]; - if (domain && (!options2.allowRelative || matched) && !isDomainValid(matched, domain)) { - return helpers.error("string.domain", { value: matched }); - } - return value; + return this.Promise.resolve(total); } - if (options2.relativeOnly) { - return helpers.error("string.uriRelativeOnly"); - } - if (options2.scheme) { - return helpers.error("string.uriCustomScheme", { scheme, value }); - } - return helpers.error("string.uri"); - } - } - }, - manifest: { - build(obj, desc) { - if (desc.replacements) { - for (const { pattern, replacement } of desc.replacements) { - obj = obj.replace(pattern, replacement); - } - } - return obj; - } - }, - messages: { - "string.alphanum": "{{#label}} must only contain alpha-numeric characters", - "string.base": "{{#label}} must be a string", - "string.base64": "{{#label}} must be a valid base64 string", - "string.creditCard": "{{#label}} must be a credit card", - "string.dataUri": "{{#label}} must be a valid dataUri string", - "string.domain": "{{#label}} must contain a valid domain name", - "string.email": "{{#label}} must be a valid email", - "string.empty": "{{#label}} is not allowed to be empty", - "string.guid": "{{#label}} must be a valid GUID", - "string.hex": "{{#label}} must only contain hexadecimal characters", - "string.hexAlign": "{{#label}} hex decoded representation must be byte aligned", - "string.hostname": "{{#label}} must be a valid hostname", - "string.ip": "{{#label}} must be a valid ip address with a {{#cidr}} CIDR", - "string.ipVersion": "{{#label}} must be a valid ip address of one of the following versions {{#version}} with a {{#cidr}} CIDR", - "string.isoDate": "{{#label}} must be in iso format", - "string.isoDuration": "{{#label}} must be a valid ISO 8601 duration", - "string.length": "{{#label}} length must be {{#limit}} characters long", - "string.lowercase": "{{#label}} must only contain lowercase characters", - "string.max": "{{#label}} length must be less than or equal to {{#limit}} characters long", - "string.min": "{{#label}} length must be at least {{#limit}} characters long", - "string.normalize": "{{#label}} must be unicode normalized in the {{#form}} form", - "string.token": "{{#label}} must only contain alpha-numeric and underscore characters", - "string.pattern.base": "{{#label}} with value {:[.]} fails to match the required pattern: {{#regex}}", - "string.pattern.name": "{{#label}} with value {:[.]} fails to match the {{#name}} pattern", - "string.pattern.invert.base": "{{#label}} with value {:[.]} matches the inverted pattern: {{#regex}}", - "string.pattern.invert.name": "{{#label}} with value {:[.]} matches the inverted {{#name}} pattern", - "string.trim": "{{#label}} must not have leading or trailing whitespace", - "string.uri": "{{#label}} must be a valid uri", - "string.uriCustomScheme": "{{#label}} must be a valid uri with a scheme matching the {{#scheme}} pattern", - "string.uriRelativeOnly": "{{#label}} must be a valid relative uri", - "string.uppercase": "{{#label}} must only contain uppercase characters" - } - }); - internals.addressOptions = function(options2) { - if (!options2) { - return internals.tlds || options2; - } - assert2(options2.minDomainSegments === void 0 || Number.isSafeInteger(options2.minDomainSegments) && options2.minDomainSegments > 0, "minDomainSegments must be a positive integer"); - assert2(options2.maxDomainSegments === void 0 || Number.isSafeInteger(options2.maxDomainSegments) && options2.maxDomainSegments > 0, "maxDomainSegments must be a positive integer"); - if (options2.tlds === false) { - return options2; - } - if (options2.tlds === true || options2.tlds === void 0) { - assert2(internals.tlds, "Built-in TLD list disabled"); - return Object.assign({}, options2, internals.tlds); - } - assert2(typeof options2.tlds === "object", "tlds must be true, false, or an object"); - const deny = options2.tlds.deny; - if (deny) { - if (Array.isArray(deny)) { - options2 = Object.assign({}, options2, { tlds: { deny: new Set(deny) } }); + }).catch((e2) => { + return this.Events.trigger("error", e2); + }); } - assert2(options2.tlds.deny instanceof Set, "tlds.deny must be an array, Set, or boolean"); - assert2(!options2.tlds.allow, "Cannot specify both tlds.allow and tlds.deny lists"); - internals.validateTlds(options2.tlds.deny, "tlds.deny"); - return options2; - } - const allow = options2.tlds.allow; - if (!allow) { - return { ...options2, tlds: false }; - } - if (allow === true) { - assert2(internals.tlds, "Built-in TLD list disabled"); - return Object.assign({}, options2, internals.tlds); - } - if (Array.isArray(allow)) { - options2 = Object.assign({}, options2, { tlds: { allow: new Set(allow) } }); - } - assert2(options2.tlds.allow instanceof Set, "tlds.allow must be an array, Set, or boolean"); - internals.validateTlds(options2.tlds.allow, "tlds.allow"); - return options2; - }; - internals.validateTlds = function(set, source) { - for (const tld of set) { - assert2(isDomainValid(tld, { minDomainSegments: 1, maxDomainSegments: 1 }), `${source} must contain valid top level domain names`); - } - }; - internals.isoDate = function(value) { - if (!Common.isIsoDate(value)) { - return null; - } - if (/.*T.*[+-]\d\d$/.test(value)) { - value += "00"; - } - const date3 = new Date(value); - if (isNaN(date3.getTime())) { - return null; - } - return date3.toISOString(); - }; - internals.length = function(schema, name, limit, operator, encoding) { - assert2(!encoding || Buffer && Buffer.isEncoding(encoding), "Invalid encoding:", encoding); - return schema.$_addRule({ name, method: "length", args: { limit, encoding }, operator }); - }; - } -}); -var require_symbol2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/symbol.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var internals = {}; - internals.Map = class extends Map { - slice() { - return new internals.Map(this); - } - }; - module14.exports = Any.extend({ - type: "symbol", - terms: { - map: { init: new internals.Map() } - }, - coerce: { - method(value, { schema, error: error2 }) { - const lookup = schema.$_terms.map.get(value); - if (lookup) { - value = lookup; - } - if (!schema._flags.only || typeof value === "symbol") { - return { value }; - } - return { value, errors: error2("symbol.map", { map: schema.$_terms.map }) }; + _dropAllQueued(message) { + return this._queues.shiftAll(function(job) { + return job.doDrop({ + message + }); + }); } - }, - validate(value, { error: error2 }) { - if (typeof value !== "symbol") { - return { value, errors: error2("symbol.base") }; + stop(options2 = {}) { + var done, waitForExecuting; + options2 = parser3.load(options2, this.stopDefaults); + waitForExecuting = (at) => { + var finished; + finished = () => { + var counts; + counts = this._states.counts; + return counts[0] + counts[1] + counts[2] + counts[3] === at; + }; + return new this.Promise((resolve82, reject) => { + if (finished()) { + return resolve82(); + } else { + return this.on("done", () => { + if (finished()) { + this.removeAllListeners("done"); + return resolve82(); + } + }); + } + }); + }; + done = options2.dropWaitingJobs ? (this._run = function(index, next) { + return next.doDrop({ + message: options2.dropErrorMessage + }); + }, this._drainOne = () => { + return this.Promise.resolve(null); + }, this._registerLock.schedule(() => { + return this._submitLock.schedule(() => { + var k, ref, v2; + ref = this._scheduled; + for (k in ref) { + v2 = ref[k]; + if (this.jobStatus(v2.job.options.id) === "RUNNING") { + clearTimeout(v2.timeout); + clearTimeout(v2.expiration); + v2.job.doDrop({ + message: options2.dropErrorMessage + }); + } + } + this._dropAllQueued(options2.dropErrorMessage); + return waitForExecuting(0); + }); + })) : this.schedule({ + priority: NUM_PRIORITIES - 1, + weight: 0 + }, () => { + return waitForExecuting(1); + }); + this._receive = function(job) { + return job._reject(new Bottleneck3.prototype.BottleneckError(options2.enqueueErrorMessage)); + }; + this.stop = () => { + return this.Promise.reject(new Bottleneck3.prototype.BottleneckError("stop() has already been called")); + }; + return done; } - }, - rules: { - map: { - method(iterable) { - if (iterable && !iterable[Symbol.iterator] && typeof iterable === "object") { - iterable = Object.entries(iterable); + _addToQueue(job) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var args, blocked, error2, options2, reachedHWM, shifted, strategy; + args = job.args; + options2 = job.options; + try { + var _ref2 = yield _this2._store.__submit__(_this2.queued(), options2.weight); + reachedHWM = _ref2.reachedHWM; + blocked = _ref2.blocked; + strategy = _ref2.strategy; + } catch (error1) { + error2 = error1; + _this2.Events.trigger("debug", `Could not queue ${options2.id}`, { + args, + options: options2, + error: error2 + }); + job.doDrop({ + error: error2 + }); + return false; } - assert2(iterable && iterable[Symbol.iterator], "Iterable must be an iterable or object"); - const obj = this.clone(); - const symbols2 = []; - for (const entry of iterable) { - assert2(entry && entry[Symbol.iterator], "Entry must be an iterable"); - const [key, value] = entry; - assert2(typeof key !== "object" && typeof key !== "function" && typeof key !== "symbol", "Key must not be of type object, function, or Symbol"); - assert2(typeof value === "symbol", "Value must be a Symbol"); - obj.$_terms.map.set(key, value); - symbols2.push(value); + if (blocked) { + job.doDrop(); + return true; + } else if (reachedHWM) { + shifted = strategy === Bottleneck3.prototype.strategy.LEAK ? _this2._queues.shiftLastFrom(options2.priority) : strategy === Bottleneck3.prototype.strategy.OVERFLOW_PRIORITY ? _this2._queues.shiftLastFrom(options2.priority + 1) : strategy === Bottleneck3.prototype.strategy.OVERFLOW ? job : void 0; + if (shifted != null) { + shifted.doDrop(); + } + if (shifted == null || strategy === Bottleneck3.prototype.strategy.OVERFLOW) { + if (shifted == null) { + job.doDrop(); + } + return reachedHWM; + } } - return obj.valid(...symbols2); - } - } - }, - manifest: { - build(obj, desc) { - if (desc.map) { - obj = obj.map(desc.map); - } - return obj; + job.doQueue(reachedHWM, blocked); + _this2._queues.push(job); + yield _this2._drainAll(); + return reachedHWM; + })(); } - }, - messages: { - "symbol.base": "{{#label}} must be a symbol", - "symbol.map": "{{#label}} must be one of {{#map}}" - } - }); - } -}); -var require_binary2 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/types/binary.js"(exports2, module14) { - "use strict"; - var { assert: assert2 } = require_lib(); - var Any = require_any2(); - var Common = require_common3(); - module14.exports = Any.extend({ - type: "binary", - coerce: { - from: ["string", "object"], - method(value, { schema }) { - if (typeof value === "string" || value !== null && value.type === "Buffer") { - try { - return { value: Buffer.from(value, schema._flags.encoding) }; - } catch { - } + _receive(job) { + if (this._states.jobStatus(job.options.id) != null) { + job._reject(new Bottleneck3.prototype.BottleneckError(`A job with the same id already exists (id=${job.options.id})`)); + return false; + } else { + job.doReceive(); + return this._submitLock.schedule(this._addToQueue, job); } } - }, - validate(value, { error: error2 }) { - if (!Buffer.isBuffer(value)) { - return { value, errors: error2("binary.base") }; - } - }, - rules: { - encoding: { - method(encoding) { - assert2(Buffer.isEncoding(encoding), "Invalid encoding:", encoding); - return this.$_setFlag("encoding", encoding); + submit(...args) { + var cb, fn, job, options2, ref, ref1, task; + if (typeof args[0] === "function") { + var _ref3, _ref4, _splice$call, _splice$call2; + ref = args, _ref3 = ref, _ref4 = _toArray(_ref3), fn = _ref4[0], args = _ref4.slice(1), _ref3, _splice$call = splice.call(args, -1), _splice$call2 = _slicedToArray2(_splice$call, 1), cb = _splice$call2[0], _splice$call; + options2 = parser3.load({}, this.jobDefaults); + } else { + var _ref5, _ref6, _splice$call3, _splice$call4; + ref1 = args, _ref5 = ref1, _ref6 = _toArray(_ref5), options2 = _ref6[0], fn = _ref6[1], args = _ref6.slice(2), _ref5, _splice$call3 = splice.call(args, -1), _splice$call4 = _slicedToArray2(_splice$call3, 1), cb = _splice$call4[0], _splice$call3; + options2 = parser3.load(options2, this.jobDefaults); } - }, - length: { - method(limit) { - return this.$_addRule({ name: "length", method: "length", args: { limit }, operator: "=" }); - }, - validate(value, helpers, { limit }, { name, operator, args }) { - if (Common.compare(value.length, limit, operator)) { - return value; - } - return helpers.error("binary." + name, { limit: args.limit, value }); - }, - args: [ - { - name: "limit", - ref: true, - assert: Common.limit, - message: "must be a positive integer" + task = (...args2) => { + return new this.Promise(function(resolve82, reject) { + return fn(...args2, function(...args3) { + return (args3[0] != null ? reject : resolve82)(args3); + }); + }); + }; + job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + job.promise.then(function(args2) { + return typeof cb === "function" ? cb(...args2) : void 0; + }).catch(function(args2) { + if (Array.isArray(args2)) { + return typeof cb === "function" ? cb(...args2) : void 0; + } else { + return typeof cb === "function" ? cb(args2) : void 0; } - ] - }, - max: { - method(limit) { - return this.$_addRule({ name: "max", method: "length", args: { limit }, operator: "<=" }); - } - }, - min: { - method(limit) { - return this.$_addRule({ name: "min", method: "length", args: { limit }, operator: ">=" }); - } + }); + return this._receive(job); } - }, - cast: { - string: { - from: (value) => Buffer.isBuffer(value), - to(value, helpers) { - return value.toString(); + schedule(...args) { + var job, options2, task; + if (typeof args[0] === "function") { + var _args = args; + var _args2 = _toArray(_args); + task = _args2[0]; + args = _args2.slice(1); + options2 = {}; + } else { + var _args3 = args; + var _args4 = _toArray(_args3); + options2 = _args4[0]; + task = _args4[1]; + args = _args4.slice(2); } + job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + this._receive(job); + return job.promise; } - }, - messages: { - "binary.base": "{{#label}} must be a buffer or a string", - "binary.length": "{{#label}} must be {{#limit}} bytes", - "binary.max": "{{#label}} must be less than or equal to {{#limit}} bytes", - "binary.min": "{{#label}} must be at least {{#limit}} bytes" - } - }); - } -}); -var require_lib39 = __commonJS({ - "node_modules/.deno/joi@18.0.1/node_modules/joi/lib/index.js"(exports2, module14) { - "use strict"; - var { assert: assert2, clone: clone2 } = require_lib(); - var Cache = require_cache2(); - var Common = require_common3(); - var Compile = require_compile2(); - var Errors = require_errors3(); - var Extend = require_extend2(); - var Manifest = require_manifest(); - var Ref = require_ref2(); - var Template = require_template2(); - var Trace = require_trace(); - var Schemas; - var internals = { - types: { - alternatives: require_alternatives2(), - any: require_any2(), - array: require_array2(), - boolean: require_boolean2(), - date: require_date2(), - function: require_function2(), - link: require_link2(), - number: require_number2(), - object: require_object2(), - string: require_string2(), - symbol: require_symbol2() - }, - aliases: { - alt: "alternatives", - bool: "boolean", - func: "function" - } - }; - if (Buffer) { - internals.types.binary = require_binary2(); - } - internals.root = function() { - const root = { - _types: new Set(Object.keys(internals.types)) - }; - for (const type of root._types) { - root[type] = function(...args) { - assert2(!args.length || ["alternatives", "link", "object"].includes(type), "The", type, "type does not allow arguments"); - return internals.generate(this, internals.types[type], args); - }; - } - for (const method of ["allow", "custom", "disallow", "equal", "exist", "forbidden", "invalid", "not", "only", "optional", "options", "prefs", "preferences", "required", "strip", "valid", "when"]) { - root[method] = function(...args) { - return this.any()[method](...args); - }; - } - Object.assign(root, internals.methods); - for (const alias in internals.aliases) { - const target = internals.aliases[alias]; - root[alias] = root[target]; - } - root.x = root.expression; - if (Trace.setup) { - Trace.setup(root); - } - return root; - }; - internals.methods = { - ValidationError: Errors.ValidationError, - version: Common.version, - cache: Cache.provider, - assert(value, schema, ...args) { - internals.assert(value, schema, true, args); - }, - attempt(value, schema, ...args) { - return internals.assert(value, schema, false, args); - }, - build(desc) { - assert2(typeof Manifest.build === "function", "Manifest functionality disabled"); - return Manifest.build(this, desc); - }, - checkPreferences(prefs) { - Common.checkPreferences(prefs); - }, - compile(schema, options2) { - return Compile.compile(this, schema, options2); - }, - defaults(modifier) { - assert2(typeof modifier === "function", "modifier must be a function"); - const joi = Object.assign({}, this); - for (const type of joi._types) { - const schema = modifier(joi[type]()); - assert2(Common.isSchema(schema), "modifier must return a valid schema object"); - joi[type] = function(...args) { - return internals.generate(this, schema, args); + wrap(fn) { + var schedule, wrapped; + schedule = this.schedule.bind(this); + wrapped = function wrapped2(...args) { + return schedule(fn.bind(this), ...args); }; + wrapped.withOptions = function(options2, ...args) { + return schedule(options2, fn, ...args); + }; + return wrapped; } - return joi; - }, - expression(...args) { - return new Template(...args); - }, - extend(...extensions) { - Common.verifyFlat(extensions, "extend"); - Schemas = Schemas || require_schemas2(); - assert2(extensions.length, "You need to provide at least one extension"); - this.assert(extensions, Schemas.extensions); - const joi = Object.assign({}, this); - joi._types = new Set(joi._types); - for (let extension of extensions) { - if (typeof extension === "function") { - extension = extension(joi); - } - this.assert(extension, Schemas.extension); - const expanded = internals.expandExtension(extension, joi); - for (const item of expanded) { - assert2(joi[item.type] === void 0 || joi._types.has(item.type), "Cannot override name", item.type); - const base2 = item.base || this.any(); - const schema = Extend.type(base2, item); - joi._types.add(item.type); - joi[item.type] = function(...args) { - return internals.generate(this, schema, args); - }; - } + updateSettings(options2 = {}) { + var _this3 = this; + return _asyncToGenerator2(function* () { + yield _this3._store.__updateSettings__(parser3.overwrite(options2, _this3.storeDefaults)); + parser3.overwrite(options2, _this3.instanceDefaults, _this3); + return _this3; + })(); } - return joi; - }, - isError: Errors.ValidationError.isError, - isExpression: Template.isTemplate, - isRef: Ref.isRef, - isSchema: Common.isSchema, - in(...args) { - return Ref.in(...args); - }, - override: Common.symbols.override, - ref(...args) { - return Ref.create(...args); - }, - types() { - const types = {}; - for (const type of this._types) { - types[type] = this[type](); + currentReservoir() { + return this._store.__currentReservoir__(); } - for (const target in internals.aliases) { - types[target] = this[target](); + incrementReservoir(incr = 0) { + return this._store.__incrementReservoir__(incr); } - return types; - } - }; - internals.assert = function(value, schema, annotate, args) { - const message = args[0] instanceof Error || typeof args[0] === "string" ? args[0] : null; - const options2 = message !== null ? args[1] : args[0]; - const result = schema.validate(value, Common.preferences({ errors: { stack: true } }, options2 || {})); - let error2 = result.error; - if (!error2) { - return result.value; - } - if (message instanceof Error) { - throw message; - } - const display = annotate && typeof error2.annotate === "function" ? error2.annotate() : error2.message; - if (error2 instanceof Errors.ValidationError === false) { - error2 = clone2(error2); } - error2.message = message ? `${message} ${display}` : display; - throw error2; - }; - internals.generate = function(root, schema, args) { - assert2(root, "Must be invoked on a Joi instance."); - schema.$_root = root; - if (!schema._definition.args || !args.length) { - return schema; - } - return schema._definition.args(schema, ...args); - }; - internals.expandExtension = function(extension, joi) { - if (typeof extension.type === "string") { - return [extension]; - } - const extended = []; - for (const type of joi._types) { - if (extension.type.test(type)) { - const item = Object.assign({}, extension); - item.type = type; - item.base = joi[type](); - extended.push(item); + ; + Bottleneck3.default = Bottleneck3; + Bottleneck3.Events = Events2; + Bottleneck3.version = Bottleneck3.prototype.version = require_version().version; + Bottleneck3.strategy = Bottleneck3.prototype.strategy = { + LEAK: 1, + OVERFLOW: 2, + OVERFLOW_PRIORITY: 4, + BLOCK: 3 + }; + Bottleneck3.BottleneckError = Bottleneck3.prototype.BottleneckError = require_BottleneckError(); + Bottleneck3.Group = Bottleneck3.prototype.Group = require_Group(); + Bottleneck3.RedisConnection = Bottleneck3.prototype.RedisConnection = require_RedisConnection(); + Bottleneck3.IORedisConnection = Bottleneck3.prototype.IORedisConnection = require_IORedisConnection(); + Bottleneck3.Batcher = Bottleneck3.prototype.Batcher = require_Batcher(); + Bottleneck3.prototype.jobDefaults = { + priority: DEFAULT_PRIORITY, + weight: 1, + expiration: null, + id: "" + }; + Bottleneck3.prototype.storeDefaults = { + maxConcurrent: null, + minTime: 0, + highWater: null, + strategy: Bottleneck3.prototype.strategy.LEAK, + penalty: null, + reservoir: null, + reservoirRefreshInterval: null, + reservoirRefreshAmount: null, + reservoirIncreaseInterval: null, + reservoirIncreaseAmount: null, + reservoirIncreaseMaximum: null + }; + Bottleneck3.prototype.localStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 250 + }; + Bottleneck3.prototype.redisStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 5e3, + clientTimeout: 1e4, + Redis: null, + clientOptions: {}, + clusterNodes: null, + clearDatastore: false, + connection: null + }; + Bottleneck3.prototype.instanceDefaults = { + datastore: "local", + connection: null, + id: "", + rejectOnDrop: true, + trackDoneStatus: false, + Promise + }; + Bottleneck3.prototype.stopDefaults = { + enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", + dropWaitingJobs: true, + dropErrorMessage: "This limiter has been stopped." + }; + return Bottleneck3; + }.call(void 0); + module14.exports = Bottleneck2; + } +}); +var require_lib6 = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/index.js"(exports2, module14) { + "use strict"; + module14.exports = require_Bottleneck(); + } +}); +var getConnInfo2; +var init_conninfo2 = __esm({ + "node_modules/.deno/@hono+node-server@1.19.14/node_modules/@hono/node-server/dist/conninfo.mjs"() { + getConnInfo2 = (c) => { + const bindings = c.env.server ? c.env.server : c.env; + const address = bindings.incoming.socket.remoteAddress; + const port = bindings.incoming.socket.remotePort; + const family = bindings.incoming.socket.remoteFamily; + return { + remote: { + address, + port, + addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0 } + }; + }; + } +}); +function extractBearer(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "bearer "; + if (authorization.slice(0, prefix.length) !== prefix) return null; + return { token: authorization.slice(prefix.length) }; +} +function extractShelter(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "shelter "; + if (authorization.slice(0, prefix.length) !== prefix) return null; + try { + const billableContractID = verifyShelterAuthorizationHeader(authorization); + return { billableContractID }; + } catch (e2) { + console.warn(e2, "Shelter authorization failed"); + return null; + } +} +function authMiddleware(strategies, mode = "required") { + const strategyList = Array.isArray(strategies) ? strategies : [strategies]; + return async (c, next) => { + for (const strategy of strategyList) { + const extractor = extractors[strategy]; + if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`); + const credentials = extractor(c); + if (credentials) { + c.set("credentials", credentials); + c.set("authStrategy", strategy); + return next(); } - return extended; + } + if (mode === "optional") { + c.set("credentials", {}); + c.set("authStrategy", ""); + return next(); + } + throw new HTTPException(401, { message: "Unauthorized" }); + }; +} +var extractors; +var init_auth = __esm({ + "src/serve/auth.ts"() { + "use strict"; + init_utils(); + init_http_exception(); + extractors = { + "chel-bearer": extractBearer, + "chel-shelter": extractShelter }; - module14.exports = internals.root(); } }); var routes_exports = {}; -function notFoundNoCache(h2) { - return h2.response().code(404).header("Cache-Control", "no-store"); +__export(routes_exports, { + staticServeConfig: () => staticServeConfig +}); +function getClientIP(c) { + const headerIP = c.req.header("x-real-ip"); + if (headerIP) return headerIP; + try { + const info = getConnInfo2(c); + return info.remote.address || "unknown"; + } catch { + return "unknown"; + } +} +function notFoundNoCache(c) { + return c.body(null, 404, { "Cache-Control": "no-store" }); } -var import_boom3; var import_npm_bottleneck; var import_npm_chalk2; -var import_npm_joi; var import_npm_nconf5; var MEGABYTE; var SECOND; @@ -107663,7 +72680,7 @@ var appDir; var dashboardDir; var staticServeConfig; var errorMapper; -var route; +var app; var init_routes = __esm({ "src/serve/routes.ts"() { "use strict"; @@ -107671,16 +72688,17 @@ var init_routes = __esm({ init_chelonia(); init_functions(); init_persistent_actions(); - import_boom3 = __toESM(require_lib2()); init_esm(); - import_npm_bottleneck = __toESM(require_lib36()); + import_npm_bottleneck = __toESM(require_lib6()); import_npm_chalk2 = __toESM(require_source()); - import_npm_joi = __toESM(require_lib39()); + init_http_exception(); + init_conninfo2(); init_database(); init_instance_keys(); init_logger(); init_zkppSalt(); import_npm_nconf5 = __toESM(require_nconf()); + init_auth(); MEGABYTE = 1048576; SECOND = 1e3; CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; @@ -107781,168 +72799,162 @@ var init_routes = __esm({ errorMapper = (e2) => { switch (e2?.name) { case "BackendErrorNotFound": - return import_boom3.default.notFound(); + throw new HTTPException(404); case "BackendErrorGone": - return import_boom3.default.resourceGone(); + throw new HTTPException(410); case "BackendErrorBadData": - return import_boom3.default.badData(e2.message); + throw new HTTPException(422, { message: e2.message }); default: console.error(e2, "Unexpected backend error"); - return import_boom3.default.internal(e2.message ?? "internal error"); + throw new HTTPException(500, { message: e2.message ?? "internal error" }); } }; - route = new Proxy({}, { - get: function(_obj, prop) { - return function(path8, options2, handler) { - esm_default("okTurtles.data/apply", SERVER_INSTANCE, function(server) { - server.route({ path: path8, method: prop, options: options2, handler }); - }); - }; - } - }); - route.POST("/event", { - auth: { - strategy: "chel-shelter", - mode: "optional" - }, - validate: { - headers: import_npm_joi.default.object({ - "shelter-namespace-registration": import_npm_joi.default.string().regex(NAME_REGEX) - }), - options: { - allowUnknown: true - }, - payload: import_npm_joi.default.string().required() - } - }, async function(request) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const ip = request.headers["x-real-ip"] || request.info.remoteAddress; - try { - const deserializedHEAD = SPMessage.deserializeHEAD(request.payload); + app = esm_default("okTurtles.data/get", SERVER_INSTANCE); + app.post( + "/event", + authMiddleware("chel-shelter", "optional"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const ip = getClientIP(c); try { - const parsed = maybeParseCID(deserializedHEAD.head.manifest); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { - return import_boom3.default.badData("Invalid manifest"); - } - const credentials = request.auth.credentials; - if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { - const manifest2 = await esm_default("chelonia.db/get", deserializedHEAD.head.manifest); - const parsedManifest = JSON.parse(manifest2); - const { name } = JSON.parse(parsedManifest.body); - if (name !== "gi.contracts/identity") { - return import_boom3.default.unauthorized("This contract type requires ownership information", "shelter"); - } - if (import_npm_nconf5.default.get("server:signup:disabled")) { - return import_boom3.default.forbidden("Registration disabled"); - } - if (!SIGNUP_LIMIT_DISABLED) { - try { - const keyedIp = limiterKey(ip); - await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()); - await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()); - await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()); - } catch { - console.warn("rate limit hit for IP:", ip); - throw import_boom3.default.tooManyRequests("Rate limit exceeded"); - } - } - } - const saltUpdateToken = request.headers["shelter-salt-update-token"]; - let updateSalts; - if (saltUpdateToken) { - updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken); + const payload = await c.req.text(); + if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); + const namespaceRegistration = c.req.header("shelter-namespace-registration"); + if (namespaceRegistration && !NAME_REGEX.test(namespaceRegistration)) { + throw new HTTPException(400, { message: "Invalid shelter-namespace-registration header" }); } - await esm_default("backend/server/handleEntry", deserializedHEAD, request.payload); - await updateSalts?.(deserializedHEAD.hash); - if (deserializedHEAD.isFirstMessage) { - if (credentials?.billableContractID) { - await esm_default("backend/server/saveOwner", credentials.billableContractID, deserializedHEAD.contractID); - } else { - await esm_default("backend/server/registerBillableEntity", deserializedHEAD.contractID); - } - const name = request.headers["shelter-namespace-registration"]; - if (name) { - const cheloniaState = esm_default("chelonia/rootState"); - if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === "gi.contracts/identity") { - const r = await esm_default("backend/db/registerName", name, deserializedHEAD.contractID); - if (import_boom3.default.isBoom(r)) { - return r; + const deserializedHEAD = SPMessage.deserializeHEAD(payload); + try { + const parsed = maybeParseCID(deserializedHEAD.head.manifest); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { + throw new HTTPException(422, { message: "Invalid manifest" }); + } + const credentials = c.get("credentials"); + if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { + const manifest2 = await esm_default("chelonia.db/get", deserializedHEAD.head.manifest); + const parsedManifest = JSON.parse(manifest2); + const { name } = JSON.parse(parsedManifest.body); + if (name !== "gi.contracts/identity") { + throw new HTTPException(401, { message: "This contract type requires ownership information" }); + } + if (import_npm_nconf5.default.get("server:signup:disabled")) { + throw new HTTPException(403, { message: "Registration disabled" }); + } + if (!SIGNUP_LIMIT_DISABLED) { + try { + const keyedIp = limiterKey(ip); + await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()); + await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()); + await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()); + } catch { + console.warn("rate limit hit for IP:", ip); + throw new HTTPException(429, { message: "Rate limit exceeded" }); } - const saltRegistrationToken = request.headers["shelter-salt-registration-token"]; - console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`); - if (saltRegistrationToken) { - await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken); + } + } + const saltUpdateToken = c.req.header("shelter-salt-update-token"); + let updateSalts; + if (saltUpdateToken) { + updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken); + } + await esm_default("backend/server/handleEntry", deserializedHEAD, payload); + await updateSalts?.(deserializedHEAD.hash); + if (deserializedHEAD.isFirstMessage) { + if (credentials?.billableContractID) { + await esm_default("backend/server/saveOwner", credentials.billableContractID, deserializedHEAD.contractID); + } else { + await esm_default("backend/server/registerBillableEntity", deserializedHEAD.contractID); + } + const name = c.req.header("shelter-namespace-registration"); + if (name) { + const cheloniaState = esm_default("chelonia/rootState"); + if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === "gi.contracts/identity") { + try { + await esm_default("backend/db/registerName", name, deserializedHEAD.contractID); + } catch (registerErr) { + if (registerErr.name === "BackendErrorConflict") { + throw new HTTPException(409, { message: "Name already exists" }); + } + throw registerErr; + } + const saltRegistrationToken = c.req.header("shelter-salt-registration-token"); + console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`); + if (saltRegistrationToken) { + await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken); + } } } + const deletionTokenDgst = c.req.header("shelter-deletion-token-digest"); + if (deletionTokenDgst) { + await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst); + } } - const deletionTokenDgst = request.headers["shelter-deletion-token-digest"]; - if (deletionTokenDgst) { - await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst); + await esm_default("backend/server/updateSize", deserializedHEAD.contractID, Buffer15.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : void 0); + } catch (err) { + if (err instanceof HTTPException) throw err; + console.error(err, import_npm_chalk2.default.bold.yellow(err.name)); + if (err.name === "ChelErrorDBBadPreviousHEAD" || err.name === "ChelErrorAlreadyProcessed") { + const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", deserializedHEAD.contractID) ?? { HEAD: null, height: 0 }; + return c.json({ message: err.message, data: { HEADinfo } }, 409, { + "shelter-headinfo-head": HEADinfo.HEAD, + "shelter-headinfo-height": String(HEADinfo.height) + }); + } else if (err.name === "ChelErrorSignatureError") { + throw new HTTPException(422, { message: "Invalid signature" }); + } else if (err.name === "ChelErrorSignatureKeyUnauthorized") { + throw new HTTPException(403, { message: "Unauthorized signing key" }); } + throw err; } - await esm_default("backend/server/updateSize", deserializedHEAD.contractID, Buffer15.byteLength(request.payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : void 0); + return c.text(deserializedHEAD.hash); } catch (err) { - console.error(err, import_npm_chalk2.default.bold.yellow(err.name)); - if (err.name === "ChelErrorDBBadPreviousHEAD" || err.name === "ChelErrorAlreadyProcessed") { - const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", deserializedHEAD.contractID) ?? { HEAD: null, height: 0 }; - const r = import_boom3.default.conflict(err.message, { HEADinfo }); - Object.assign(r.output.headers, { - "shelter-headinfo-head": HEADinfo.HEAD, - "shelter-headinfo-height": HEADinfo.height - }); - return r; - } else if (err.name === "ChelErrorSignatureError") { - return import_boom3.default.badData("Invalid signature"); - } else if (err.name === "ChelErrorSignatureKeyUnauthorized") { - return import_boom3.default.forbidden("Unauthorized signing key"); - } + if (err instanceof HTTPException) throw err; + err.ip = ip; + logger_default.error(err, "POST /event", err.message); throw err; } - return deserializedHEAD.hash; - } catch (err) { - err.ip = ip; - logger_default.error(err, "POST /event", err.message); - return err; - } - }); - route.GET("/eventsAfter/{contractID}/{since}/{limit?}", { - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required(), - since: import_npm_joi.default.string().regex(POSITIVE_INTEGER_REGEX).required(), - limit: import_npm_joi.default.string().regex(POSITIVE_INTEGER_REGEX) - }), - query: import_npm_joi.default.object({ - keyOps: import_npm_joi.default.boolean() - }) } - }, async function(request) { - const { contractID, since, limit } = request.params; - const ip = request.headers["x-real-ip"] || request.info.remoteAddress; - try { - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return import_boom3.default.badRequest(); + ); + app.get( + "/eventsAfter/:contractID/:since/:limit?", + async function(c) { + const contractID = c.req.param("contractID"); + const since = c.req.param("since"); + const limit = c.req.param("limit"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + if (!POSITIVE_INTEGER_REGEX.test(since)) throw new HTTPException(400, { message: "Invalid since" }); + if (limit !== void 0 && !POSITIVE_INTEGER_REGEX.test(limit)) throw new HTTPException(400, { message: "Invalid limit" }); + const keyOps2 = c.req.query("keyOps"); + const ip = getClientIP(c); + try { + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); + } + const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: keyOps2 === "true" }); + c.req.raw.signal.addEventListener("abort", () => stream.destroy()); + const streamHeaders = stream.headers || {}; + const webStream = Readable3.toWeb(stream); + return new Response(webStream, { + headers: { "content-type": "application/octet-stream", ...streamHeaders } + }); + } catch (err) { + if (err instanceof HTTPException) throw err; + err.ip = ip; + logger_default.error(err, `GET /eventsAfter/${contractID}/${since}`, err.message); + errorMapper(err); } - const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: !!request.query["keyOps"] }); - request.events.once("disconnect", stream.destroy.bind(stream)); - return stream; - } catch (err) { - err.ip = ip; - logger_default.error(err, `GET /eventsAfter/${contractID}/${since}`, err.message); - return err; } - }); - route.GET("/ownResources", { - auth: { - strategies: ["chel-shelter"], - mode: "required" - } - }, async function(request) { - const billableContractID = request.auth.credentials.billableContractID; - const resources = (await esm_default("chelonia.db/get", `_private_resources_${billableContractID}`))?.split("\0"); - return resources || []; - }); + ); + app.get( + "/ownResources", + authMiddleware("chel-shelter", "required"), + async function(c) { + const billableContractID = c.get("credentials").billableContractID; + const resources = (await esm_default("chelonia.db/get", `_private_resources_${billableContractID}`))?.split("\0"); + return c.json(resources || []); + } + ); if (process9.env.NODE_ENV === "development") { const levelToColor = { error: import_npm_chalk2.default.bold.red, @@ -107951,616 +72963,605 @@ var init_routes = __esm({ info: import_npm_chalk2.default.green, debug: import_npm_chalk2.default.blue }; - route.POST("/log", { - validate: { - payload: import_npm_joi.default.object({ - level: import_npm_joi.default.string().required(), - value: import_npm_joi.default.string().required() - }) - } - }, function(request, h2) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const ip = request.headers["x-real-ip"] || request.info.remoteAddress; - const log2 = levelToColor[request.payload.level]; - console.debug(import_npm_chalk2.default.bold.yellow(`REMOTE LOG (${ip}): `) + log2(`[${request.payload.level}] ${request.payload.value}`)); - return h2.response().code(200); + app.post("/log", async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const body = await c.req.json(); + if (!body.level || !body.value) throw new HTTPException(400, { message: "level and value are required" }); + const ip = getClientIP(c); + const log2 = levelToColor[body.level]; + console.debug(import_npm_chalk2.default.bold.yellow(`REMOTE LOG (${ip}): `) + log2(`[${body.level}] ${body.value}`)); + return c.body(null, 200); }); } - route.GET("/name/{name}", { - validate: { - params: import_npm_joi.default.object({ - name: import_npm_joi.default.string().regex(NAME_REGEX).required() - }) - } - }, async function(request, h2) { - const { name } = request.params; + app.get("/name/:name", async function(c) { + const name = c.req.param("name"); + if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: "Invalid name" }); try { const lookupResult = await esm_default("backend/db/lookupName", name); - return lookupResult ? h2.response(lookupResult).type("text/plain") : notFoundNoCache(h2); + return lookupResult ? c.text(lookupResult) : notFoundNoCache(c); } catch (err) { logger_default.error(err, `GET /name/${name}`, err.message); - return err; + throw err; } }); - route.GET("/latestHEADinfo/{contractID}", { - cache: { otherwise: "no-store" }, - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required() - }) - } - }, async function(request, h2) { - const { contractID } = request.params; + app.get("/latestHEADinfo/:contractID", async function(c) { + const contractID = c.req.param("contractID"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); try { const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) return import_boom3.default.badRequest(); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400); const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); if (HEADinfo === "") { - return import_boom3.default.resourceGone(); + throw new HTTPException(410); } if (!HEADinfo) { console.warn(`[backend] latestHEADinfo not found for ${contractID}`); - return notFoundNoCache(h2); + return notFoundNoCache(c); } - return HEADinfo; + return c.json(HEADinfo, 200, { "Cache-Control": "no-store" }); } catch (err) { + if (err instanceof HTTPException) throw err; logger_default.error(err, `GET /latestHEADinfo/${contractID}`, err.message); - return err; + throw err; } }); - route.GET("/time", {}, function(_request, h2) { - return h2.response((/* @__PURE__ */ new Date()).toISOString()).header("cache-control", "no-store").type("text/plain"); + app.get("/time", function(c) { + return c.text((/* @__PURE__ */ new Date()).toISOString(), 200, { + "Cache-Control": "no-store" + }); }); - route.POST( - "/streams-test", - { - payload: { - parse: false - } - }, - function(request, h2) { - if (request.payload.byteLength === 2 && Buffer15.from(request.payload).toString() === "ok") { - return h2.response().code(204); - } else { - return import_boom3.default.badRequest(); - } + app.post("/streams-test", async function(c) { + const raw2 = await c.req.arrayBuffer(); + const buf2 = Buffer15.from(raw2); + if (buf2.byteLength === 2 && buf2.toString() === "ok") { + return c.body(null, 204); + } else { + throw new HTTPException(400); } - ); + }); if (process9.env.NODE_ENV === "development") { - route.POST("/dev-file", { - payload: { - output: "data", - multipart: true, - allow: "multipart/form-data", - failAction: function(_request, _h, err) { - console.error("failAction error:", err); - return import_boom3.default.isBoom(err) ? err : import_boom3.default.boomify(err instanceof Error ? err : new Error(err)); - }, - maxBytes: 6 * MEGABYTE, - // TODO: make this a configurable setting - timeout: 10 * SECOND - // TODO: make this a configurable setting - } - }, async function(request) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); + app.post("/dev-file", async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { console.log("FILE UPLOAD!"); - const { hash: hash3, data } = request.payload; - if (!hash3) return import_boom3.default.badRequest("missing hash"); - if (!data) return import_boom3.default.badRequest("missing data"); + const formData = await c.req.parseBody({ all: true }); + const hash3 = formData["hash"]; + const data = formData["data"]; + if (!hash3) throw new HTTPException(400, { message: "missing hash" }); + if (!data) throw new HTTPException(400, { message: "missing data" }); const parsed = maybeParseCID(hash3); - if (!parsed) return import_boom3.default.badRequest("invalid hash"); + if (!parsed) throw new HTTPException(400, { message: "invalid hash" }); const ourHash = createCID(data, parsed.code); if (ourHash !== hash3) { console.error(`hash(${hash3}) != ourHash(${ourHash})`); - return import_boom3.default.badRequest("bad hash!"); + throw new HTTPException(400, { message: "bad hash!" }); } await esm_default("chelonia.db/set", hash3, data); - return "/file/" + hash3; + return c.text("/file/" + hash3); } catch (err) { + if (err instanceof HTTPException) throw err; logger_default.error(err); - return import_boom3.default.internal("File upload failed"); + throw new HTTPException(500, { message: "File upload failed" }); } }); } - route.POST("/file", { - auth: { - strategies: ["chel-shelter"], - mode: "required" - }, - payload: { - parse: true, - output: "stream", - multipart: { output: "annotated" }, - allow: "multipart/form-data", - failAction: function(_request, _h, err) { - console.error(err, "failAction error"); - return import_boom3.default.isBoom(err) ? err : import_boom3.default.boomify(err instanceof Error ? err : new Error(err)); - }, - maxBytes: FILE_UPLOAD_MAX_BYTES, - timeout: 10 * SECOND - // TODO: make this a configurable setting - } - }, async function(request, h2) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - try { - console.info("FILE UPLOAD!"); - const credentials = request.auth.credentials; - if (!credentials?.billableContractID) { - return import_boom3.default.unauthorized("Uploading files requires ownership information", "shelter"); - } - const manifestMeta = request.payload["manifest"]; - if (typeof manifestMeta !== "object") return import_boom3.default.badRequest("missing manifest"); - if (manifestMeta.filename !== "manifest.json") return import_boom3.default.badRequest("wrong manifest filename"); - if (!(manifestMeta.payload instanceof Uint8Array)) return import_boom3.default.badRequest("wrong manifest format"); - const manifest2 = (() => { - try { - return JSON.parse(Buffer15.from(manifestMeta.payload).toString()); - } catch { - throw import_boom3.default.badData("Error parsing manifest"); + app.post( + "/file", + authMiddleware("chel-shelter", "required"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + try { + console.info("FILE UPLOAD!"); + const credentials = c.get("credentials"); + if (!credentials?.billableContractID) { + throw new HTTPException(401, { message: "Uploading files requires ownership information" }); + } + const contentType = c.req.header("content-type") || ""; + if (!contentType.includes("multipart/form-data")) { + throw new HTTPException(400, { message: "Expected multipart/form-data" }); + } + const contentLength = parseInt(c.req.header("content-length") || "0", 10); + if (contentLength > FILE_UPLOAD_MAX_BYTES) { + throw new HTTPException(413, { message: "Payload too large" }); + } + const formData = await c.req.formData(); + const manifestFile = formData.get("manifest"); + if (!manifestFile) throw new HTTPException(400, { message: "missing manifest" }); + if (manifestFile.name !== "manifest.json") throw new HTTPException(400, { message: "wrong manifest filename" }); + const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()); + const manifest2 = (() => { + try { + return JSON.parse(Buffer15.from(manifestPayload).toString()); + } catch { + throw new HTTPException(422, { message: "Error parsing manifest" }); + } + })(); + if (typeof manifest2 !== "object") throw new HTTPException(422, { message: "manifest format is invalid" }); + if (manifest2.version !== "1.0.0") throw new HTTPException(422, { message: "unsupported manifest version" }); + if (manifest2.cipher !== "aes256gcm") throw new HTTPException(422, { message: "unsupported cipher" }); + if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new HTTPException(422, { message: "missing chunks" }); + const chunkFiles = []; + for (let i2 = 0; ; i2++) { + const chunkFile = formData.get(String(i2)); + if (!chunkFile) break; + chunkFiles.push(chunkFile); + } + let ourSize = 0; + const chunks = await Promise.all(manifest2.chunks.map(async (chunk, i2) => { + if (!Array.isArray(chunk) || chunk.length !== 2 || typeof chunk[0] !== "number" || typeof chunk[1] !== "string" || !Number.isSafeInteger(chunk[0]) || chunk[0] <= 0) { + throw new HTTPException(422, { message: "bad chunk description" }); + } + if (!chunkFiles[i2]) { + throw new HTTPException(400, { message: "chunk missing in submitted data" }); + } + const chunkPayload = new Uint8Array(await chunkFiles[i2].arrayBuffer()); + const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK); + if (chunkPayload.byteLength !== chunk[0]) { + throw new HTTPException(400, { message: "bad chunk size" }); + } + if (ourHash !== chunk[1]) { + throw new HTTPException(400, { message: "bad chunk hash" }); + } + ourSize += chunk[0]; + return [ourHash, chunkPayload]; + })); + if (ourSize !== manifest2.size) throw new HTTPException(400, { message: "Mismatched total size" }); + const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST); + if (await esm_default("chelonia.db/get", manifestHash)) { + throw new Error(`Manifest ${manifestHash} already exists`); } - })(); - if (typeof manifest2 !== "object") return import_boom3.default.badData("manifest format is invalid"); - if (manifest2.version !== "1.0.0") return import_boom3.default.badData("unsupported manifest version"); - if (manifest2.cipher !== "aes256gcm") return import_boom3.default.badData("unsupported cipher"); - if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) return import_boom3.default.badData("missing chunks"); - let ourSize = 0; - const chunks = manifest2.chunks.map((chunk, i2) => { - if (!Array.isArray(chunk) || chunk.length !== 2 || typeof chunk[0] !== "number" || typeof chunk[1] !== "string" || !Number.isSafeInteger(chunk[0]) || chunk[0] <= 0) { - throw import_boom3.default.badData("bad chunk description"); - } - if (!request.payload[i2] || !(request.payload[i2].payload instanceof Uint8Array)) { - throw import_boom3.default.badRequest("chunk missing in submitted data"); - } - const ourHash = createCID(request.payload[i2].payload, multicodes.SHELTER_FILE_CHUNK); - if (request.payload[i2].payload.byteLength !== chunk[0]) { - throw import_boom3.default.badRequest("bad chunk size"); - } - if (ourHash !== chunk[1]) { - throw import_boom3.default.badRequest("bad chunk hash"); - } - ourSize += chunk[0]; - return [ourHash, request.payload[i2].payload]; - }); - if (ourSize !== manifest2.size) return import_boom3.default.badRequest("Mismatched total size"); - const manifestHash = createCID(manifestMeta.payload, multicodes.SHELTER_FILE_MANIFEST); - if (await esm_default("chelonia.db/get", manifestHash)) { - throw new Error(`Manifest ${manifestHash} already exists`); + await Promise.all(chunks.map(async ([cid]) => { + const exists = !!await esm_default("chelonia.db/get", cid); + if (exists) { + throw new Error(`Chunk ${cid} already exists`); + } + })); + await Promise.all(chunks.map(([cid, data]) => esm_default("chelonia.db/set", cid, data))); + await esm_default("chelonia.db/set", manifestHash, manifestPayload); + await esm_default("backend/server/saveOwner", credentials.billableContractID, manifestHash); + const size = manifest2.size + manifestPayload.byteLength; + await esm_default("backend/server/updateSize", manifestHash, size); + await esm_default("backend/server/updateContractFilesTotalSize", credentials.billableContractID, size); + const deletionTokenDgst = c.req.header("shelter-deletion-token-digest"); + if (deletionTokenDgst) { + await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst); + } + return c.text(manifestHash); + } catch (err) { + if (err instanceof HTTPException) throw err; + logger_default.error(err, "POST /file", err.message); + throw err; } - await Promise.all(chunks.map(async ([cid]) => { - const exists = !!await esm_default("chelonia.db/get", cid); - if (exists) { - throw new Error(`Chunk ${cid} already exists`); - } - })); - await Promise.all(chunks.map(([cid, data]) => esm_default("chelonia.db/set", cid, data))); - await esm_default("chelonia.db/set", manifestHash, manifestMeta.payload); - await esm_default("backend/server/saveOwner", credentials.billableContractID, manifestHash); - const size = manifest2.size + manifestMeta.payload.byteLength; - await esm_default("backend/server/updateSize", manifestHash, size); - await esm_default("backend/server/updateContractFilesTotalSize", credentials.billableContractID, size); - const deletionTokenDgst = request.headers["shelter-deletion-token-digest"]; - if (deletionTokenDgst) { - await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst); - } - return h2.response(manifestHash); - } catch (err) { - logger_default.error(err, "POST /file", err.message); - return err; - } - }); - route.GET("/file/{hash}", { - validate: { - params: import_npm_joi.default.object({ - hash: import_npm_joi.default.string().regex(CID_REGEX).required() - }) } - }, async function(request, h2) { - const { hash: hash3 } = request.params; + ); + app.get("/file/:hash", async function(c) { + const hash3 = c.req.param("hash"); + if (!CID_REGEX.test(hash3)) throw new HTTPException(400, { message: "Invalid hash" }); const parsed = maybeParseCID(hash3); if (!parsed) { - return import_boom3.default.badRequest(); + throw new HTTPException(400); } const blobOrString = await esm_default("chelonia.db/get", `any:${hash3}`); if (blobOrString?.length === 0) { - return import_boom3.default.resourceGone(); + throw new HTTPException(410); } else if (!blobOrString) { - return notFoundNoCache(h2); + return notFoundNoCache(c); } const type = cidLookupTable[parsed.code] || "application/octet-stream"; - return h2.response(blobOrString).etag(hash3).header("Cache-Control", "public,max-age=31536000,immutable").header("content-security-policy", "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox").header("x-content-type-options", "nosniff").type(type); + return c.body(blobOrString, 200, { + "ETag": `"${hash3}"`, + "Cache-Control": "public,max-age=31536000,immutable", + // CSP to disable everything -- this only affects direct navigation to the + // `/file` URL. + // The CSP below prevents any sort of resource loading or script execution + // on direct navigation. The `nosniff` header instructs the browser to + // honour the provided content-type. + "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox", + "X-Content-Type-Options": "nosniff", + "Content-Type": type + }); }); - route.POST("/deleteFile/{hash}", { - auth: { - // Allow file deletion, and allow either the bearer of the deletion token or - // the file owner to delete it - strategies: ["chel-shelter", "chel-bearer"], - mode: "required" - }, - validate: { - params: import_npm_joi.default.object({ - hash: import_npm_joi.default.string().regex(CID_REGEX).required() - }) - } - }, async function(request, h2) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const { hash: hash3 } = request.params; - const strategy = request.auth.strategy; - const parsed = maybeParseCID(hash3); - if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { - return import_boom3.default.badRequest(); - } - const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); - if (!owner) { - return import_boom3.default.notFound(); - } - switch (strategy) { - case "chel-shelter": { - const ultimateOwner = await lookupUltimateOwner(owner); - if (!ctEq(request.auth.credentials.billableContractID, ultimateOwner)) { - return import_boom3.default.unauthorized("Invalid shelter auth", "shelter"); - } - break; - } - case "chel-bearer": { - const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); - if (!expectedTokenDgst) { - return import_boom3.default.notFound(); + app.post( + "/deleteFile/:hash", + authMiddleware(["chel-shelter", "chel-bearer"], "required"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const hash3 = c.req.param("hash"); + if (!CID_REGEX.test(hash3)) throw new HTTPException(400, { message: "Invalid hash" }); + const strategy = c.get("authStrategy"); + const parsed = maybeParseCID(hash3); + if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { + throw new HTTPException(400); + } + const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); + if (!owner) { + throw new HTTPException(404); + } + const credentials = c.get("credentials"); + switch (strategy) { + case "chel-shelter": { + const ultimateOwner = await lookupUltimateOwner(owner); + if (!ctEq(credentials.billableContractID, ultimateOwner)) { + throw new HTTPException(401, { message: "Invalid shelter auth" }); + } + break; } - const tokenDgst = blake32Hash(request.auth.credentials.token); - if (!ctEq(expectedTokenDgst, tokenDgst)) { - return import_boom3.default.unauthorized("Invalid token", "bearer"); + case "chel-bearer": { + const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); + if (!expectedTokenDgst) { + throw new HTTPException(404); + } + const tokenDgst = blake32Hash(credentials.token); + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: "Invalid token" }); + } + break; } - break; + default: + throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); + } + try { + await esm_default("backend/deleteFile", hash3, null, true); + return c.body(null, 200); + } catch (e2) { + errorMapper(e2); } - default: - return import_boom3.default.unauthorized("Missing or invalid auth strategy"); - } - try { - await esm_default("backend/deleteFile", hash3, null, true); - return h2.response(); - } catch (e2) { - return errorMapper(e2); } - }); - route.POST("/deleteContract/{hash}", { - auth: { - // Allow file deletion, and allow either the bearer of the deletion token or - // the file owner to delete it - strategies: ["chel-shelter", "chel-bearer"], - mode: "required" - } - }, async function(request, h2) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const { hash: hash3 } = request.params; - const strategy = request.auth.strategy; - if (!hash3 || hash3.startsWith("_private")) return import_boom3.default.notFound(); - switch (strategy) { - case "chel-shelter": { - const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); - if (!owner) { - return import_boom3.default.notFound(); + ); + app.post( + "/deleteContract/:hash", + authMiddleware(["chel-shelter", "chel-bearer"], "required"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const hash3 = c.req.param("hash"); + const strategy = c.get("authStrategy"); + if (!hash3 || hash3.startsWith("_private")) throw new HTTPException(404); + const credentials = c.get("credentials"); + switch (strategy) { + case "chel-shelter": { + const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); + if (!owner) { + throw new HTTPException(404); + } + const ultimateOwner = await lookupUltimateOwner(owner); + if (!ctEq(credentials.billableContractID, ultimateOwner)) { + throw new HTTPException(401, { message: "Invalid shelter auth" }); + } + break; } - const ultimateOwner = await lookupUltimateOwner(owner); - if (!ctEq(request.auth.credentials.billableContractID, ultimateOwner)) { - return import_boom3.default.unauthorized("Invalid shelter auth", "shelter"); + case "chel-bearer": { + const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); + if (!expectedTokenDgst) { + throw new HTTPException(404); + } + const tokenDgst = blake32Hash(credentials.token); + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: "Invalid token" }); + } + break; } - break; + default: + throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); } - case "chel-bearer": { - const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); - if (!expectedTokenDgst) { - return import_boom3.default.notFound(); - } - const tokenDgst = blake32Hash(request.auth.credentials.token); - if (!ctEq(expectedTokenDgst, tokenDgst)) { - return import_boom3.default.unauthorized("Invalid token", "bearer"); + const username = await esm_default("chelonia.db/get", `_private_cid2name_${hash3}`); + try { + const [id] = esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", hash3, null, true]); + if (username) { + const ip = getClientIP(c); + console.info({ contractID: hash3, username, ip, taskId: id }, "Scheduled deletion on named contract"); } - break; + return c.json({ id }, 202); + } catch (e2) { + errorMapper(e2); } - default: - return import_boom3.default.unauthorized("Missing or invalid auth strategy"); } - const username = await esm_default("chelonia.db/get", `_private_cid2name_${hash3}`); - try { - const [id] = esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", hash3, null, true]); - if (username) { - const ip = request.headers["x-real-ip"] || request.info.remoteAddress; - console.info({ contractID: hash3, username, ip, taskId: id }, "Scheduled deletion on named contract"); + ); + app.post( + "/kv/:contractID/:key", + authMiddleware("chel-shelter", "required"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const contractID = c.req.param("contractID"); + const key = c.req.param("key"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: "Invalid key" }); + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); } - return h2.response({ id }).code(202); - } catch (e2) { - return errorMapper(e2); - } - }); - route.POST("/kv/{contractID}/{key}", { - auth: { - strategies: ["chel-shelter"], - mode: "required" - }, - payload: { - parse: false, - maxBytes: 6 * MEGABYTE, - // TODO: make this a configurable setting - timeout: 10 * SECOND - // TODO: make this a configurable setting - }, - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required(), - key: import_npm_joi.default.string().regex(KV_KEY_REGEX).required() - }) - } - }, function(request, h2) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const { contractID, key } = request.params; - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return import_boom3.default.badRequest(); - } - if (!ctEq(request.auth.credentials.billableContractID, contractID)) { - return import_boom3.default.unauthorized(null, "shelter"); - } - return esm_default("chelonia/queueInvocation", contractID, async () => { - const existing = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); - const expectedEtag = request.headers["if-match"]; - if (!expectedEtag) { - return import_boom3.default.badRequest("if-match is required"); + const credentials = c.get("credentials"); + if (!ctEq(credentials.billableContractID, contractID)) { + throw new HTTPException(401); } - const cid = existing ? createCID(existing, multicodes.RAW) : ""; - if (expectedEtag === "*") { - } else { - if (!expectedEtag.split(",").map((v2) => v2.trim()).includes(`"${cid}"`)) { - return h2.response(existing || "").etag(cid).header("x-cid", `"${cid}"`).code(412); + const payloadBuffer = Buffer15.from(await c.req.arrayBuffer()); + return esm_default("chelonia/queueInvocation", contractID, async () => { + const existing = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); + const expectedEtag = c.req.header("if-match"); + if (!expectedEtag) { + throw new HTTPException(400, { message: "if-match is required" }); } - } - try { - const serializedData = JSON.parse(request.payload.toString()); - const { contracts } = esm_default("chelonia/rootState"); - if (contracts[contractID].height !== Number(serializedData.height)) { - return h2.response(existing || "").etag(cid).header("x-cid", `"${cid}"`).code(409); + const cid = existing ? createCID(existing, multicodes.RAW) : ""; + if (expectedEtag === "*") { + } else { + if (!expectedEtag.split(",").map((v2) => v2.trim()).includes(`"${cid}"`)) { + return new Response(existing || "", { + status: 412, + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` + } + }); + } } - esm_default("chelonia/parseEncryptedOrUnencryptedDetachedMessage", { - contractID, - serializedData, - meta: key - }); - } catch { - return import_boom3.default.badData(); - } - const existingSize = existing ? Buffer15.from(existing).byteLength : 0; - await esm_default("chelonia.db/set", `_private_kv_${contractID}_${key}`, request.payload); - await esm_default("backend/server/updateSize", contractID, request.payload.byteLength - existingSize); - await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key); - esm_default("backend/server/broadcastKV", contractID, key, request.payload.toString()).catch((e2) => console.error(e2, "Error broadcasting KV update", contractID, key)); - return h2.response().code(204); - }); - }); - route.GET("/kv/{contractID}/{key}", { - auth: { - strategies: ["chel-shelter"], - mode: "required" - }, - cache: { otherwise: "no-store" }, - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required(), - key: import_npm_joi.default.string().regex(KV_KEY_REGEX).required() - }) - } - }, async function(request, h2) { - const { contractID, key } = request.params; - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - return import_boom3.default.badRequest(); - } - if (!ctEq(request.auth.credentials.billableContractID, contractID)) { - return import_boom3.default.unauthorized(null, "shelter"); + try { + const serializedData = JSON.parse(payloadBuffer.toString()); + const { contracts } = esm_default("chelonia/rootState"); + if (contracts[contractID].height !== Number(serializedData.height)) { + return new Response(existing || "", { + status: 409, + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` + } + }); + } + esm_default("chelonia/parseEncryptedOrUnencryptedDetachedMessage", { + contractID, + serializedData, + meta: key + }); + } catch (parseErr) { + if (parseErr instanceof Response) throw parseErr; + throw new HTTPException(422); + } + const existingSize = existing ? Buffer15.from(existing).byteLength : 0; + await esm_default("chelonia.db/set", `_private_kv_${contractID}_${key}`, payloadBuffer); + await esm_default("backend/server/updateSize", contractID, payloadBuffer.byteLength - existingSize); + await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key); + esm_default("backend/server/broadcastKV", contractID, key, payloadBuffer.toString()).catch((e2) => console.error(e2, "Error broadcasting KV update", contractID, key)); + return c.body(null, 204); + }); } - const result = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); - if (!result) { - return notFoundNoCache(h2); + ); + app.get( + "/kv/:contractID/:key", + authMiddleware("chel-shelter", "required"), + async function(c) { + const contractID = c.req.param("contractID"); + const key = c.req.param("key"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: "Invalid key" }); + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); + } + const credentials = c.get("credentials"); + if (!ctEq(credentials.billableContractID, contractID)) { + throw new HTTPException(401); + } + const result = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); + if (!result) { + return notFoundNoCache(c); + } + const cid = createCID(result, multicodes.RAW); + return new Response(result, { + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"`, + "Cache-Control": "no-store" + } + }); } - const cid = createCID(result, multicodes.RAW); - return h2.response(result).etag(cid).header("x-cid", `"${cid}"`); - }); - route.GET("/serverMessages", { cache: { otherwise: "no-store" } }, (_request, h2) => { + ); + app.get("/serverMessages", function(c) { const messages = import_npm_nconf5.default.get("server:messages"); - if (!messages) return []; - return h2.response(messages); + if (!messages) return c.json([]); + return c.json(messages, 200, { "Cache-Control": "no-store" }); }); - route.GET("/assets/{subpath*}", { - ext: { - onPostHandler: { - method(request, h2) { - if (request.path.includes("assets/js/sw-")) { - if (!(request.response instanceof import_boom3.default.Boom)) { - console.debug("adding header: Service-Worker-Allowed /"); - request.response.header("Service-Worker-Allowed", "/"); - } - } - return h2.continue; - } - } - }, - files: { - relativeTo: staticServeConfig.distAssets - } - }, function(request, h2) { - const { subpath } = request.params; + app.get("/assets/:subpath{.+}", async function(c) { + const subpath = c.req.param("subpath"); const basename72 = path6.basename(subpath); - if (basename72.includes("-cached")) { - return h2.file(subpath, { etagMethod: false }).etag(basename72).header("Cache-Control", "public,max-age=31536000,immutable"); + const filePath = path6.join(staticServeConfig.distAssets, subpath); + try { + const file = await Deno.readFile(filePath); + const headers = {}; + if (basename72.includes("-cached")) { + headers["ETag"] = `"${basename72}"`; + headers["Cache-Control"] = "public,max-age=31536000,immutable"; + } + if (subpath.includes("js/sw-")) { + console.debug("adding header: Service-Worker-Allowed /"); + headers["Service-Worker-Allowed"] = "/"; + } + const ext = path6.extname(subpath).toLowerCase(); + const mimeTypes = { + ".js": "application/javascript", + ".mjs": "application/javascript", + ".css": "text/css", + ".html": "text/html", + ".json": "application/json", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".ico": "image/x-icon", + ".woff": "font/woff", + ".woff2": "font/woff2", + ".ttf": "font/ttf", + ".otf": "font/otf", + ".webp": "image/webp", + ".mp4": "video/mp4", + ".webm": "video/webm", + ".map": "application/json" + }; + const contentType = mimeTypes[ext] || "application/octet-stream"; + headers["Content-Type"] = contentType; + return c.body(file, 200, headers); + } catch { + return notFoundNoCache(c); } - return h2.file(subpath); }); if (isCheloniaDashboard) { - route.GET("/dashboard/assets/{subpath*}", { - ext: { - onPostHandler: { - method(request, h2) { - if (request.path.includes("assets/js/sw-")) { - if (!(request.response instanceof import_boom3.default.Boom)) { - console.debug("adding header: Service-Worker-Allowed /"); - request.response.header("Service-Worker-Allowed", "/"); - } - } - return h2.continue; - } - } - }, - files: { - relativeTo: staticServeConfig.distAssets - } - }, function(request, h2) { - const { subpath } = request.params; + app.get("/dashboard/assets/:subpath{.+}", async function(c) { + const subpath = c.req.param("subpath"); const basename72 = path6.basename(subpath); - if (basename72.includes("-cached")) { - return h2.file(subpath, { etagMethod: false }).etag(basename72).header("Cache-Control", "public,max-age=31536000,immutable"); + const filePath = path6.join(staticServeConfig.distAssets, subpath); + try { + const file = await Deno.readFile(filePath); + const headers = {}; + if (basename72.includes("-cached")) { + headers["ETag"] = `"${basename72}"`; + headers["Cache-Control"] = "public,max-age=31536000,immutable"; + } + if (subpath.includes("js/sw-")) { + console.debug("adding header: Service-Worker-Allowed /"); + headers["Service-Worker-Allowed"] = "/"; + } + const ext = path6.extname(subpath).toLowerCase(); + const mimeTypes = { + ".js": "application/javascript", + ".mjs": "application/javascript", + ".css": "text/css", + ".html": "text/html", + ".json": "application/json", + ".png": "image/png", + ".jpg": "image/jpeg", + ".jpeg": "image/jpeg", + ".gif": "image/gif", + ".svg": "image/svg+xml", + ".ico": "image/x-icon", + ".woff": "font/woff", + ".woff2": "font/woff2", + ".ttf": "font/ttf", + ".otf": "font/otf", + ".webp": "image/webp", + ".mp4": "video/mp4", + ".webm": "video/webm", + ".map": "application/json" + }; + const contentType = mimeTypes[ext] || "application/octet-stream"; + headers["Content-Type"] = contentType; + return c.body(file, 200, headers); + } catch { + return notFoundNoCache(c); } - return h2.file(subpath); }); } - route.GET(staticServeConfig.routePath, {}, { - file: staticServeConfig.distIndexHtml + app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { + try { + const file = await Deno.readFile(staticServeConfig.distIndexHtml); + return c.body(file, 200, { "Content-Type": "text/html" }); + } catch { + return notFoundNoCache(c); + } }); - route.GET("/", {}, function(_req, h2) { - return h2.redirect(staticServeConfig.redirect); + app.get("/", function(c) { + return c.redirect(staticServeConfig.redirect); }); - route.POST("/zkpp/register/{name}", { - validate: { - params: import_npm_joi.default.object({ - name: import_npm_joi.default.string().regex(NAME_REGEX).required() - }), - payload: import_npm_joi.default.alternatives([ - { - // b is a hash of a random public key (`g^r`) with secret key `r`, - // which is used by the requester to commit to that particular `r` - b: import_npm_joi.default.string().required() - }, - { - // `r` is the value used to derive `b` (in this case, it's the public - // key `g^r`) - r: import_npm_joi.default.string().required(), - // `s` is an opaque (to the client) value that was earlier returned by - // the server - s: import_npm_joi.default.string().required(), - // `sig` is an opaque (to the client) value returned by the server - // to validate the request (ensuring that (`r`, `s`) come from a - // previous request - sig: import_npm_joi.default.string().required(), - // `Eh` is the Eh = E_{S_A + S_C}(h), where S_A and S_C are salts and - // h = H\_{S_A}(P) - Eh: import_npm_joi.default.string().required() - } - ]) - } - }, async function(req) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); - const lookupResult = await esm_default("backend/db/lookupName", req.params["name"]); + app.post("/zkpp/register/:name", async function(c) { + const name = c.req.param("name"); + if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: "Invalid name" }); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const lookupResult = await esm_default("backend/db/lookupName", name); if (lookupResult) { - return import_boom3.default.conflict(); + throw new HTTPException(409); } try { - const { payload } = req; - if (payload["b"]) { - const result = registrationKey(req.params["name"], payload["b"]); + const payload = await c.req.json(); + if (payload.b) { + if (typeof payload.b !== "string") throw new HTTPException(400); + const result = registrationKey(name, payload.b); if (result) { - return result; + return c.json(result); } - } else { - const result = register(req.params["name"], payload["r"], payload["s"], payload["sig"], payload["Eh"]); + } else if (payload.r && payload.s && payload.sig && payload.Eh) { + if (typeof payload.r !== "string" || typeof payload.s !== "string" || typeof payload.sig !== "string" || typeof payload.Eh !== "string") { + throw new HTTPException(400); + } + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); if (result) { - return result; + return c.json(result); } + } else { + throw new HTTPException(400, { message: "Invalid payload" }); } } catch (e2) { - e2.ip = req.headers["x-real-ip"] || req.info.remoteAddress; + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); console.error(e2, "Error at POST /zkpp/{name}: " + e2.message); } - return import_boom3.default.internal("internal error"); + throw new HTTPException(500, { message: "internal error" }); }); - route.GET("/zkpp/{contractID}/auth_hash", { - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required() - }), - query: import_npm_joi.default.object({ b: import_npm_joi.default.string().required() }) - } - }, async function(req, h2) { + app.get("/zkpp/:contractID/auth_hash", async function(c) { + const contractID = c.req.param("contractID"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + const b = c.req.query("b"); + if (!b) throw new HTTPException(400, { message: "b is required" }); try { - const challenge = await getChallenge(req.params["contractID"], req.query["b"]); - return challenge || notFoundNoCache(h2); + const challenge = await getChallenge(contractID, b); + return challenge ? c.json(challenge) : notFoundNoCache(c); } catch (e2) { - e2.ip = req.headers["x-real-ip"] || req.info.remoteAddress; + ; + e2.ip = getClientIP(c); console.error(e2, "Error at GET /zkpp/{contractID}/auth_hash: " + e2.message); } - return import_boom3.default.internal("internal error"); + throw new HTTPException(500, { message: "internal error" }); }); - route.GET("/zkpp/{contractID}/contract_hash", { - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required() - }), - query: import_npm_joi.default.object({ - r: import_npm_joi.default.string().required(), - s: import_npm_joi.default.string().required(), - sig: import_npm_joi.default.string().required(), - hc: import_npm_joi.default.string().required() - }) - } - }, async function(req) { + app.get("/zkpp/:contractID/contract_hash", async function(c) { + const contractID = c.req.param("contractID"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + const r = c.req.query("r"); + const s = c.req.query("s"); + const sig = c.req.query("sig"); + const hc = c.req.query("hc"); + if (!r || !s || !sig || !hc) throw new HTTPException(400, { message: "r, s, sig, and hc are required" }); try { - const salt = await getContractSalt(req.params["contractID"], req.query["r"], req.query["s"], req.query["sig"], req.query["hc"]); + const salt = await getContractSalt(contractID, r, s, sig, hc); if (salt) { - return salt; + return c.json(salt); } } catch (e2) { - e2.ip = req.headers["x-real-ip"] || req.info.remoteAddress; + ; + e2.ip = getClientIP(c); console.error(e2, "Error at GET /zkpp/{contractID}/contract_hash: " + e2.message); } - return import_boom3.default.internal("internal error"); + throw new HTTPException(500, { message: "internal error" }); }); - route.POST("/zkpp/{contractID}/updatePasswordHash", { - validate: { - params: import_npm_joi.default.object({ - contractID: import_npm_joi.default.string().regex(CID_REGEX).required() - }), - payload: import_npm_joi.default.object({ - r: import_npm_joi.default.string().required(), - s: import_npm_joi.default.string().required(), - sig: import_npm_joi.default.string().required(), - hc: import_npm_joi.default.string().required(), - Ea: import_npm_joi.default.string().required() - }) - } - }, async function(req) { - if (ARCHIVE_MODE) return import_boom3.default.notImplemented("Server in archive mode"); + app.post("/zkpp/:contractID/updatePasswordHash", async function(c) { + const contractID = c.req.param("contractID"); + if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { - const { payload } = req; - const result = await updateContractSalt(req.params["contractID"], payload["r"], payload["s"], payload["sig"], payload["hc"], payload["Ea"]); + const payload = await c.req.json(); + if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { + throw new HTTPException(400, { message: "r, s, sig, hc, and Ea are required" }); + } + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); if (result) { - return result; + return c.json(result); } } catch (e2) { - e2.ip = req.headers["x-real-ip"] || req.info.remoteAddress; + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); console.error(e2, "Error at POST /zkpp/{contractID}/updatePasswordHash: " + e2.message); } - return import_boom3.default.internal("internal error"); + throw new HTTPException(500, { message: "internal error" }); }); } }); var server_exports = {}; -var import_boom4; -var Hapi2; -var import_inert2; +__export(server_exports, { + app: () => app2 +}); var import_npm_chalk3; var import_npm_nconf6; var cheloniaAppManifest; var ARCHIVE_MODE2; var ownerSizeTotalWorker; var creditsWorker; -var hapi; +var app2; +var httpServer; var appendToOrphanedNamesIndex; var init_server = __esm({ async "src/serve/server.ts"() { @@ -108570,14 +73571,13 @@ var init_server = __esm({ init_functions(); init_persistent_actions(); init_presets(); - import_boom4 = __toESM(require_lib2()); - Hapi2 = __toESM(require_lib34()); - import_inert2 = __toESM(require_lib35()); init_esm(); import_npm_chalk3 = __toESM(require_source()); + init_dist(); + init_cors(); + init_dist2(); init_createWorker(); - init_auth(); - init_constants2(); + init_constants4(); init_database(); init_errors4(); init_events2(); @@ -108587,7 +73587,7 @@ var init_server = __esm({ import_npm_nconf6 = __toESM(require_nconf()); cheloniaAppManifest = await (async () => { try { - return (await import(pathToFileURL(join72(process10.cwd(), "chelonia.json")).toString(), { + return (await import(pathToFileURL(join82(process10.cwd(), "chelonia.json")).toString(), { with: { type: "json" } })).default; } catch { @@ -108599,44 +73599,24 @@ var init_server = __esm({ process10.stderr.write("The size calculation worker must run more frequently than the credits worker for accurate billing"); process10.exit(1); } - ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "ownerSizeTotalWorker.js")); - creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "creditsWorker.js")); - hapi = new Hapi2.Server({ - // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements - // // v17 doesn't seem to do this anymore so I've re-enabled the logging - // debug: { log: ['error'], request: ['error'] }, - host: import_npm_nconf6.default.get("server:host"), - port: import_npm_nconf6.default.get("server:port"), - // See: https://github.com/hapijs/discuss/issues/262#issuecomment-204616831 - routes: { - cors: { - // TODO: figure out if we can live with '*' or if we need to restrict it - origin: ["*"] - // origin: [ - // process.env.API_URL, - // // improve support for browsersync proxy - // ...(process.env.NODE_ENV === 'development' && ['http://localhost:3000']) - // ] - } - } - }); - hapi.ext({ - type: "onPreResponse", - method: function(request, h2) { - try { - if (!(request.response instanceof import_boom4.default.Boom)) { - request.response.header("X-Frame-Options", "DENY"); - } else { - request.response.output.headers["X-Frame-Options"] = "DENY"; - } - } catch (err) { - console.warn(import_npm_chalk3.default.yellow("[backend] Could not set X-Frame-Options header:", err.message)); - } - return h2.continue; - } + ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join82(import.meta.dirname || ".", "serve", "ownerSizeTotalWorker.js")); + creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join82(import.meta.dirname || ".", "serve", "creditsWorker.js")); + app2 = new Hono2(); + app2.use("*", cors({ origin: "*" })); + app2.use("*", async (c, next) => { + await next(); + c.header("X-Frame-Options", "DENY"); }); + if (process10.env.NODE_ENV === "development" && !process10.env.CI) { + app2.use("*", async (c, next) => { + await next(); + const ip = c.req.header("x-real-ip") || "unknown"; + console.debug(import_npm_chalk3.default`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`); + }); + } + httpServer = createAdaptorServer({ fetch: app2.fetch }); appendToOrphanedNamesIndex = appendToIndexFactory("_private_orphaned_names_index"); - esm_default("okTurtles.data/set", SERVER_INSTANCE, hapi); + esm_default("okTurtles.data/set", SERVER_INSTANCE, app2); esm_default("sbp/selectors/register", { "backend/server/persistState": async function(deserializedHEAD) { const contractID = deserializedHEAD.contractID; @@ -108736,7 +73716,12 @@ var init_server = __esm({ return updateSize(resourceID, sizeKey, size, true); }, "backend/server/stop": function() { - return hapi.stop(); + return new Promise((resolve82, reject) => { + httpServer.close((err) => { + if (err) reject(err); + else resolve82(); + }); + }); }, async "backend/deleteFile"(cid, ultimateOwnerID, skipIfDeleted) { const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); @@ -108871,14 +73856,7 @@ var init_server = __esm({ }); } }); - if (process10.env.NODE_ENV === "development" && !process10.env.CI) { - hapi.events.on("response", (req) => { - const ip = req.headers["x-real-ip"] || req.info.remoteAddress; - const statusCode = req.response instanceof import_boom4.default.Boom ? req.response.output.statusCode : req.response.statusCode; - console.debug(import_npm_chalk3.default`{grey ${ip}: ${req.method} ${req.path} --> ${statusCode}}`); - }); - } - esm_default("okTurtles.data/set", PUBSUB_INSTANCE, createServer(hapi.listener, { + esm_default("okTurtles.data/set", PUBSUB_INSTANCE, createServer(httpServer, { serverHandlers: { connection(socket) { const versionInfo = { @@ -109006,20 +73984,15 @@ var init_server = __esm({ esm_default("chelonia.persistentActions/load").catch((e2) => { console.error(e2, "Error loading persistent actions"); }); - await hapi.register([ - { plugin: auth_default }, - { plugin: import_inert2.default } - // { - // plugin: require('hapi-pino'), - // options: { - // instance: logger - // } - // } - ]); await Promise.resolve().then(() => (init_routes(), routes_exports)); - await hapi.start(); - console.info("Backend server running at:", hapi.info.uri); - esm_default("okTurtles.events/emit", SERVER_RUNNING, hapi); + const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; + const port = import_npm_nconf6.default.get("server:port") || 8e3; + httpServer.listen(port, host, () => { + const addr = httpServer.address(); + const uri = `http://${addr.address}:${addr.port}`; + console.info("Backend server running at:", uri); + esm_default("okTurtles.events/emit", SERVER_RUNNING, { info: { uri } }); + }); })(); (() => { const map = /* @__PURE__ */ new WeakMap(); @@ -109093,7 +74066,7 @@ var init_serve = __esm({ pubsub.on("close", async function() { try { await esm_default("backend/server/stop"); - console.info("Hapi server down"); + console.info("Server down"); } catch (err) { console.error(err, "Error during shutdown"); } finally { @@ -109261,18 +74234,18 @@ var TomlDate = class _TomlDate extends Date { let hasTime = true; let offset = "Z"; if (typeof date3 === "string") { - let match = date3.match(DATE_TIME_RE); - if (match) { - if (!match[1]) { + let match2 = date3.match(DATE_TIME_RE); + if (match2) { + if (!match2[1]) { hasDate = false; date3 = `0000-01-01T${date3}`; } - hasTime = !!match[2]; + hasTime = !!match2[2]; hasTime && date3[10] === " " && (date3 = date3.replace(" ", "T")); - if (match[2] && +match[2] > 23) { + if (match2[2] && +match2[2] > 23) { date3 = ""; } else { - offset = match[3] || null; + offset = match2[3] || null; date3 = date3.toUpperCase(); if (!offset && hasTime) date3 += "Z"; @@ -110143,10 +75116,10 @@ async function deploy(args) { const manifestText = await Deno.readTextFile(manifestPath); const json = JSON.parse(manifestText); const body = ContractBodySchema.parse(JSON.parse(json.body)); - const dirname72 = dirname8(manifestPath); - toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname72, body.contract.file)); + const dirname82 = dirname8(manifestPath); + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contract.file)); if (body.contractSlim) { - toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname72, body.contractSlim.file)); + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contractSlim.file)); } toUpload.push(CONTRACT_MANIFEST_PREFIX + manifestPath); } @@ -111150,8 +76123,8 @@ var UI = class { // if the full 'source' can render in // the target line, do so. renderInline(source, previousLine) { - const match = source.match(/^ */); - const leadingWhitespace = match ? match[0].length : 0; + const match2 = source.match(/^ */); + const leadingWhitespace = match2 ? match2[0].length : 0; const target = previousLine.text; const targetTextWidth = mixin.stringWidth(target.trimRight()); if (!previousLine.span) { @@ -111228,11 +76201,11 @@ var UI = class { return void 0; }); const unsetWidth = unset ? Math.floor(remainingWidth / unset) : 0; - return widths.map((w4, i2) => { - if (w4 === void 0) { + return widths.map((w3, i2) => { + if (w3 === void 0) { return Math.max(unsetWidth, _minWidth(row[i2])); } - return w4; + return w3; }); } }; @@ -111318,12 +76291,12 @@ function sync_default(start, callback) { let dir = resolve42(".", start); let tmp, stats = statSync(dir); if (!stats.isDirectory()) { - dir = dirname52(dir); + dir = dirname62(dir); } while (true) { tmp = callback(dir, readdirSync(dir)); if (tmp) return resolve42(dir, tmp); - dir = dirname52(tmp = dir); + dir = dirname62(tmp = dir); if (tmp === dir) break; } } @@ -112114,8 +77087,8 @@ var YargsParser = class { function hasFlagsMatching(arg, ...patterns) { const toCheck = [].concat(...patterns); return toCheck.some(function(pattern) { - const match = arg.match(pattern); - return match && hasAnyFlag(match[1]); + const match2 = arg.match(pattern); + return match2 && hasAnyFlag(match2[1]); }); } function hasAllShortFlags(arg) { @@ -112514,7 +77487,7 @@ var esm_default7 = { Parser: lib_default, path: { basename: basename62, - dirname: dirname62, + dirname: dirname72, extname: extname8, relative: relative22, resolve: resolve72 @@ -112551,7 +77524,7 @@ function assertSingleKey(actual, shim4) { function objectKeys(object2) { return Object.keys(object2); } -function isPromise(maybePromise) { +function isPromise2(maybePromise) { return !!maybePromise && !!maybePromise.then && typeof maybePromise.then === "function"; } function parseCommand(cmd) { @@ -112673,16 +77646,16 @@ function applyMiddleware(argv, yargs, middlewares, beforeValidation) { if (middleware.applyBeforeValidation !== beforeValidation) { return acc; } - if (isPromise(acc)) { + if (isPromise2(acc)) { return acc.then((initialObj) => Promise.all([ initialObj, middleware(initialObj, yargs) ])).then(([initialObj, middlewareObj]) => Object.assign(initialObj, middlewareObj)); } else { const result = middleware(acc, yargs); - if (beforeValidation && isPromise(result)) + if (beforeValidation && isPromise2(result)) throw beforeValidationError; - return isPromise(result) ? result.then((middlewareObj) => Object.assign(acc, middlewareObj)) : Object.assign(acc, result); + return isPromise2(result) ? result.then((middlewareObj) => Object.assign(acc, middlewareObj)) : Object.assign(acc, result); } }, argv); } @@ -112848,13 +77821,13 @@ function command(yargs, usage2, validation2, globalMiddleware = [], shim4) { yargs2._postProcess(innerArgv, populateDoubleDash); innerArgv = applyMiddleware(innerArgv, yargs2, middlewares, false); let handlerResult; - if (isPromise(innerArgv)) { + if (isPromise2(innerArgv)) { handlerResult = innerArgv.then((argv) => commandHandler.handler(argv)); } else { handlerResult = commandHandler.handler(innerArgv); } const handlerFinishCommand = yargs2.getHandlerFinishCommand(); - if (isPromise(handlerResult)) { + if (isPromise2(handlerResult)) { yargs2.getUsageInstance().cacheHelpMessage(); handlerResult.then((value) => { if (handlerFinishCommand) { @@ -113620,7 +78593,7 @@ function completion(yargs, usage2, command2, shim4) { assertNotStrictEqual(completionFunction, null, shim4); if (isSyncCompletionFunction(completionFunction)) { const result = completionFunction(current, argv2); - if (isPromise(result)) { + if (isPromise2(result)) { return result.then((list) => { shim4.process.nextTick(() => { done(list); @@ -113639,7 +78612,7 @@ function completion(yargs, usage2, command2, shim4) { } } if (completionFunction) { - return isPromise(argv) ? argv.then(runCompletionFunction) : runCompletionFunction(argv); + return isPromise2(argv) ? argv.then(runCompletionFunction) : runCompletionFunction(argv); } const handlers = command2.getCommandHandlers(); for (let i2 = 0, ii = args.length; i2 < ii; ++i2) { @@ -115083,7 +80056,7 @@ function Yargs(processArgs = [], cwd = shim3.process.cwd(), parentRequire) { return self2._postProcess(argv, populateDoubleDash, _calledFromCommand); }; self2._postProcess = function(argv, populateDoubleDash, calledFromCommand = false) { - if (isPromise(argv)) + if (isPromise2(argv)) return argv; if (calledFromCommand) return argv; diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 7b2d5ed..814a512 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/creditsWorker.js-tmp diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index ec3e39a..deaef25 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/ownerSizeTotalWorker.js-tmp diff --git a/scripts/build.ts b/scripts/build.ts index e58af9f..d470275 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -48,10 +48,23 @@ if (result.errors.length) { } console.log(colors.green('built:'), options.outdir) +import { builtinModules } from 'node:module' + +const nodeBuiltins = new Set(builtinModules.filter((m: string) => !m.startsWith('_'))) +const bareBuiltinRe = /\bfrom\s+"([^"]+)"/g + +function addNodePrefix (source: string): string { + return source.replace(bareBuiltinRe, (match, specifier) => { + return nodeBuiltins.has(specifier) ? `from "node:${specifier}"` : match + }) +} + for (const outfile of result.outputFiles!) { const tmpFile = outfile.path + '-tmp' try { - Deno.writeFileSync(tmpFile, outfile.contents) + const text = new TextDecoder().decode(outfile.contents) + const patched = addNodePrefix(text) + Deno.writeFileSync(tmpFile, new TextEncoder().encode(patched)) try { Deno.removeSync(outfile.path) } catch (e) { From a489c8d84d74ca62af7b025724272a94d7716ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 20:59:30 -0400 Subject: [PATCH 08/71] Fix incorrect JSON parsing --- build/main.js | 13 +++- src/serve/routes-zkpp.test.ts | 123 ++++++++++++++++++++++++++++++++++ src/serve/routes.ts | 12 +++- src/serve/server.ts | 2 +- 4 files changed, 144 insertions(+), 6 deletions(-) diff --git a/build/main.js b/build/main.js index b7abef3..8f43a56 100644 --- a/build/main.js +++ b/build/main.js @@ -72654,6 +72654,13 @@ function getClientIP(c) { function notFoundNoCache(c) { return c.body(null, 404, { "Cache-Control": "no-store" }); } +async function parseRequestBody(c) { + const contentType = c.req.header("content-type") || ""; + if (contentType.includes("application/json")) { + return await c.req.json(); + } + return await c.req.parseBody(); +} var import_npm_bottleneck; var import_npm_chalk2; var import_npm_nconf5; @@ -73468,7 +73475,7 @@ var init_routes = __esm({ throw new HTTPException(409); } try { - const payload = await c.req.json(); + const payload = await parseRequestBody(c); if (payload.b) { if (typeof payload.b !== "string") throw new HTTPException(400); const result = registrationKey(name, payload.b); @@ -73533,7 +73540,7 @@ var init_routes = __esm({ if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { - const payload = await c.req.json(); + const payload = await parseRequestBody(c); if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { throw new HTTPException(400, { message: "r, s, sig, hc, and Ea are required" }); } @@ -73986,7 +73993,7 @@ var init_server = __esm({ }); await Promise.resolve().then(() => (init_routes(), routes_exports)); const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; - const port = import_npm_nconf6.default.get("server:port") || 8e3; + const port = import_npm_nconf6.default.get("server:port") ?? 8e3; httpServer.listen(port, host, () => { const addr = httpServer.address(); const uri = `http://${addr.address}:${addr.port}`; diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index ae556ce..3380add 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -187,6 +187,129 @@ Deno.test({ const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') }) + + await t.step('POST /zkpp/register step 1 with form-urlencoded body', async () => { + const keyPair = nacl.box.keyPair() + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from( + Buffer.from(keyPair.publicKey).toString('base64url') + ))).toString('base64url') + const res = await fetch(`${baseURL}/zkpp/register/zkppformuser1`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!body.s) throw new Error('Expected s in response') + if (!body.p) throw new Error('Expected p in response') + if (!body.sig) throw new Error('Expected sig in response') + }) + + await t.step('POST /zkpp/register step 2 with form-urlencoded body', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const res1 = await fetch(`${baseURL}/zkpp/register/zkppformuser2`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res1.status !== 200) throw new Error(`Step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, 'testhash') + const res2 = await fetch(`${baseURL}/zkpp/register/zkppformuser2`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + r: publicKey, + s: step1.s, + sig: step1.sig, + Eh: encryptedHashedPassword + }).toString() + }) + if (res2.status !== 200) throw new Error(`Step 2 failed: ${res2.status}`) + const token = await res2.text() + if (!token) throw new Error('Expected registration token') + }) + + await t.step('POST /zkpp/{contractID}/updatePasswordHash with form-urlencoded body returns 400 for missing params', async () => { + const cid = createCID('zkpp-form-test', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${cid}/updatePasswordHash`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ r: 'a', s: 'b' }).toString() + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('ZKPP full flow with form-urlencoded registration', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + const hash = 'myhash-form' + const name = 'zkppformfull' + + const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) + const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + r: publicKey, + s: step1.s, + sig: step1.sig, + Eh: encryptedHashedPassword + }).toString() + }) + if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) + const encryptedToken = (await res2.text()).replace(/^"|"$/g, '') + const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) + + const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) + await sbp('backend/db/registerName', name, contractCID) + + const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') + await redeemSaltRegistrationToken(name, contractCID, token) + + const r = 'challenge-r-form' + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) + if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) + const challenge = await challengeRes.json() + if (!challenge.authSalt) throw new Error('Expected authSalt') + if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const saltRes = await fetch( + `${baseURL}/zkpp/${contractCID}/contract_hash?` + + `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + + `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` + ) + if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) + const encryptedSalt = await saltRes.text() + if (!encryptedSalt) throw new Error('Expected encrypted salt response') + + const saltBuf = Buffer.from(encryptedSalt.replace(/^"|"$/g, ''), 'base64url') + const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) + const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt contract salt') + const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) + if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') + }) } finally { await stopTestServer() } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index d6299f1..0890c12 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -189,6 +189,14 @@ function notFoundNoCache (c: Context): Response { return c.body(null, 404, { 'Cache-Control': 'no-store' }) } +async function parseRequestBody> (c: Context): Promise { + const contentType = c.req.header('content-type') || '' + if (contentType.includes('application/json')) { + return await c.req.json() as T + } + return await c.req.parseBody() as T +} + // Get the Hono app via SERVER_INSTANCE const app: Hono = sbp('okTurtles.data/get', SERVER_INSTANCE) @@ -1029,7 +1037,7 @@ app.post('/zkpp/register/:name', async function (c) { throw new HTTPException(409) } try { - const payload = await c.req.json() as { b?: string, r?: string, s?: string, sig?: string, Eh?: string } + const payload = await parseRequestBody<{ b?: string, r?: string, s?: string, sig?: string, Eh?: string }>(c) // Validate: must be either { b } or { r, s, sig, Eh } if (payload.b) { if (typeof payload.b !== 'string') throw new HTTPException(400) @@ -1104,7 +1112,7 @@ app.post('/zkpp/:contractID/updatePasswordHash', async function (c) { if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { - const payload = await c.req.json() as { r: string, s: string, sig: string, hc: string, Ea: string } + const payload = await parseRequestBody<{ r: string, s: string, sig: string, hc: string, Ea: string }>(c) if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { throw new HTTPException(400, { message: 'r, s, sig, hc, and Ea are required' }) } diff --git a/src/serve/server.ts b/src/serve/server.ts index 7b39a28..093571e 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -557,7 +557,7 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { await import('./routes.ts') // Start listening const host = nconf.get('server:host') || '0.0.0.0' - const port = nconf.get('server:port') || 8000 + const port = nconf.get('server:port') ?? 8000 httpServer.listen(port, host, () => { const addr = httpServer.address() as { address: string; port: number } const uri = `http://${addr.address}:${addr.port}` From ecff1d9582fcf59d0dbfbcd7067366478f3acf47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 13 Apr 2026 21:00:44 -0400 Subject: [PATCH 09/71] Improve tests --- src/serve/routes-zkpp.test.ts | 123 ++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index ae556ce..3380add 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -187,6 +187,129 @@ Deno.test({ const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') }) + + await t.step('POST /zkpp/register step 1 with form-urlencoded body', async () => { + const keyPair = nacl.box.keyPair() + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from( + Buffer.from(keyPair.publicKey).toString('base64url') + ))).toString('base64url') + const res = await fetch(`${baseURL}/zkpp/register/zkppformuser1`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res.status !== 200) throw new Error(`Expected 200 but got ${res.status}`) + const body = await res.json() + if (!body.s) throw new Error('Expected s in response') + if (!body.p) throw new Error('Expected p in response') + if (!body.sig) throw new Error('Expected sig in response') + }) + + await t.step('POST /zkpp/register step 2 with form-urlencoded body', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const res1 = await fetch(`${baseURL}/zkpp/register/zkppformuser2`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res1.status !== 200) throw new Error(`Step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, 'testhash') + const res2 = await fetch(`${baseURL}/zkpp/register/zkppformuser2`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + r: publicKey, + s: step1.s, + sig: step1.sig, + Eh: encryptedHashedPassword + }).toString() + }) + if (res2.status !== 200) throw new Error(`Step 2 failed: ${res2.status}`) + const token = await res2.text() + if (!token) throw new Error('Expected registration token') + }) + + await t.step('POST /zkpp/{contractID}/updatePasswordHash with form-urlencoded body returns 400 for missing params', async () => { + const cid = createCID('zkpp-form-test', multicodes.SHELTER_CONTRACT_DATA) + const res = await fetch(`${baseURL}/zkpp/${cid}/updatePasswordHash`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ r: 'a', s: 'b' }).toString() + }) + await res.body?.cancel() + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) + }) + + await t.step('ZKPP full flow with form-urlencoded registration', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + const hash = 'myhash-form' + const name = 'zkppformfull' + + const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: `b=${encodeURIComponent(publicKeyHash)}` + }) + if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) + const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + r: publicKey, + s: step1.s, + sig: step1.sig, + Eh: encryptedHashedPassword + }).toString() + }) + if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) + const encryptedToken = (await res2.text()).replace(/^"|"$/g, '') + const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) + + const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) + await sbp('backend/db/registerName', name, contractCID) + + const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') + await redeemSaltRegistrationToken(name, contractCID, token) + + const r = 'challenge-r-form' + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) + if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) + const challenge = await challengeRes.json() + if (!challenge.authSalt) throw new Error('Expected authSalt') + if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const saltRes = await fetch( + `${baseURL}/zkpp/${contractCID}/contract_hash?` + + `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + + `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` + ) + if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) + const encryptedSalt = await saltRes.text() + if (!encryptedSalt) throw new Error('Expected encrypted salt response') + + const saltBuf = Buffer.from(encryptedSalt.replace(/^"|"$/g, ''), 'base64url') + const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) + const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt contract salt') + const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) + if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') + }) } finally { await stopTestServer() } From 64cf74e44424cb395e0e33b44e147a9978129e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:33:25 -0400 Subject: [PATCH 10/71] Improvements --- deno.json | 2 +- src/serve/routes-kv.test.ts | 4 ++++ src/serve/routes-test-helpers.ts | 11 ++++++++--- src/serve/server.ts | 5 +++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/deno.json b/deno.json index 9c6defb..674732e 100644 --- a/deno.json +++ b/deno.json @@ -5,7 +5,7 @@ "compile": "deno run --allow-env --allow-ffi --allow-sys='hostname' --allow-run --allow-read --allow-write=./dist scripts/compile.ts", "build": "deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir' scripts/dashboard-esbuild.ts && deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir,hostname' scripts/build.ts", "dist": "deno task lint && deno task build && deno task compile", - "test": "deno task lint && deno test --no-check --sloppy-imports --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" + "test": "deno task lint && deno test --sloppy-imports --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" }, "imports": { "@db/sqlite": "jsr:@db/sqlite@0.13.0", diff --git a/src/serve/routes-kv.test.ts b/src/serve/routes-kv.test.ts index 2f09f75..8524679 100644 --- a/src/serve/routes-kv.test.ts +++ b/src/serve/routes-kv.test.ts @@ -132,6 +132,7 @@ Deno.test({ if (!etag) throw new Error('Expected ETag header') const xcid = res.headers.get('x-cid') if (!xcid) throw new Error('Expected x-cid header') + if (!etag.startsWith('W/') && etag !== xcid) throw new Error('Expected x-cid to match ETag') }) await t.step('GET /kv with valid auth for nonexistent key returns 404', async () => { @@ -167,9 +168,12 @@ Deno.test({ const getRes = await fetch(`${baseURL}/kv/${owner.contractID}/testkey`, { headers: { authorization: auth1 } }) + const etag = getRes.headers.get('etag') const xcid = getRes.headers.get('x-cid') await getRes.body?.cancel() if (!xcid) throw new Error('Expected x-cid from GET') + if (!etag) throw new Error('Expected ETag from GET') + if (!etag.startsWith('W/') && etag !== xcid) throw new Error('Expected x-cid to match ETag') const auth2 = buildShelterAuthHeader(owner.contractID, owner.SAK) const payload = buildSignedKvPayload(owner.contractID, 'testkey', 0, { updated: true }, owner.SAK) diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts index fea77c7..7b64898 100644 --- a/src/serve/routes-test-helpers.ts +++ b/src/serve/routes-test-helpers.ts @@ -21,7 +21,7 @@ export const nacl = tweetnacl const TEST_PORT = 0 export function buildSignedKvPayload ( - contractID: string, + _contractID: string, key: string, height: number, data: unknown, @@ -136,10 +136,15 @@ export async function startTestServer (): Promise { nconf.set('server:archiveMode', false) const serverAddress = await new Promise((resolve, reject) => { - sbp('okTurtles.events/on', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { + const unregister = sbp('okTurtles.events/once', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { resolve(hapi.info.uri) }) - import('./server.ts').catch(reject) + import('./index.ts').then(({ default: start }) => { + return start() + }).catch((e) => { + unregister() + reject(e) + }) }) return serverAddress diff --git a/src/serve/server.ts b/src/serve/server.ts index b46e64d..7a02fc6 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -10,6 +10,7 @@ import * as Hapi from 'npm:@hapi/hapi' import Inert from 'npm:@hapi/inert' import sbp from 'npm:@sbp/sbp' import chalk from 'npm:chalk' +import type { ImportMeta } from '../types/build.d.ts' import createWorker from './createWorker.ts' // import type { SubMessage, UnsubMessage } from './pubsub.ts' // TODO: Use for type checking import { join } from 'node:path' @@ -44,10 +45,10 @@ if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTER // Initialize workers for size calculation and credits processing const ownerSizeTotalWorker = ARCHIVE_MODE || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? undefined - : createWorker(join(import.meta.dirname || '.', import.meta.workerDir || '.', 'ownerSizeTotalWorker.js')) + : createWorker(join(import.meta.dirname || '.', (import.meta as ImportMeta).workerDir || '.', 'ownerSizeTotalWorker.js')) const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? undefined - : createWorker(join(import.meta.dirname || '.', import.meta.workerDir || '.', 'creditsWorker.js')) + : createWorker(join(import.meta.dirname || '.', (import.meta as ImportMeta).workerDir || '.', 'creditsWorker.js')) const { CONTRACTS_VERSION, GI_VERSION } = process.env From 80765dee43194ea5b7c7f5150a816c1efa7f73bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:06:35 -0400 Subject: [PATCH 11/71] Remove --sloppy-imports --- deno.json | 2 +- scripts/build.ts | 3 ++- src/serve/server.ts | 5 ++--- src/types/build.d.ts | 5 +++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/deno.json b/deno.json index 674732e..f695c5c 100644 --- a/deno.json +++ b/deno.json @@ -5,7 +5,7 @@ "compile": "deno run --allow-env --allow-ffi --allow-sys='hostname' --allow-run --allow-read --allow-write=./dist scripts/compile.ts", "build": "deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir' scripts/dashboard-esbuild.ts && deno run --node-modules-dir --allow-ffi --allow-run --allow-read --allow-env --allow-write=./build --allow-sys='cpus,homedir,hostname' scripts/build.ts", "dist": "deno task lint && deno task build && deno task compile", - "test": "deno task lint && deno test --sloppy-imports --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" + "test": "deno task lint && deno test --unstable-worker-options --allow-read=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-write=.,$HOME/.cache,$HOME/Library/Caches/deno --allow-env --allow-ffi --allow-net --allow-sys" }, "imports": { "@db/sqlite": "jsr:@db/sqlite@0.13.0", diff --git a/scripts/build.ts b/scripts/build.ts index e58af9f..0003783 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -14,7 +14,8 @@ const options: esbuild.BuildOptions = { bundle: true, define: { 'import.meta.VERSION': JSON.stringify(version), - 'import.meta.workerDir': '"serve"' + 'import.meta.ownerSizeTotalWorker': '"./serve/ownerSizeTotalWorker.js"', + 'import.meta.creditsWorker': '"./serve/creditsWorker.js"', }, format: 'esm', platform: 'node', diff --git a/src/serve/server.ts b/src/serve/server.ts index 7a02fc6..59b3a68 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -13,7 +13,6 @@ import chalk from 'npm:chalk' import type { ImportMeta } from '../types/build.d.ts' import createWorker from './createWorker.ts' // import type { SubMessage, UnsubMessage } from './pubsub.ts' // TODO: Use for type checking -import { join } from 'node:path' import process from 'node:process' import authPlugin from './auth.ts' import { CREDITS_WORKER_TASK_TIME_INTERVAL, OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL } from './constants.ts' @@ -45,10 +44,10 @@ if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTER // Initialize workers for size calculation and credits processing const ownerSizeTotalWorker = ARCHIVE_MODE || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? undefined - : createWorker(join(import.meta.dirname || '.', (import.meta as ImportMeta).workerDir || '.', 'ownerSizeTotalWorker.js')) + : createWorker((import.meta as ImportMeta).ownerSizeTotalWorker || './ownerSizeTotalWorker.ts') const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? undefined - : createWorker(join(import.meta.dirname || '.', (import.meta as ImportMeta).workerDir || '.', 'creditsWorker.js')) + : createWorker((import.meta as ImportMeta).creditsWorker || './creditsWorker.ts') const { CONTRACTS_VERSION, GI_VERSION } = process.env diff --git a/src/types/build.d.ts b/src/types/build.d.ts index e04f91e..a195654 100644 --- a/src/types/build.d.ts +++ b/src/types/build.d.ts @@ -1,6 +1,7 @@ interface ImportMeta { - VERSION: string - workerDir?: string + VERSION: string, + ownerSizeTotalWorker?: string, + creditsWorker?: string } declare const logger: { From edbf14e19cd301d594c4d09adce5f36f2e5fd3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:12:35 -0400 Subject: [PATCH 12/71] Remove redundant call --- src/serve/routes-test-helpers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts index 7b64898..216b281 100644 --- a/src/serve/routes-test-helpers.ts +++ b/src/serve/routes-test-helpers.ts @@ -159,5 +159,4 @@ export async function stopTestServer (): Promise { }) sbp('okTurtles.events/emit', SERVER_EXITING) }) - await sbp('backend/server/stop') } From 3aaa5fb1aca635cb8eab6b953eeab194c7faec30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:51:01 -0400 Subject: [PATCH 13/71] Clean up on shutdown --- src/serve/index.ts | 17 +++++++++++++++-- src/serve/pubsub.ts | 1 + src/serve/routes-kv.test.ts | 2 -- src/serve/routes-reads.test.ts | 2 -- src/serve/routes-stateless.test.ts | 2 -- src/serve/routes-writes.test.ts | 2 -- src/serve/routes-zkpp.test.ts | 2 -- src/serve/routes.ts | 8 ++++++++ src/serve/server.ts | 7 ++++++- 9 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/serve/index.ts b/src/serve/index.ts index 66414ba..39783d6 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -45,6 +45,8 @@ sbp('okTurtles.events/once', SERVER_EXITING, () => { return new Promise((resolve) => { pubsub.on('close', async function () { try { + removeSignalHandlers() + await sbp('chelonia.persistentActions/unload') await sbp('backend/server/stop') console.info('Hapi server down') } catch (err) { @@ -86,13 +88,17 @@ const exit = (code: number) => { sbp('okTurtles.events/emit', SERVER_EXITING) } +const signalHandlers: Array<[string, () => void]> = [] + const handleSignal = (signal: string, code: number) => { - process.on(signal, () => { + const handler = () => { console.error(`Exiting upon receiving ${signal} (${code})`) // Exit codes follow the 128 + signal code convention. // See exit(128 + code) - }) + } + signalHandlers.push([signal, handler]) + process.on(signal, handler) } // Codes from @@ -104,3 +110,10 @@ const handleSignal = (signal: string, code: number) => { ['SIGUSR1', 10], ['SIGUSR2', 11] ] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) + +export function removeSignalHandlers () { + for (const [signal, handler] of signalHandlers) { + process.removeListener(signal, handler) + } + signalHandlers.length = 0 +} diff --git a/src/serve/pubsub.ts b/src/serve/pubsub.ts index a607b62..643f88b 100644 --- a/src/serve/pubsub.ts +++ b/src/serve/pubsub.ts @@ -274,6 +274,7 @@ export function createServer (httpServer: import('node:http').Server, options: S // The `this` binding refers to the server object. const defaultServerHandlers: ServerHandlers = { close () { + clearInterval(this.pingIntervalID) log('Server closed') }, /** diff --git a/src/serve/routes-kv.test.ts b/src/serve/routes-kv.test.ts index 8524679..f0c3d65 100644 --- a/src/serve/routes-kv.test.ts +++ b/src/serve/routes-kv.test.ts @@ -12,8 +12,6 @@ import { Deno.test({ name: 'routes: KV store endpoints', - sanitizeResources: false, - sanitizeOps: false, async fn (t: Deno.TestContext) { const baseURL = await startTestServer() diff --git a/src/serve/routes-reads.test.ts b/src/serve/routes-reads.test.ts index 6312a02..564abd4 100644 --- a/src/serve/routes-reads.test.ts +++ b/src/serve/routes-reads.test.ts @@ -9,8 +9,6 @@ import { Deno.test({ name: 'routes: state-dependent reads', - sanitizeResources: false, - sanitizeOps: false, async fn (t: Deno.TestContext) { const baseURL = await startTestServer() diff --git a/src/serve/routes-stateless.test.ts b/src/serve/routes-stateless.test.ts index e52f048..b45c74f 100644 --- a/src/serve/routes-stateless.test.ts +++ b/src/serve/routes-stateless.test.ts @@ -3,8 +3,6 @@ import { startTestServer, stopTestServer } from './routes-test-helpers.ts' Deno.test({ name: 'routes: stateless endpoints', - sanitizeResources: false, - sanitizeOps: false, async fn (t: Deno.TestContext) { const baseURL = await startTestServer() diff --git a/src/serve/routes-writes.test.ts b/src/serve/routes-writes.test.ts index 070777c..9ecd4de 100644 --- a/src/serve/routes-writes.test.ts +++ b/src/serve/routes-writes.test.ts @@ -12,8 +12,6 @@ import { Deno.test({ name: 'routes: write endpoints', - sanitizeResources: false, - sanitizeOps: false, async fn (t: Deno.TestContext) { const baseURL = await startTestServer() diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index 3380add..73a7f69 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -14,8 +14,6 @@ import { CS } from 'npm:@chelonia/lib/zkppConstants' Deno.test({ name: 'routes: ZKPP endpoints', - sanitizeResources: false, - sanitizeOps: false, async fn (t: Deno.TestContext) { const baseURL = await startTestServer() diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 6579605..091758d 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -66,6 +66,14 @@ const limiterPerDay = new Bottleneck.Group({ reservoirRefreshAmount: SIGNUP_LIMIT_DAY }) +sbp('sbp/selectors/register', { + 'backend/server/stopRateLimiters': function () { + clearInterval((limiterPerMinute as unknown as Record>).interval) + clearInterval((limiterPerHour as unknown as Record>).interval) + clearInterval((limiterPerDay as unknown as Record>).interval) + } +}) + const cidLookupTable = { [multicodes.SHELTER_CONTRACT_MANIFEST]: 'application/vnd.shelter.contractmanifest+json', [multicodes.SHELTER_CONTRACT_TEXT]: 'application/vnd.shelter.contracttext', diff --git a/src/serve/server.ts b/src/serve/server.ts index 59b3a68..f83536b 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -247,6 +247,10 @@ sbp('sbp/selectors/register', { return updateSize(resourceID, sizeKey, size, true) }, 'backend/server/stop': function () { + clearInterval(pushHeartbeatIntervalID) + ownerSizeTotalWorker?.terminate() + creditsWorker?.terminate() + sbp('backend/server/stopRateLimiters') return hapi.stop() }, async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { @@ -581,10 +585,11 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { })() // Recurring task to send messages to push clients (for periodic notifications) +let pushHeartbeatIntervalID: ReturnType ;(() => { const map = new WeakMap() - setInterval(() => { + pushHeartbeatIntervalID = setInterval(() => { const now = Date.now() const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS | undefined // Notification text From eea4b600d8d254386140300928f5252ac969e967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:52:41 -0400 Subject: [PATCH 14/71] Update AGENTS.md --- AGENTS.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 217f1ce..e2a83e6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -262,7 +262,8 @@ The project uses `vendor: true` in deno.json. Some dependencies are vendored. Ex Build process injects: - `import.meta.VERSION` - Package version from package.json -- `import.meta.workerDir` - Worker directory path +- `import.meta.ownerSizeTotalWorker` - 'Owner size total' worker path +- `import.meta.creditsWorker` - 'Credits' worker path ### 6. No Network After Key Loading From 5f658c7c2e389fc65bdd462664a49a7963fff675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:58:35 -0400 Subject: [PATCH 15/71] No private API use --- src/serve/routes.ts | 8 +++++--- src/serve/server.ts | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 091758d..1ea6b7a 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -68,9 +68,11 @@ const limiterPerDay = new Bottleneck.Group({ sbp('sbp/selectors/register', { 'backend/server/stopRateLimiters': function () { - clearInterval((limiterPerMinute as unknown as Record>).interval) - clearInterval((limiterPerHour as unknown as Record>).interval) - clearInterval((limiterPerDay as unknown as Record>).interval) + return Promise.allSettled([ + limiterPerMinute.disconnect(), + limiterPerHour.disconnect(), + limiterPerDay.disconnect() + ]) } }) diff --git a/src/serve/server.ts b/src/serve/server.ts index f83536b..734a81a 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -246,11 +246,11 @@ sbp('sbp/selectors/register', { const sizeKey = `_private_contractFilesTotalSize_${resourceID}` return updateSize(resourceID, sizeKey, size, true) }, - 'backend/server/stop': function () { + 'backend/server/stop': async function () { clearInterval(pushHeartbeatIntervalID) ownerSizeTotalWorker?.terminate() creditsWorker?.terminate() - sbp('backend/server/stopRateLimiters') + await sbp('backend/server/stopRateLimiters') return hapi.stop() }, async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { From 0670392fade39a4e7aefd2f4fcf0aa0b03d41673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:15:23 -0400 Subject: [PATCH 16/71] Partially revert --- src/serve/routes.ts | 9 +++++++-- src/serve/server.ts | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 1ea6b7a..0311bbd 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -67,12 +67,17 @@ const limiterPerDay = new Bottleneck.Group({ }) sbp('sbp/selectors/register', { - 'backend/server/stopRateLimiters': function () { - return Promise.allSettled([ + 'backend/server/stopRateLimiters': async function () { + await Promise.allSettled([ limiterPerMinute.disconnect(), limiterPerHour.disconnect(), limiterPerDay.disconnect() ]) + // The following needs to be done using a private API because `disconnect()` + // isn't enough. + clearInterval((limiterPerMinute as unknown as { interval: ReturnType }).interval) + clearInterval((limiterPerHour as unknown as { interval: ReturnType }).interval) + clearInterval((limiterPerDay as unknown as { interval: ReturnType }).interval) } }) diff --git a/src/serve/server.ts b/src/serve/server.ts index 734a81a..edb7374 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -250,7 +250,9 @@ sbp('sbp/selectors/register', { clearInterval(pushHeartbeatIntervalID) ownerSizeTotalWorker?.terminate() creditsWorker?.terminate() - await sbp('backend/server/stopRateLimiters') + if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { + await sbp('backend/server/stopRateLimiters') + } return hapi.stop() }, async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { From 9f95cc8172c74b0ef92173e9aee9ea057cb84372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:28:51 -0400 Subject: [PATCH 17/71] Build artifacts --- build/main.js | 106 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/build/main.js b/build/main.js index b00c4b7..eeaf48a 100644 --- a/build/main.js +++ b/build/main.js @@ -3092,7 +3092,6 @@ import { Buffer as Buffer15 } from "node:buffer"; import { isIP } from "node:net"; import path6 from "node:path"; import process9 from "node:process"; -import { join as join72 } from "node:path"; import process10 from "node:process"; import process11 from "node:process"; import process13 from "node:process"; @@ -9730,7 +9729,7 @@ var require_require_directory = __commonJS({ "node_modules/.deno/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module14) { "use strict"; var fs = __require2("fs"); - var join92 = __require2("path").join; + var join82 = __require2("path").join; var resolve82 = __require2("path").resolve; var dirname72 = __require2("path").dirname; var defaultOptions4 = { @@ -9767,7 +9766,7 @@ var require_require_directory = __commonJS({ } path8 = !path8 ? dirname72(m3.filename) : resolve82(dirname72(m3.filename), path8); fs.readdirSync(path8).forEach(function(filename) { - var joined = join92(path8, filename), files, key, obj; + var joined = join82(path8, filename), files, key, obj; if (fs.statSync(joined).isDirectory() && options2.recurse) { files = requireDirectory(m3, joined, options2); if (Object.keys(files).length) { @@ -87652,7 +87651,7 @@ var require_thread_stream = __commonJS({ var { version: version3 } = require_package6(); var { EventEmitter } = __require2("events"); var { Worker: Worker2 } = __require2("worker_threads"); - var { join: join92 } = __require2("path"); + var { join: join82 } = __require2("path"); var { pathToFileURL } = __require2("url"); var { wait } = require_wait2(); var { @@ -87688,7 +87687,7 @@ var require_thread_stream = __commonJS({ function createWorker2(stream, opts) { const { filename, workerData } = opts; const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; - const toExecute = bundlerOverrides["thread-stream-worker"] || join92(__dirname, "lib", "worker.js"); + const toExecute = bundlerOverrides["thread-stream-worker"] || join82(__dirname, "lib", "worker.js"); const worker = new Worker2(toExecute, { ...opts.workerOpts, trackUnmanagedFds: false, @@ -88072,7 +88071,7 @@ var require_transport = __commonJS({ "use strict"; var { createRequire } = __require2("module"); var getCallers = require_caller(); - var { join: join92, isAbsolute: isAbsolute8, sep } = __require2("path"); + var { join: join82, isAbsolute: isAbsolute8, sep } = __require2("path"); var sleep = require_atomic_sleep(); var onExit = require_on_exit_leak_free(); var ThreadStream = require_thread_stream(); @@ -88131,7 +88130,7 @@ var require_transport = __commonJS({ throw new Error("only one of target or targets can be specified"); } if (targets) { - target = bundlerOverrides["pino-worker"] || join92(__dirname, "worker.js"); + target = bundlerOverrides["pino-worker"] || join82(__dirname, "worker.js"); options2.targets = targets.map((dest) => { return { ...dest, @@ -88139,7 +88138,7 @@ var require_transport = __commonJS({ }; }); } else if (pipeline) { - target = bundlerOverrides["pino-pipeline-worker"] || join92(__dirname, "worker-pipeline.js"); + target = bundlerOverrides["pino-pipeline-worker"] || join82(__dirname, "worker-pipeline.js"); options2.targets = pipeline.map((dest) => { return { ...dest, @@ -88160,7 +88159,7 @@ var require_transport = __commonJS({ return origin; } if (origin === "pino/file") { - return join92(__dirname, "..", "file.js"); + return join82(__dirname, "..", "file.js"); } let fixTarget2; for (const filePath of callers) { @@ -89098,7 +89097,7 @@ var require_safe_stable_stringify = __commonJS({ return circularValue; } let res = ""; - let join92 = ","; + let join82 = ","; const originalIndentation = indentation; if (Array.isArray(value)) { if (value.length === 0) { @@ -89112,7 +89111,7 @@ var require_safe_stable_stringify = __commonJS({ indentation += spacer; res += ` ${indentation}`; - join92 = `, + join82 = `, ${indentation}`; } const maximumValuesToStringify = Math.min(value.length, maximumBreadth); @@ -89120,13 +89119,13 @@ ${indentation}`; for (; i2 < maximumValuesToStringify - 1; i2++) { const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); res += tmp2 !== void 0 ? tmp2 : "null"; - res += join92; + res += join82; } const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); res += tmp !== void 0 ? tmp : "null"; if (value.length - 1 > maximumBreadth) { const removedKeys = value.length - maximumBreadth - 1; - res += `${join92}"... ${getItemCount(removedKeys)} not stringified"`; + res += `${join82}"... ${getItemCount(removedKeys)} not stringified"`; } if (spacer !== "") { res += ` @@ -89147,7 +89146,7 @@ ${originalIndentation}`; let separator = ""; if (spacer !== "") { indentation += spacer; - join92 = `, + join82 = `, ${indentation}`; whitespace = " "; } @@ -89161,13 +89160,13 @@ ${indentation}`; const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation); if (tmp !== void 0) { res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join92; + separator = join82; } } if (keyLength > maximumBreadth) { const removedKeys = keyLength - maximumBreadth; res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`; - separator = join92; + separator = join82; } if (spacer !== "" && separator.length > 1) { res = ` @@ -89208,7 +89207,7 @@ ${originalIndentation}`; } const originalIndentation = indentation; let res = ""; - let join92 = ","; + let join82 = ","; if (Array.isArray(value)) { if (value.length === 0) { return "[]"; @@ -89221,7 +89220,7 @@ ${originalIndentation}`; indentation += spacer; res += ` ${indentation}`; - join92 = `, + join82 = `, ${indentation}`; } const maximumValuesToStringify = Math.min(value.length, maximumBreadth); @@ -89229,13 +89228,13 @@ ${indentation}`; for (; i2 < maximumValuesToStringify - 1; i2++) { const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); res += tmp2 !== void 0 ? tmp2 : "null"; - res += join92; + res += join82; } const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); res += tmp !== void 0 ? tmp : "null"; if (value.length - 1 > maximumBreadth) { const removedKeys = value.length - maximumBreadth - 1; - res += `${join92}"... ${getItemCount(removedKeys)} not stringified"`; + res += `${join82}"... ${getItemCount(removedKeys)} not stringified"`; } if (spacer !== "") { res += ` @@ -89248,7 +89247,7 @@ ${originalIndentation}`; let whitespace = ""; if (spacer !== "") { indentation += spacer; - join92 = `, + join82 = `, ${indentation}`; whitespace = " "; } @@ -89257,7 +89256,7 @@ ${indentation}`; const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation); if (tmp !== void 0) { res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join92; + separator = join82; } } if (spacer !== "" && separator.length > 1) { @@ -89315,20 +89314,20 @@ ${originalIndentation}`; indentation += spacer; let res2 = ` ${indentation}`; - const join10 = `, + const join92 = `, ${indentation}`; const maximumValuesToStringify = Math.min(value.length, maximumBreadth); let i2 = 0; for (; i2 < maximumValuesToStringify - 1; i2++) { const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); res2 += tmp2 !== void 0 ? tmp2 : "null"; - res2 += join10; + res2 += join92; } const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); res2 += tmp !== void 0 ? tmp : "null"; if (value.length - 1 > maximumBreadth) { const removedKeys = value.length - maximumBreadth - 1; - res2 += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; + res2 += `${join92}"... ${getItemCount(removedKeys)} not stringified"`; } res2 += ` ${originalIndentation}`; @@ -89344,16 +89343,16 @@ ${originalIndentation}`; return '"[Object]"'; } indentation += spacer; - const join92 = `, + const join82 = `, ${indentation}`; let res = ""; let separator = ""; let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); if (isTypedArrayWithEntries(value)) { - res += stringifyTypedArray(value, join92, maximumBreadth); + res += stringifyTypedArray(value, join82, maximumBreadth); keys = keys.slice(value.length); maximumPropertiesToStringify -= value.length; - separator = join92; + separator = join82; } if (deterministic) { keys = sort(keys, comparator); @@ -89364,13 +89363,13 @@ ${indentation}`; const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation); if (tmp !== void 0) { res += `${separator}${strEscape(key2)}: ${tmp}`; - separator = join92; + separator = join82; } } if (keyLength > maximumBreadth) { const removedKeys = keyLength - maximumBreadth; res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`; - separator = join92; + separator = join82; } if (separator !== "") { res = ` @@ -94122,6 +94121,7 @@ var init_pubsub2 = __esm({ log.error = (error2, ...args) => logger_default.error(error2, bold.red(tag2, ...args)); defaultServerHandlers = { close() { + clearInterval(this.pingIntervalID); log("Server closed"); }, /** @@ -107713,6 +107713,18 @@ var init_routes = __esm({ reservoirRefreshInterval: 24 * 60 * 60 * SECOND, reservoirRefreshAmount: SIGNUP_LIMIT_DAY }); + esm_default("sbp/selectors/register", { + "backend/server/stopRateLimiters": async function() { + await Promise.allSettled([ + limiterPerMinute.disconnect(), + limiterPerHour.disconnect(), + limiterPerDay.disconnect() + ]); + clearInterval(limiterPerMinute.interval); + clearInterval(limiterPerHour.interval); + clearInterval(limiterPerDay.interval); + } + }); cidLookupTable = { [multicodes.SHELTER_CONTRACT_MANIFEST]: "application/vnd.shelter.contractmanifest+json", [multicodes.SHELTER_CONTRACT_TEXT]: "application/vnd.shelter.contracttext", @@ -108562,6 +108574,7 @@ var CONTRACTS_VERSION; var GI_VERSION; var hapi; var appendToOrphanedNamesIndex; +var pushHeartbeatIntervalID; var init_server = __esm({ "src/serve/server.ts"() { "use strict"; @@ -108590,8 +108603,8 @@ var init_server = __esm({ process10.stderr.write("The size calculation worker must run more frequently than the credits worker for accurate billing"); process10.exit(1); } - ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "ownerSizeTotalWorker.js")); - creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default(join72(import.meta.dirname || ".", "serve", "creditsWorker.js")); + ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/ownerSizeTotalWorker.js"); + creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/creditsWorker.js"); ({ CONTRACTS_VERSION, GI_VERSION } = process10.env); hapi = new Hapi2.Server({ // debug: false, // <- Hapi v16 was outputing too many unnecessary debug statements @@ -108727,7 +108740,13 @@ var init_server = __esm({ const sizeKey = `_private_contractFilesTotalSize_${resourceID}`; return updateSize(resourceID, sizeKey, size, true); }, - "backend/server/stop": function() { + "backend/server/stop": async function() { + clearInterval(pushHeartbeatIntervalID); + ownerSizeTotalWorker?.terminate(); + creditsWorker?.terminate(); + if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { + await esm_default("backend/server/stopRateLimiters"); + } return hapi.stop(); }, async "backend/deleteFile"(cid, ultimateOwnerID, skipIfDeleted) { @@ -109013,7 +109032,7 @@ var init_server = __esm({ })(); (() => { const map = /* @__PURE__ */ new WeakMap(); - setInterval(() => { + pushHeartbeatIntervalID = setInterval(() => { const now = Date.now(); const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); const notification = JSON.stringify({ type: "recurring" }); @@ -109034,7 +109053,8 @@ var init_server = __esm({ }); var serve_exports = {}; __export(serve_exports, { - default: () => serve_default + default: () => serve_default, + removeSignalHandlers: () => removeSignalHandlers }); function logSBP(_domain, selector, data) { if (!dontLog[selector]) { @@ -109045,10 +109065,17 @@ function logSBP(_domain, selector, data) { } } } +function removeSignalHandlers() { + for (const [signal, handler] of signalHandlers) { + process11.removeListener(signal, handler); + } + signalHandlers.length = 0; +} var import_npm_chalk4; var dontLog; var serve_default; var exit2; +var signalHandlers; var handleSignal; var init_serve = __esm({ "src/serve/index.ts"() { @@ -109082,6 +109109,8 @@ var init_serve = __esm({ return new Promise((resolve82) => { pubsub.on("close", async function() { try { + removeSignalHandlers(); + await esm_default("chelonia.persistentActions/unload"); await esm_default("backend/server/stop"); console.info("Hapi server down"); } catch (err) { @@ -109113,11 +109142,14 @@ var init_serve = __esm({ }); esm_default("okTurtles.events/emit", SERVER_EXITING); }; + signalHandlers = []; handleSignal = (signal, code2) => { - process11.on(signal, () => { + const handler = () => { console.error(`Exiting upon receiving ${signal} (${code2})`); exit2(128 + code2); - }); + }; + signalHandlers.push([signal, handler]); + process11.on(signal, handler); }; [ ["SIGHUP", 1], From ba080fb1d9bc84a8cdf201efe1c747a99c991abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:36:10 -0400 Subject: [PATCH 18/71] Feedback --- src/serve/pubsub.ts | 2 +- src/serve/routes-test-helpers.ts | 22 ++++++++-------------- src/serve/server.ts | 8 +++++--- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/serve/pubsub.ts b/src/serve/pubsub.ts index 643f88b..479a72b 100644 --- a/src/serve/pubsub.ts +++ b/src/serve/pubsub.ts @@ -191,7 +191,7 @@ export interface WSS extends Omit { customServerEventHandlers: Partial; customSocketEventHandlers: Partial; customMessageHandlers: Partial; - pingIntervalID?: ReturnType + pingIntervalID?: ReturnType subscribersByChannelID: Record> pushSubscriptions: Record; options: ServerOptions diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts index 216b281..9a4de5d 100644 --- a/src/serve/routes-test-helpers.ts +++ b/src/serve/routes-test-helpers.ts @@ -41,21 +41,21 @@ export function buildSignedKvPayload ( export function saltsAndEncryptedHashedPassword (p: string, secretKey: Uint8Array, hash: string) { const nonce = nacl.randomBytes(nacl.secretbox.nonceLength) const dhKey = nacl.hash(nacl.box.before(Buffer.from(p, 'base64url'), secretKey)) - const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') - const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') - const encryptionKey = nacl.hash(Buffer.from(authSalt + contractSalt)).slice(0, nacl.secretbox.keyLength) + const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).subarray(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).subarray(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const encryptionKey = nacl.hash(Buffer.from(authSalt + contractSalt)).subarray(0, nacl.secretbox.keyLength) const encryptedHashedPassword = Buffer.concat([nonce, nacl.secretbox(Buffer.from(hash), nonce, encryptionKey)]).toString('base64url') return [authSalt, contractSalt, encryptedHashedPassword] } export function decryptRegistrationRedemptionToken (p: string, secretKey: Uint8Array, encryptedToken: string) { const dhKey = nacl.hash(nacl.box.before(Buffer.from(p, 'base64url'), secretKey)) - const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') - const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).slice(0, SALT_LENGTH_IN_OCTETS).toString('base64') - const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), nacl.hash(Buffer.from(authSalt + contractSalt)).slice(0, nacl.secretbox.keyLength)])).slice(0, nacl.secretbox.keyLength) + const authSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(AUTHSALT)), dhKey]))).subarray(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const contractSalt = Buffer.from(nacl.hash(Buffer.concat([nacl.hash(Buffer.from(CONTRACTSALT)), dhKey]))).subarray(0, SALT_LENGTH_IN_OCTETS).toString('base64') + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), nacl.hash(Buffer.from(authSalt + contractSalt)).subarray(0, nacl.secretbox.keyLength)])).subarray(0, nacl.secretbox.keyLength) const encryptedTokenBuf = Buffer.from(encryptedToken, 'base64url') - const nonce = encryptedTokenBuf.slice(0, nacl.secretbox.nonceLength) - const ciphertext = encryptedTokenBuf.slice(nacl.secretbox.nonceLength) + const nonce = encryptedTokenBuf.subarray(0, nacl.secretbox.nonceLength) + const ciphertext = encryptedTokenBuf.subarray(nacl.secretbox.nonceLength) const decrypted = nacl.secretbox.open(ciphertext, nonce, encryptionKey) if (!decrypted) throw new Error('Failed to decrypt token') return Buffer.from(decrypted).toString() @@ -129,12 +129,6 @@ export async function startTestServer (): Promise { } }) - nconf.set('server:host', '127.0.0.1') - nconf.set('server:port', TEST_PORT) - nconf.set('database:backend', 'mem') - nconf.set('server:messages', [{ type: 'info', text: 'test message' }]) - nconf.set('server:archiveMode', false) - const serverAddress = await new Promise((resolve, reject) => { const unregister = sbp('okTurtles.events/once', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { resolve(hapi.info.uri) diff --git a/src/serve/server.ts b/src/serve/server.ts index edb7374..6381357 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -248,12 +248,14 @@ sbp('sbp/selectors/register', { }, 'backend/server/stop': async function () { clearInterval(pushHeartbeatIntervalID) - ownerSizeTotalWorker?.terminate() - creditsWorker?.terminate() if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { await sbp('backend/server/stopRateLimiters') } - return hapi.stop() + await hapi.stop() + await Promise.all([ + ownerSizeTotalWorker?.terminate(), + creditsWorker?.terminate() + ]) }, async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { const owner = await sbp('chelonia.db/get', `_private_owner_${cid}`) From 1f4a5285e12294458e79196f8cfc72c476ea0399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:35:06 -0400 Subject: [PATCH 19/71] Feedback --- src/pin.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index 4f8f69a..e7acd2a 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -74,9 +74,9 @@ export async function pin (args: ArgumentsCamelCase): Promise { } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) - await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath) + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${version}`)) + console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${manifestVersion}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } catch (error) { exit(error) @@ -196,11 +196,11 @@ async function loadCheloniaConfig () { } } -async function updateCheloniaConfig (contractName: string, version: string, manifestPath: string) { +async function updateCheloniaConfig (fullContractName: string, contractName: string, version: string, manifestPath: string) { const manifestFileName = basename(manifestPath) const pinnedManifestPath = `contracts/${contractName}/${version}/${manifestFileName}` - cheloniaConfig.contracts[contractName] = { + cheloniaConfig.contracts[fullContractName] = { version, path: pinnedManifestPath } From 4ad9ee80ff88ce7b637c97789b56219f596d6d74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:39:05 -0400 Subject: [PATCH 20/71] Updates --- build/main.js | 18 +++++++++++------- build/serve/creditsWorker.js | 4 ++-- build/serve/ownerSizeTotalWorker.js | 4 ++-- src/pin.ts | 9 ++++++++- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/build/main.js b/build/main.js index 2cf0783..9284657 100644 --- a/build/main.js +++ b/build/main.js @@ -1,6 +1,6 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/main.js-tmp @@ -110617,10 +110617,11 @@ var module9 = { return migrate(argv); } }; +var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replace(/[/\\:*?"<>|]/g, "_").replace(/\.\./g, "__"); + return contractName.replace(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; @@ -110639,6 +110640,9 @@ async function pin(args) { exit(`Manifest file not found: ${manifestPath}`); } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + if (RESERVED_FILE_CHARS.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`); + } console.log(blue(`Contract name: ${fullContractName}`)); console.log(blue(`Manifest version: ${manifestVersion}`)); if (version3) { @@ -110669,8 +110673,8 @@ async function pin(args) { await createVersionDirectory(contractName, manifestVersion); } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(fullContractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${contractName} to version ${version3}`)); + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); + console.log(green(`\u2705 Successfully pinned ${contractName} to version ${manifestVersion}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { exit(error2); @@ -110757,10 +110761,10 @@ async function loadCheloniaConfig() { cheloniaConfig.contracts = {}; } } -async function updateCheloniaConfig(contractName, version3, manifestPath) { +async function updateCheloniaConfig(fullContractName, contractName, version3, manifestPath) { const manifestFileName = basename42(manifestPath); const pinnedManifestPath = `contracts/${contractName}/${version3}/${manifestFileName}`; - cheloniaConfig.contracts[contractName] = { + cheloniaConfig.contracts[fullContractName] = { version: version3, path: pinnedManifestPath }; diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 7b2d5ed..814a512 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/creditsWorker.js-tmp diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index ec3e39a..deaef25 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1,5 +1,5 @@ -import { createRequire } from "node:module"; -var __require = createRequire(import.meta.url); +import { createRequire as __deno_internal_createRequire } from "node:module"; +var __require = __deno_internal_createRequire(import.meta.url); // build/serve/ownerSizeTotalWorker.js-tmp diff --git a/src/pin.ts b/src/pin.ts index e7acd2a..b2e778b 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,13 +6,15 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' +const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g + type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replace(/[/\\:*?"<>|]/g, '_').replace(/\.\./g, '__') + return contractName.replace(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { @@ -37,6 +39,11 @@ export async function pin (args: ArgumentsCamelCase): Promise { } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + + if (RESERVED_FILE_CHARS.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`) + } + console.log(colors.blue(`Contract name: ${fullContractName}`)) console.log(colors.blue(`Manifest version: ${manifestVersion}`)) From c8a92094551d0362c73be0665c0f6cb2c87322f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:55:23 -0400 Subject: [PATCH 21/71] Avoid `/g` for clarity --- src/pin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pin.ts b/src/pin.ts index b2e778b..e28be09 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,7 +6,7 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' -const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g +const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -14,7 +14,7 @@ let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replace(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') + return contractName.replaceAll(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { From 5239115dc0229555648a05b770ba7f15b380ef06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 22:08:14 -0400 Subject: [PATCH 22/71] Updates --- build/main.js | 6 +++--- src/serve/server.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/build/main.js b/build/main.js index 9284657..be2daaa 100644 --- a/build/main.js +++ b/build/main.js @@ -108591,7 +108591,7 @@ var init_server = __esm({ with: { type: "json" } })).default; } catch { - console.warn("`chelonia.json` not found. Version information will be unavailable."); + console.warn("`chelonia.json` unparsable or not found. Version information will be unavailable."); } })(); ARCHIVE_MODE2 = import_npm_nconf6.default.get("server:archiveMode"); @@ -110617,11 +110617,11 @@ var module9 = { return migrate(argv); } }; -var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/g; +var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replace(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); + return contractName.replaceAll(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; diff --git a/src/serve/server.ts b/src/serve/server.ts index ae5b29e..37a38dd 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -41,7 +41,7 @@ const cheloniaAppManifest = await (async () => { with: { type: 'json' } })).default } catch { - console.warn('`chelonia.json` not found. Version information will be unavailable.') + console.warn('`chelonia.json` unparsable or not found. Version information will be unavailable.') } })() @@ -438,7 +438,7 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { appVersion: cheloniaAppManifest?.appVersion || null, contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( Object.entries(cheloniaAppManifest?.contracts) - .map(([k, v]) => [k, (v as Record).version]) + .map(([k, v]) => [k, (v as { version: string }).version]) ) : null } socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) From 9a84046f6e675a70fa9f1d2c1e7374fbd6a0b3a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 23:30:08 -0400 Subject: [PATCH 23/71] Use separate regexes --- build/main.js | 3 ++- src/pin.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build/main.js b/build/main.js index be2daaa..5ba947c 100644 --- a/build/main.js +++ b/build/main.js @@ -110618,10 +110618,11 @@ var module9 = { } }; var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; +var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { - return contractName.replaceAll(RESERVED_FILE_CHARS, "_").replace(/\.\./g, "__"); + return contractName.replace(RESERVED_FILE_CHARS_REPLACE, "_").replace(/\.\./g, "__"); } async function pin(args) { const version3 = args["manifest-version"]; diff --git a/src/pin.ts b/src/pin.ts index e28be09..78e1b8d 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -7,6 +7,7 @@ import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ +const RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -14,7 +15,7 @@ let projectRoot: string let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { - return contractName.replaceAll(RESERVED_FILE_CHARS, '_').replace(/\.\./g, '__') + return contractName.replace(RESERVED_FILE_CHARS_REPLACE, '_').replace(/\.\./g, '__') } export async function pin (args: ArgumentsCamelCase): Promise { From d9b1488717478d61c3c6e9e4898e0a46b559e760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Wed, 15 Apr 2026 23:47:33 -0400 Subject: [PATCH 24/71] Feedback --- build/main.js | 7 ++++--- src/pin.ts | 8 ++++++-- src/serve/server.ts | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build/main.js b/build/main.js index 83e93fa..66f4c5a 100644 --- a/build/main.js +++ b/build/main.js @@ -73607,8 +73607,9 @@ var init_server = __esm({ init_push(); import_npm_nconf6 = __toESM(require_nconf()); cheloniaAppManifest = await (async () => { + const appDir2 = import_npm_nconf6.default.get("server:appDir") || process10.cwd(); try { - return (await import(pathToFileURL(join82(process10.cwd(), "chelonia.json")).toString(), { + return (await import(pathToFileURL(join82(appDir2, "chelonia.json")).toString(), { with: { type: "json" } })).default; } catch { @@ -75659,7 +75660,7 @@ async function pin(args) { exit(`Manifest file not found: ${manifestPath}`); } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if (RESERVED_FILE_CHARS.test(manifestVersion) || manifestVersion.startsWith(".") || manifestVersion.endsWith(".")) { exit(`Invalid manifest version: ${manifestVersion}`); } console.log(blue(`Contract name: ${fullContractName}`)); @@ -75693,7 +75694,7 @@ async function pin(args) { } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${contractName} to version ${manifestVersion}`)); + console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { exit(error2); diff --git a/src/pin.ts b/src/pin.ts index 78e1b8d..1541d77 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -41,7 +41,11 @@ export async function pin (args: ArgumentsCamelCase): Promise { const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if ( + RESERVED_FILE_CHARS.test(manifestVersion) || + manifestVersion.startsWith('.') || + manifestVersion.endsWith('.') + ) { exit(`Invalid manifest version: ${manifestVersion}`) } @@ -84,7 +88,7 @@ export async function pin (args: ArgumentsCamelCase): Promise { await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${manifestVersion}`)) + console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } catch (error) { exit(error) diff --git a/src/serve/server.ts b/src/serve/server.ts index 36de444..ac2db15 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -36,8 +36,9 @@ import { pathToFileURL } from 'node:url' import nconf from 'npm:nconf' const cheloniaAppManifest = await (async () => { + const appDir = nconf.get('server:appDir') || process.cwd() try { - return (await import(pathToFileURL(join(process.cwd(), 'chelonia.json')).toString(), { + return (await import(pathToFileURL(join(appDir, 'chelonia.json')).toString(), { with: { type: 'json' } })).default } catch { From 37c2927824f484c408465a4e671887a92bb098fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:35:50 -0400 Subject: [PATCH 25/71] Refinements --- build/main.js | 671 ++++++++++++++++++++++++-------- src/serve/auth.ts | 4 +- src/serve/dashboard-server.ts | 13 +- src/serve/routes-writes.test.ts | 4 +- src/serve/routes-zkpp.test.ts | 6 +- src/serve/routes.ts | 310 ++++++++------- 6 files changed, 689 insertions(+), 319 deletions(-) diff --git a/build/main.js b/build/main.js index 66f4c5a..f995478 100644 --- a/build/main.js +++ b/build/main.js @@ -11863,7 +11863,7 @@ ${customMsgs.join("\n")}` : ""; } let parseFn = null; let parseContext = null; - self2.parse = function parse52(args, shortCircuit, _parseFn) { + self2.parse = function parse62(args, shortCircuit, _parseFn) { argsert2("[string|array] [function|boolean|object] [function]", [args, shortCircuit, _parseFn], arguments.length); freeze(); if (typeof args === "undefined") { @@ -46454,7 +46454,7 @@ var require_single_entry_cache = __commonJS({ exports2.default = SingleEntryCache; function makeCircularReplacer() { const seen = /* @__PURE__ */ new WeakSet(); - return function serialize(_, value) { + return function serialize2(_, value) { if (value && typeof value === "object") { if (seen.has(value)) { return "circular"; @@ -60807,8 +60807,8 @@ var require_caller = __commonJS({ var require_validator = __commonJS({ "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/validator.js"(exports2, module14) { "use strict"; - module14.exports = validator; - function validator(opts = {}) { + module14.exports = validator2; + function validator2(opts = {}) { const { ERR_PATHS_MUST_BE_STRINGS = () => "fast-redact - Paths must be (non-empty) strings", ERR_INVALID_PATH = (s) => `fast-redact \u2013 Invalid path (${s})` @@ -60847,8 +60847,8 @@ var require_parse = __commonJS({ "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/parse.js"(exports2, module14) { "use strict"; var rx = require_rx(); - module14.exports = parse52; - function parse52({ paths }) { + module14.exports = parse62; + function parse62({ paths }) { const wildcards = []; var wcLen = 0; const secret = paths.reduce(function(o2, strPath, ix) { @@ -60892,10 +60892,10 @@ var require_redactor = __commonJS({ "use strict"; var rx = require_rx(); module14.exports = redactor; - function redactor({ secret, serialize, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { + function redactor({ secret, serialize: serialize2, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { const redact = Function("o", ` if (typeof o !== 'object' || o == null) { - ${strictImpl(strict, serialize)} + ${strictImpl(strict, serialize2)} } const { censor, secret } = this const originalSecret = {} @@ -60908,10 +60908,10 @@ var require_redactor = __commonJS({ this.compileRestore() ${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} this.secret = originalSecret - ${resultTmpl(serialize)} + ${resultTmpl(serialize2)} `).bind(state); redact.state = state; - if (serialize === false) { + if (serialize2 === false) { redact.restore = (o2) => state.restore(o2); } return redact; @@ -60969,15 +60969,15 @@ var require_redactor = __commonJS({ } ` : ""; } - function resultTmpl(serialize) { - return serialize === false ? `return o` : ` + function resultTmpl(serialize2) { + return serialize2 === false ? `return o` : ` var s = this.serialize(o) this.restore(o) return s `; } - function strictImpl(strict, serialize) { - return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize === false ? `return o` : `return this.serialize(o)`; + function strictImpl(strict, serialize2) { + return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize2 === false ? `return o` : `return this.serialize(o)`; } } }); @@ -61268,14 +61268,14 @@ var require_state = __commonJS({ secret, censor, compileRestore, - serialize, + serialize: serialize2, groupRedact, nestedRedact, wildcards, wcLen } = o2; const builder = [{ secret, censor, compileRestore }]; - if (serialize !== false) builder.push({ serialize }); + if (serialize2 !== false) builder.push({ serialize: serialize2 }); if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }); return Object.assign(...builder); } @@ -61284,40 +61284,40 @@ var require_state = __commonJS({ var require_fast_redact = __commonJS({ "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/index.js"(exports2, module14) { "use strict"; - var validator = require_validator(); - var parse52 = require_parse(); + var validator2 = require_validator(); + var parse62 = require_parse(); var redactor = require_redactor(); var restorer = require_restorer(); var { groupRedact, nestedRedact } = require_modifiers(); var state = require_state(); var rx = require_rx(); - var validate = validator(); + var validate = validator2(); var noop = (o2) => o2; noop.restore = noop; var DEFAULT_CENSOR = "[REDACTED]"; fastRedact.rx = rx; - fastRedact.validator = validator; + fastRedact.validator = validator2; module14.exports = fastRedact; function fastRedact(opts = {}) { const paths = Array.from(new Set(opts.paths || [])); - const serialize = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; + const serialize2 = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; const remove = opts.remove; - if (remove === true && serialize !== JSON.stringify) { + if (remove === true && serialize2 !== JSON.stringify) { throw Error("fast-redact \u2013 remove option may only be set when serializer is JSON.stringify"); } const censor = remove === true ? void 0 : "censor" in opts ? opts.censor : DEFAULT_CENSOR; const isCensorFct = typeof censor === "function"; const censorFctTakesPath = isCensorFct && censor.length > 1; - if (paths.length === 0) return serialize || noop; - validate({ paths, serialize, censor }); - const { wildcards, wcLen, secret } = parse52({ paths, censor }); + if (paths.length === 0) return serialize2 || noop; + validate({ paths, serialize: serialize2, censor }); + const { wildcards, wcLen, secret } = parse62({ paths, censor }); const compileRestore = restorer(); const strict = "strict" in opts ? opts.strict : true; - return redactor({ secret, wcLen, serialize, strict, isCensorFct, censorFctTakesPath }, state({ + return redactor({ secret, wcLen, serialize: serialize2, strict, isCensorFct, censorFctTakesPath }, state({ secret, censor, compileRestore, - serialize, + serialize: serialize2, groupRedact, nestedRedact, wildcards, @@ -61400,14 +61400,14 @@ var require_redaction = __commonJS({ "use strict"; var fastRedact = require_fast_redact(); var { redactFmtSym, wildcardFirstSym } = require_symbols(); - var { rx, validator } = fastRedact; - var validate = validator({ + var { rx, validator: validator2 } = fastRedact; + var validate = validator2({ ERR_PATHS_MUST_BE_STRINGS: () => "pino \u2013 redacted paths must be strings", ERR_INVALID_PATH: (s) => `pino \u2013 redact paths array contains an invalid path (${s})` }); var CENSOR = "[Redacted]"; var strict = false; - function redaction(opts, serialize) { + function redaction(opts, serialize2) { const { paths, censor } = handle(opts); const shape = paths.reduce((o2, str) => { rx.lastIndex = 0; @@ -61441,10 +61441,10 @@ var require_redaction = __commonJS({ return o2; }, {}); const result = { - [redactFmtSym]: fastRedact({ paths, censor, serialize, strict }) + [redactFmtSym]: fastRedact({ paths, censor, serialize: serialize2, strict }) }; const topCensor = (...args) => { - return typeof censor === "function" ? serialize(censor(...args)) : serialize(censor); + return typeof censor === "function" ? serialize2(censor(...args)) : serialize2(censor); }; return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o2, k) => { if (shape[k] === null) { @@ -61456,7 +61456,7 @@ var require_redaction = __commonJS({ o2[k] = fastRedact({ paths: shape[k], censor: wrappedCensor, - serialize, + serialize: serialize2, strict }); } @@ -68006,7 +68006,7 @@ var require_extension = __commonJS({ if (dest[name] === void 0) dest[name] = [elem]; else dest[name].push(elem); } - function parse52(header) { + function parse62(header) { const offers = /* @__PURE__ */ Object.create(null); let params = /* @__PURE__ */ Object.create(null); let mustUnescape = false; @@ -68146,7 +68146,7 @@ var require_extension = __commonJS({ }).join(", "); }).join(", "); } - module14.exports = { format: format52, parse: parse52 }; + module14.exports = { format: format52, parse: parse62 }; } }); var require_websocket = __commonJS({ @@ -68176,7 +68176,7 @@ var require_websocket = __commonJS({ var { EventTarget: { addEventListener: addEventListener2, removeEventListener } } = require_event_target(); - var { format: format52, parse: parse52 } = require_extension(); + var { format: format52, parse: parse62 } = require_extension(); var { toBuffer } = require_buffer_util(); var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; @@ -68814,7 +68814,7 @@ var require_websocket = __commonJS({ } let extensions; try { - extensions = parse52(secWebSocketExtensions); + extensions = parse62(secWebSocketExtensions); } catch (err) { const message = "Invalid Sec-WebSocket-Extensions header"; abortHandshake(websocket, socket, message); @@ -68975,7 +68975,7 @@ var require_subprotocol = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/subprotocol.js"(exports2, module14) { "use strict"; var { tokenChars } = require_validation(); - function parse52(header) { + function parse62(header) { const protocols = /* @__PURE__ */ new Set(); let start = -1; let end = -1; @@ -69011,7 +69011,7 @@ var require_subprotocol = __commonJS({ protocols.add(protocol); return protocols; } - module14.exports = { parse: parse52 }; + module14.exports = { parse: parse62 }; } }); var require_websocket_server = __commonJS({ @@ -72589,14 +72589,14 @@ function extractBearer(c) { const authorization = c.req.header("authorization"); if (!authorization) return null; const prefix = "bearer "; - if (authorization.slice(0, prefix.length) !== prefix) return null; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; return { token: authorization.slice(prefix.length) }; } function extractShelter(c) { const authorization = c.req.header("authorization"); if (!authorization) return null; const prefix = "shelter "; - if (authorization.slice(0, prefix.length) !== prefix) return null; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; try { const billableContractID = verifyShelterAuthorizationHeader(authorization); return { billableContractID }; @@ -72638,6 +72638,300 @@ var init_auth = __esm({ }; } }); +var validCookieNameRegEx; +var validCookieValueRegEx; +var trimCookieWhitespace; +var parse42; +var init_cookie = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/cookie.js"() { + init_url(); + validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/; + validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/; + trimCookieWhitespace = (value) => { + let start = 0; + let end = value.length; + while (start < end) { + const charCode = value.charCodeAt(start); + if (charCode !== 32 && charCode !== 9) { + break; + } + start++; + } + while (end > start) { + const charCode = value.charCodeAt(end - 1); + if (charCode !== 32 && charCode !== 9) { + break; + } + end--; + } + return start === 0 && end === value.length ? value : value.slice(start, end); + }; + parse42 = (cookie, name) => { + if (name && cookie.indexOf(name) === -1) { + return {}; + } + const pairs = cookie.split(";"); + const parsedCookie = {}; + for (const pairStr of pairs) { + const valueStartPos = pairStr.indexOf("="); + if (valueStartPos === -1) { + continue; + } + const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos)); + if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) { + continue; + } + let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1)); + if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) { + cookieValue = cookieValue.slice(1, -1); + } + if (validCookieValueRegEx.test(cookieValue)) { + parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue; + if (name) { + break; + } + } + } + return parsedCookie; + }; + } +}); +var getCookie; +var init_cookie2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/cookie/index.js"() { + init_cookie(); + getCookie = (c, key, prefix) => { + const cookie = c.req.raw.headers.get("Cookie"); + if (typeof key === "string") { + if (!cookie) { + return void 0; + } + let finalKey = key; + if (prefix === "secure") { + finalKey = "__Secure-" + key; + } else if (prefix === "host") { + finalKey = "__Host-" + key; + } + const obj2 = parse42(cookie, finalKey); + return obj2[finalKey]; + } + if (!cookie) { + return {}; + } + const obj = parse42(cookie); + return obj; + }; + } +}); +var init_crypto = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/crypto.js"() { + } +}); +var bufferToFormData; +var init_buffer = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/buffer.js"() { + init_crypto(); + bufferToFormData = (arrayBuffer, contentType) => { + const response = new Response(arrayBuffer, { + headers: { + "Content-Type": contentType + } + }); + return response.formData(); + }; + } +}); +var jsonRegex; +var multipartRegex; +var urlencodedRegex; +var validator; +var init_validator = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/validator/validator.js"() { + init_cookie2(); + init_http_exception(); + init_buffer(); + jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; + multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/; + urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; + validator = (target, validationFunc) => { + return async (c, next) => { + let value = {}; + const contentType = c.req.header("Content-Type"); + switch (target) { + case "json": + if (!contentType || !jsonRegex.test(contentType)) { + break; + } + try { + value = await c.req.json(); + } catch { + const message = "Malformed JSON in request body"; + throw new HTTPException(400, { message }); + } + break; + case "form": { + if (!contentType || !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))) { + break; + } + let formData; + if (c.req.bodyCache.formData) { + formData = await c.req.bodyCache.formData; + } else { + try { + const arrayBuffer = await c.req.arrayBuffer(); + formData = await bufferToFormData(arrayBuffer, contentType); + c.req.bodyCache.formData = formData; + } catch (e2) { + let message = "Malformed FormData request."; + message += e2 instanceof Error ? ` ${e2.message}` : ` ${String(e2)}`; + throw new HTTPException(400, { message }); + } + } + const form = /* @__PURE__ */ Object.create(null); + formData.forEach((value2, key) => { + if (key.endsWith("[]")) { + ; + (form[key] ??= []).push(value2); + } else if (Array.isArray(form[key])) { + ; + form[key].push(value2); + } else if (Object.hasOwn(form, key)) { + form[key] = [form[key], value2]; + } else { + form[key] = value2; + } + }); + value = form; + break; + } + case "query": + value = Object.fromEntries( + Object.entries(c.req.queries()).map(([k, v2]) => { + return v2.length === 1 ? [k, v2[0]] : [k, v2]; + }) + ); + break; + case "param": + value = c.req.param(); + break; + case "header": + value = c.req.header(); + break; + case "cookie": + value = getCookie(c); + break; + } + const res = await validationFunc(value, c); + if (res instanceof Response) { + return res; + } + c.req.addValidatedData(target, res); + return await next(); + }; + }; + } +}); +var init_validator2 = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/validator/index.js"() { + init_validator(); + } +}); +function zValidatorFunction(target, schema, hook, options2) { + return validator(target, async (value, c) => { + let validatorValue = value; + if (target === "header" && "_def" in schema || target === "header" && "_zod" in schema) { + const schemaKeys = Object.keys("in" in schema ? schema.in.shape : schema.shape); + const caseInsensitiveKeymap = Object.fromEntries(schemaKeys.map((key) => [key.toLowerCase(), key])); + validatorValue = Object.fromEntries(Object.entries(value).map(([key, value$1]) => [caseInsensitiveKeymap[key] || key, value$1])); + } + const result = options2 && options2.validationFunction ? await options2.validationFunction(schema, validatorValue) : await schema.safeParseAsync(validatorValue); + if (hook) { + const hookResult = await hook({ + data: validatorValue, + ...result, + target + }, c); + if (hookResult) { + if (hookResult instanceof Response) return hookResult; + if ("response" in hookResult) return hookResult.response; + } + } + if (!result.success) return c.json(result, 400); + return result.data; + }); +} +var zValidator; +var init_dist3 = __esm({ + "node_modules/.deno/@hono+zod-validator@0.7.6/node_modules/@hono/zod-validator/dist/index.js"() { + init_validator2(); + zValidator = zValidatorFunction; + } +}); +var ERROR_MESSAGE; +var BodyLimitError; +var bodyLimit; +var init_body_limit = __esm({ + "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/body-limit/index.js"() { + init_http_exception(); + ERROR_MESSAGE = "Payload Too Large"; + BodyLimitError = class extends Error { + constructor(message) { + super(message); + this.name = "BodyLimitError"; + } + }; + bodyLimit = (options2) => { + const onError = options2.onError || (() => { + const res = new Response(ERROR_MESSAGE, { + status: 413 + }); + throw new HTTPException(413, { res }); + }); + const maxSize = options2.maxSize; + return async function bodyLimit2(c, next) { + if (!c.req.raw.body) { + return next(); + } + const hasTransferEncoding = c.req.raw.headers.has("transfer-encoding"); + const hasContentLength = c.req.raw.headers.has("content-length"); + if (hasTransferEncoding && hasContentLength) { + } + if (hasContentLength && !hasTransferEncoding) { + const contentLength = parseInt(c.req.raw.headers.get("content-length") || "0", 10); + return contentLength > maxSize ? onError(c) : next(); + } + let size = 0; + const rawReader = c.req.raw.body.getReader(); + const reader = new ReadableStream({ + async start(controller) { + try { + for (; ; ) { + const { done, value } = await rawReader.read(); + if (done) { + break; + } + size += value.length; + if (size > maxSize) { + controller.error(new BodyLimitError(ERROR_MESSAGE)); + break; + } + controller.enqueue(value); + } + } finally { + controller.close(); + } + } + }); + const requestInit = { body: reader, duplex: "half" }; + c.req.raw = new Request(c.req.raw, requestInit); + await next(); + if (c.error instanceof BodyLimitError) { + c.res = await onError(c); + } + }; + }; + } +}); var routes_exports = {}; __export(routes_exports, { staticServeConfig: () => staticServeConfig @@ -72655,13 +72949,6 @@ function getClientIP(c) { function notFoundNoCache(c) { return c.body(null, 404, { "Cache-Control": "no-store" }); } -async function parseRequestBody(c) { - const contentType = c.req.header("content-type") || ""; - if (contentType.includes("application/json")) { - return await c.req.json(); - } - return await c.req.parseBody(); -} var import_npm_bottleneck; var import_npm_chalk2; var import_npm_nconf5; @@ -72671,6 +72958,21 @@ var CID_REGEX; var KV_KEY_REGEX; var NAME_REGEX; var POSITIVE_INTEGER_REGEX; +var cidSchema; +var nameSchema; +var kvKeySchema; +var positiveIntegerSchema; +var cidParamSchema; +var cidHashParamSchema; +var nameParamSchema; +var kvParamSchema; +var eventsAfterParamSchema; +var zkppContractParamSchema; +var zkppAuthHashQuerySchema; +var zkppContractHashQuerySchema; +var eventHeaderSchema; +var zkppRegisterBodySchema; +var zkppUpdatePasswordBodySchema; var FILE_UPLOAD_MAX_BYTES; var SIGNUP_LIMIT_MIN; var SIGNUP_LIMIT_HOUR; @@ -72707,12 +73009,53 @@ var init_routes = __esm({ init_zkppSalt(); import_npm_nconf5 = __toESM(require_nconf()); init_auth(); + init_dist3(); + init_zod(); + init_body_limit(); MEGABYTE = 1048576; SECOND = 1e3; CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? FILE_UPLOAD_MAX_BYTES) { - throw new HTTPException(413, { message: "Payload too large" }); - } const formData = await c.req.formData(); const manifestFile = formData.get("manifest"); if (!manifestFile) throw new HTTPException(400, { message: "missing manifest" }); @@ -73154,9 +73487,8 @@ var init_routes = __esm({ } } ); - app.get("/file/:hash", async function(c) { - const hash3 = c.req.param("hash"); - if (!CID_REGEX.test(hash3)) throw new HTTPException(400, { message: "Invalid hash" }); + app.get("/file/:hash", zValidator("param", cidHashParamSchema), async function(c) { + const { hash: hash3 } = c.req.valid("param"); const parsed = maybeParseCID(hash3); if (!parsed) { throw new HTTPException(400); @@ -73184,10 +73516,10 @@ var init_routes = __esm({ app.post( "/deleteFile/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), + zValidator("param", cidHashParamSchema), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const hash3 = c.req.param("hash"); - if (!CID_REGEX.test(hash3)) throw new HTTPException(400, { message: "Invalid hash" }); + const { hash: hash3 } = c.req.valid("param"); const strategy = c.get("authStrategy"); const parsed = maybeParseCID(hash3); if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { @@ -73231,11 +73563,11 @@ var init_routes = __esm({ app.post( "/deleteContract/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), + zValidator("param", cidHashParamSchema), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const hash3 = c.req.param("hash"); + const { hash: hash3 } = c.req.valid("param"); const strategy = c.get("authStrategy"); - if (!hash3 || hash3.startsWith("_private")) throw new HTTPException(404); const credentials = c.get("credentials"); switch (strategy) { case "chel-shelter": { @@ -73278,13 +73610,12 @@ var init_routes = __esm({ ); app.post( "/kv/:contractID/:key", + bodyLimit({ maxSize: 6 * MEGABYTE }), authMiddleware("chel-shelter", "required"), + zValidator("param", kvParamSchema), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const contractID = c.req.param("contractID"); - const key = c.req.param("key"); - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); - if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: "Invalid key" }); + const { contractID, key } = c.req.valid("param"); const parsed = maybeParseCID(contractID); if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { throw new HTTPException(400); @@ -73346,11 +73677,9 @@ var init_routes = __esm({ app.get( "/kv/:contractID/:key", authMiddleware("chel-shelter", "required"), + zValidator("param", kvParamSchema), async function(c) { - const contractID = c.req.param("contractID"); - const key = c.req.param("key"); - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); - if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: "Invalid key" }); + const { contractID, key } = c.req.valid("param"); const parsed = maybeParseCID(contractID); if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { throw new HTTPException(400); @@ -73479,95 +73808,97 @@ var init_routes = __esm({ app.get("/", function(c) { return c.redirect(staticServeConfig.redirect); }); - app.post("/zkpp/register/:name", async function(c) { - const name = c.req.param("name"); - if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: "Invalid name" }); - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const lookupResult = await esm_default("backend/db/lookupName", name); - if (lookupResult) { - throw new HTTPException(409); - } - try { - const payload = await parseRequestBody(c); - if (payload.b) { - if (typeof payload.b !== "string") throw new HTTPException(400); - const result = registrationKey(name, payload.b); - if (result) { - return c.json(result); - } - } else if (payload.r && payload.s && payload.sig && payload.Eh) { - if (typeof payload.r !== "string" || typeof payload.s !== "string" || typeof payload.sig !== "string" || typeof payload.Eh !== "string") { - throw new HTTPException(400); - } - const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); - if (result) { - return c.json(result); + app.post( + "/zkpp/register/:name", + zValidator("param", nameParamSchema), + zValidator("json", zkppRegisterBodySchema), + async function(c) { + const { name } = c.req.valid("param"); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const lookupResult = await esm_default("backend/db/lookupName", name); + if (lookupResult) { + throw new HTTPException(409); + } + try { + const payload = c.req.valid("json"); + if ("b" in payload) { + const result = registrationKey(name, payload.b); + if (result) { + return c.json(result); + } + } else { + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); + if (result) { + return c.json(result); + } } - } else { - throw new HTTPException(400, { message: "Invalid payload" }); + } catch (e2) { + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); + console.error(e2, "Error at POST /zkpp/{name}: " + e2.message); } - } catch (e2) { - if (e2 instanceof HTTPException) throw e2; - e2.ip = getClientIP(c); - console.error(e2, "Error at POST /zkpp/{name}: " + e2.message); - } - throw new HTTPException(500, { message: "internal error" }); - }); - app.get("/zkpp/:contractID/auth_hash", async function(c) { - const contractID = c.req.param("contractID"); - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); - const b = c.req.query("b"); - if (!b) throw new HTTPException(400, { message: "b is required" }); - try { - const challenge = await getChallenge(contractID, b); - return challenge ? c.json(challenge) : notFoundNoCache(c); - } catch (e2) { - ; - e2.ip = getClientIP(c); - console.error(e2, "Error at GET /zkpp/{contractID}/auth_hash: " + e2.message); + throw new HTTPException(500, { message: "internal error" }); } - throw new HTTPException(500, { message: "internal error" }); - }); - app.get("/zkpp/:contractID/contract_hash", async function(c) { - const contractID = c.req.param("contractID"); - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); - const r = c.req.query("r"); - const s = c.req.query("s"); - const sig = c.req.query("sig"); - const hc = c.req.query("hc"); - if (!r || !s || !sig || !hc) throw new HTTPException(400, { message: "r, s, sig, and hc are required" }); - try { - const salt = await getContractSalt(contractID, r, s, sig, hc); - if (salt) { - return c.json(salt); + ); + app.get( + "/zkpp/:contractID/auth_hash", + zValidator("param", zkppContractParamSchema), + zValidator("query", zkppAuthHashQuerySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + const { b } = c.req.valid("query"); + try { + const challenge = await getChallenge(contractID, b); + return challenge ? c.json(challenge) : notFoundNoCache(c); + } catch (e2) { + ; + e2.ip = getClientIP(c); + console.error(e2, "Error at GET /zkpp/{contractID}/auth_hash: " + e2.message); } - } catch (e2) { - ; - e2.ip = getClientIP(c); - console.error(e2, "Error at GET /zkpp/{contractID}/contract_hash: " + e2.message); + throw new HTTPException(500, { message: "internal error" }); } - throw new HTTPException(500, { message: "internal error" }); - }); - app.post("/zkpp/:contractID/updatePasswordHash", async function(c) { - const contractID = c.req.param("contractID"); - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: "Invalid contractID" }); - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - try { - const payload = await parseRequestBody(c); - if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { - throw new HTTPException(400, { message: "r, s, sig, hc, and Ea are required" }); + ); + app.get( + "/zkpp/:contractID/contract_hash", + zValidator("param", zkppContractParamSchema), + zValidator("query", zkppContractHashQuerySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + const { r, s, sig, hc } = c.req.valid("query"); + try { + const salt = await getContractSalt(contractID, r, s, sig, hc); + if (salt) { + return c.json(salt); + } + } catch (e2) { + ; + e2.ip = getClientIP(c); + console.error(e2, "Error at GET /zkpp/{contractID}/contract_hash: " + e2.message); } - const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); - if (result) { - return c.json(result); + throw new HTTPException(500, { message: "internal error" }); + } + ); + app.post( + "/zkpp/:contractID/updatePasswordHash", + zValidator("param", zkppContractParamSchema), + zValidator("json", zkppUpdatePasswordBodySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + try { + const payload = c.req.valid("json"); + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); + if (result) { + return c.json(result); + } + } catch (e2) { + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); + console.error(e2, "Error at POST /zkpp/{contractID}/updatePasswordHash: " + e2.message); } - } catch (e2) { - if (e2 instanceof HTTPException) throw e2; - e2.ip = getClientIP(c); - console.error(e2, "Error at POST /zkpp/{contractID}/updatePasswordHash: " + e2.message); + throw new HTTPException(500, { message: "internal error" }); } - throw new HTTPException(500, { message: "internal error" }); - }); + ); } }); var server_exports = {}; @@ -79601,7 +79932,7 @@ function Yargs(processArgs = [], cwd = shim3.process.cwd(), parentRequire) { } let parseFn = null; let parseContext = null; - self2.parse = function parse52(args, shortCircuit, _parseFn) { + self2.parse = function parse62(args, shortCircuit, _parseFn) { argsert("[string|array] [function|boolean|object] [function]", [args, shortCircuit, _parseFn], arguments.length); freeze(); if (typeof args === "undefined") { diff --git a/src/serve/auth.ts b/src/serve/auth.ts index 84e7ca1..4834d2e 100644 --- a/src/serve/auth.ts +++ b/src/serve/auth.ts @@ -18,7 +18,7 @@ function extractBearer (c: Context): AuthCredentials | null { const authorization = c.req.header('authorization') if (!authorization) return null const prefix = 'bearer ' - if (authorization.slice(0, prefix.length) !== prefix) return null + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null return { token: authorization.slice(prefix.length) } } @@ -26,7 +26,7 @@ function extractShelter (c: Context): AuthCredentials | null { const authorization = c.req.header('authorization') if (!authorization) return null const prefix = 'shelter ' - if (authorization.slice(0, prefix.length) !== prefix) return null + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null try { const billableContractID = verifyShelterAuthorizationHeader(authorization) return { billableContractID } diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index 4eced9a..c18516e 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -21,9 +21,16 @@ export async function startDashboard (): Promise { app.get('/dashboard', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) app.get('/dashboard/', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) - app.get('/*', serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })) - - app.get('/*', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) + // SPA fallback: try static file first, then serve index.html for SPA routing + app.get('/*', async (c) => { + const staticResponse = await serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })(c, async () => {}) + // If static file exists and was served successfully, return it + if (staticResponse && staticResponse.status !== 404) { + return staticResponse + } + // File not found, serve index.html for SPA routing + return serveStatic({ path: path.join(dashboardRoot, 'index.html') })(c, async () => {}) + }) await new Promise((resolve) => { Deno.serve({ port, hostname: host, onListen: () => resolve() }, app.fetch) diff --git a/src/serve/routes-writes.test.ts b/src/serve/routes-writes.test.ts index 9ecd4de..2bc21cb 100644 --- a/src/serve/routes-writes.test.ts +++ b/src/serve/routes-writes.test.ts @@ -295,14 +295,14 @@ Deno.test({ if (res.status !== 401) throw new Error(`Expected 401 but got ${res.status}`) }) - await t.step('POST /deleteContract with _private prefix returns 404', async () => { + await t.step('POST /deleteContract with _private prefix returns 400 (invalid CID)', async () => { const auth = buildShelterAuthHeader(owner.contractID, owner.SAK) const res = await fetch(`${baseURL}/deleteContract/_private_something`, { method: 'POST', headers: { authorization: auth } }) await res.body?.cancel() - if (res.status !== 404) throw new Error(`Expected 404 but got ${res.status}`) + if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) }) await t.step('POST /deleteContract with nonexistent contract returns 404', async () => { diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index 73a7f69..ada7686 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -18,7 +18,7 @@ Deno.test({ const baseURL = await startTestServer() try { - await t.step('POST /zkpp/register step 1: returns {s, p, sig}', async () => { + await t.step('POST /zkpp/register step 1 with JSON body', async () => { const keyPair = nacl.box.keyPair() const publicKeyHash = Buffer.from(nacl.hash(Buffer.from( Buffer.from(keyPair.publicKey).toString('base64url') @@ -35,7 +35,7 @@ Deno.test({ if (!body.sig) throw new Error('Expected sig in response') }) - await t.step('POST /zkpp/register step 2: completes registration', async () => { + await t.step('POST /zkpp/register step 2 with JSON body', async () => { const keyPair = nacl.box.keyPair() const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') @@ -112,7 +112,7 @@ Deno.test({ if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) }) - await t.step('POST /zkpp/{contractID}/updatePasswordHash with missing params returns 400', async () => { + await t.step('POST /zkpp/{contractID}/updatePasswordHash with JSON body returns 400 for missing params', async () => { const cid = createCID('zkpp-test', multicodes.SHELTER_CONTRACT_DATA) const res = await fetch(`${baseURL}/zkpp/${cid}/updatePasswordHash`, { method: 'POST', diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 25ecf07..ef404dd 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -22,6 +22,9 @@ import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltU import nconf from 'npm:nconf' import { authMiddleware, type AuthCredentials } from './auth.ts' import type { Hono, Context } from 'npm:hono' +import { zValidator } from 'npm:@hono/zod-validator' +import * as z from 'npm:zod' +import { bodyLimit } from 'npm:hono/body-limit' import { Readable } from 'node:stream' const MEGABYTE = 1048576 // TODO: add settings for these @@ -39,6 +42,47 @@ const KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/ const NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(?> (c: Context): Promise { - const contentType = c.req.header('content-type') || '' - if (contentType.includes('application/json')) { - return await c.req.json() as T - } - return await c.req.parseBody() as T +function safePathWithin (base: string, subpath: string): string | null { + const resolved = path.resolve(base, subpath) + if (!resolved.startsWith(base + path.sep) && resolved !== base) return null + return resolved } // Get the Hono app via SERVER_INSTANCE @@ -221,7 +263,9 @@ const app: Hono = sbp('okTurtles.data/get', SERVER_INSTANCE) // —BUT HTTP2 might be better than websockets and so we keep this around. // See related TODO in pubsub.js and the reddit discussion link. app.post('/event', + bodyLimit({ maxSize: MEGABYTE }), authMiddleware('chel-shelter', 'optional'), + zValidator('header', eventHeaderSchema), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE @@ -230,10 +274,7 @@ app.post('/event', try { const payload = await c.req.text() if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) - const namespaceRegistration = c.req.header('shelter-namespace-registration') - if (namespaceRegistration && !NAME_REGEX.test(namespaceRegistration)) { - throw new HTTPException(400, { message: 'Invalid shelter-namespace-registration header' }) - } + const validatedHeaders = c.req.valid('header') const deserializedHEAD = SPMessage.deserializeHEAD(payload) try { const parsed = maybeParseCID(deserializedHEAD.head.manifest) @@ -266,7 +307,7 @@ app.post('/event', } } } - const saltUpdateToken = c.req.header('shelter-salt-update-token') + const saltUpdateToken = validatedHeaders['shelter-salt-update-token'] let updateSalts if (saltUpdateToken) { // If we've got a salt update token (i.e., a password change), @@ -289,7 +330,7 @@ app.post('/event', // If this is the first message in a contract and the // `shelter-namespace-registration` header is present, proceed with also // registering a name for the new contract - const name = c.req.header('shelter-namespace-registration') + const name = validatedHeaders['shelter-namespace-registration'] if (name) { // Name registation is enabled only for identity contracts const cheloniaState = sbp('chelonia/rootState') @@ -302,7 +343,7 @@ app.post('/event', } throw registerErr } - const saltRegistrationToken = c.req.header('shelter-salt-registration-token') + const saltRegistrationToken = validatedHeaders['shelter-salt-registration-token'] console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`) if (saltRegistrationToken) { // If we've got a salt registration token, redeem it @@ -310,7 +351,7 @@ app.post('/event', } } } - const deletionTokenDgst = c.req.header('shelter-deletion-token-digest') + const deletionTokenDgst = validatedHeaders['shelter-deletion-token-digest'] if (deletionTokenDgst) { await sbp('chelonia.db/set', `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst) } @@ -343,14 +384,9 @@ app.post('/event', }) app.get('/eventsAfter/:contractID/:since/:limit?', + zValidator('param', eventsAfterParamSchema), async function (c) { - const contractID = c.req.param('contractID') - const since = c.req.param('since') - const limit = c.req.param('limit') - - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - if (!POSITIVE_INTEGER_REGEX.test(since)) throw new HTTPException(400, { message: 'Invalid since' }) - if (limit !== undefined && !POSITIVE_INTEGER_REGEX.test(limit)) throw new HTTPException(400, { message: 'Invalid limit' }) + const { contractID, since, limit } = c.req.valid('param') const keyOps = c.req.query('keyOps') const ip = getClientIP(c) @@ -430,9 +466,8 @@ app.post('/name', async function (c) { }) */ -app.get('/name/:name', async function (c) { - const name = c.req.param('name') - if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: 'Invalid name' }) +app.get('/name/:name', zValidator('param', nameParamSchema), async function (c) { + const { name } = c.req.valid('param') try { const lookupResult = await sbp('backend/db/lookupName', name) return lookupResult @@ -444,9 +479,8 @@ app.get('/name/:name', async function (c) { } }) -app.get('/latestHEADinfo/:contractID', async function (c) { - const contractID = c.req.param('contractID') - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) +app.get('/latestHEADinfo/:contractID', zValidator('param', cidParamSchema), async function (c) { + const { contractID } = c.req.valid('param') try { const parsed = maybeParseCID(contractID) if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) @@ -493,7 +527,7 @@ app.post('/streams-test', async function (c) { // doesn't set or read accounting information. // If accepted, the file will be stored in Chelonia DB. if (process.env.NODE_ENV === 'development') { - app.post('/dev-file', async function (c) { + app.post('/dev-file', bodyLimit({ maxSize: 6 * MEGABYTE }), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { console.log('FILE UPLOAD!') @@ -524,6 +558,7 @@ if (process.env.NODE_ENV === 'development') { // File upload route. // If accepted, the file will be stored in Chelonia DB. app.post('/file', + bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), authMiddleware('chel-shelter', 'required'), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) @@ -539,12 +574,6 @@ app.post('/file', throw new HTTPException(400, { message: 'Expected multipart/form-data' }) } - // Check content-length before reading body - const contentLength = parseInt(c.req.header('content-length') || '0', 10) - if (contentLength > FILE_UPLOAD_MAX_BYTES) { - throw new HTTPException(413, { message: 'Payload too large' }) - } - const formData = await c.req.formData() const manifestFile = formData.get('manifest') as File | null if (!manifestFile) throw new HTTPException(400, { message: 'missing manifest' }) @@ -646,9 +675,8 @@ app.post('/file', // Serve data from Chelonia DB. // Note that a `Last-Modified` header isn't included in the response. -app.get('/file/:hash', async function (c) { - const hash = c.req.param('hash') - if (!CID_REGEX.test(hash)) throw new HTTPException(400, { message: 'Invalid hash' }) +app.get('/file/:hash', zValidator('param', cidHashParamSchema), async function (c) { + const { hash } = c.req.valid('param') const parsed = maybeParseCID(hash) if (!parsed) { @@ -680,10 +708,10 @@ app.get('/file/:hash', async function (c) { app.post('/deleteFile/:hash', authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + zValidator('param', cidHashParamSchema), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const hash = c.req.param('hash') - if (!CID_REGEX.test(hash)) throw new HTTPException(400, { message: 'Invalid hash' }) + const { hash } = c.req.valid('param') const strategy = c.get('authStrategy') const parsed = maybeParseCID(hash) if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { @@ -735,11 +763,11 @@ app.post('/deleteFile/:hash', app.post('/deleteContract/:hash', authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + zValidator('param', cidHashParamSchema), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const hash = c.req.param('hash') + const { hash } = c.req.valid('param') const strategy = c.get('authStrategy') - if (!hash || hash.startsWith('_private')) throw new HTTPException(404) const credentials = c.get('credentials') as AuthCredentials switch (strategy) { @@ -792,14 +820,12 @@ app.post('/deleteContract/:hash', }) app.post('/kv/:contractID/:key', + bodyLimit({ maxSize: 6 * MEGABYTE }), authMiddleware('chel-shelter', 'required'), + zValidator('param', kvParamSchema), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const contractID = c.req.param('contractID') - const key = c.req.param('key') - - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: 'Invalid key' }) + const { contractID, key } = c.req.valid('param') const parsed = maybeParseCID(contractID) if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { @@ -878,12 +904,9 @@ app.post('/kv/:contractID/:key', app.get('/kv/:contractID/:key', authMiddleware('chel-shelter', 'required'), + zValidator('param', kvParamSchema), async function (c) { - const contractID = c.req.param('contractID') - const key = c.req.param('key') - - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - if (!KV_KEY_REGEX.test(key)) throw new HTTPException(400, { message: 'Invalid key' }) + const { contractID, key } = c.req.valid('param') const parsed = maybeParseCID(contractID) if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { @@ -921,7 +944,8 @@ app.get('/serverMessages', function (c) { app.get('/assets/:subpath{.+}', async function (c) { const subpath = c.req.param('subpath') const basename = path.basename(subpath) - const filePath = path.join(staticServeConfig.distAssets, subpath) + const filePath = safePathWithin(staticServeConfig.distAssets, subpath) + if (!filePath) return notFoundNoCache(c) try { const file = await Deno.readFile(filePath) @@ -980,7 +1004,8 @@ if (isCheloniaDashboard) { app.get('/dashboard/assets/:subpath{.+}', async function (c) { const subpath = c.req.param('subpath') const basename = path.basename(subpath) - const filePath = path.join(staticServeConfig.distAssets, subpath) + const filePath = safePathWithin(staticServeConfig.distAssets, subpath) + if (!filePath) return notFoundNoCache(c) try { const file = await Deno.readFile(filePath) @@ -1042,105 +1067,112 @@ app.get('/', function (c) { return c.redirect(staticServeConfig.redirect) }) -app.post('/zkpp/register/:name', async function (c) { - const name = c.req.param('name') - if (!NAME_REGEX.test(name)) throw new HTTPException(400, { message: 'Invalid name' }) - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const lookupResult = await sbp('backend/db/lookupName', name) - if (lookupResult) { - // If the username is already registered, abort - throw new HTTPException(409) - } - try { - const payload = await parseRequestBody<{ b?: string, r?: string, s?: string, sig?: string, Eh?: string }>(c) - // Validate: must be either { b } or { r, s, sig, Eh } - if (payload.b) { - if (typeof payload.b !== 'string') throw new HTTPException(400) - const result = registrationKey(name, payload.b) - - if (result) { - return c.json(result) - } - } else if (payload.r && payload.s && payload.sig && payload.Eh) { - if (typeof payload.r !== 'string' || typeof payload.s !== 'string' || - typeof payload.sig !== 'string' || typeof payload.Eh !== 'string') { - throw new HTTPException(400) - } - const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) +app.post('/zkpp/register/:name', + zValidator('param', nameParamSchema), + async function (c) { + const { name } = c.req.valid('param') + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - if (result) { - return c.json(result) - } + // Parse body - support both JSON and form-urlencoded + const contentType = c.req.header('content-type') || '' + let payload: { b?: string, r?: string, s?: string, sig?: string, Eh?: string } + if (contentType.includes('application/x-www-form-urlencoded')) { + const form = await c.req.parseBody() + payload = form as Record } else { - throw new HTTPException(400, { message: 'Invalid payload' }) + payload = await c.req.json() } - } catch (e) { - if (e instanceof HTTPException) throw e - ;(e as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at POST /zkpp/{name}: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) -}) + // Validate payload + const parseResult = zkppRegisterBodySchema.safeParse(payload) + if (!parseResult.success) { + throw new HTTPException(400, { message: 'Invalid request body' }) + } -app.get('/zkpp/:contractID/auth_hash', async function (c) { - const contractID = c.req.param('contractID') - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - const b = c.req.query('b') - if (!b) throw new HTTPException(400, { message: 'b is required' }) - try { - const challenge = await getChallenge(contractID, b) + const lookupResult = await sbp('backend/db/lookupName', name) + if (lookupResult) { + // If the username is already registered, abort + throw new HTTPException(409) + } + try { + if ('b' in parseResult.data) { + const result = registrationKey(name, parseResult.data.b) - return challenge ? c.json(challenge) : notFoundNoCache(c) - } catch (e) { - ;(e as unknown as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at GET /zkpp/{contractID}/auth_hash: ' + (e as Error).message) - } + if (result) { + return c.json(result) + } + } else { + const result = register(name, parseResult.data.r, parseResult.data.s, parseResult.data.sig, parseResult.data.Eh) - throw new HTTPException(500, { message: 'internal error' }) -}) + if (result) { + return c.json(result) + } + } + } catch (e) { + if (e instanceof HTTPException) throw e + ;(e as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at POST /zkpp/{name}: ' + (e as Error).message) + } -app.get('/zkpp/:contractID/contract_hash', async function (c) { - const contractID = c.req.param('contractID') - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - const r = c.req.query('r') - const s = c.req.query('s') - const sig = c.req.query('sig') - const hc = c.req.query('hc') - if (!r || !s || !sig || !hc) throw new HTTPException(400, { message: 'r, s, sig, and hc are required' }) - try { - const salt = await getContractSalt(contractID, r, s, sig, hc) + throw new HTTPException(500, { message: 'internal error' }) + }) - if (salt) { - return c.json(salt) +app.get('/zkpp/:contractID/auth_hash', + zValidator('param', zkppContractParamSchema), + zValidator('query', zkppAuthHashQuerySchema), + async function (c) { + const { contractID } = c.req.valid('param') + const { b } = c.req.valid('query') + try { + const challenge = await getChallenge(contractID, b) + + return challenge ? c.json(challenge) : notFoundNoCache(c) + } catch (e) { + ;(e as unknown as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at GET /zkpp/{contractID}/auth_hash: ' + (e as Error).message) } - } catch (e) { - ;(e as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at GET /zkpp/{contractID}/contract_hash: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) -}) + throw new HTTPException(500, { message: 'internal error' }) + }) -app.post('/zkpp/:contractID/updatePasswordHash', async function (c) { - const contractID = c.req.param('contractID') - if (!CID_REGEX.test(contractID)) throw new HTTPException(400, { message: 'Invalid contractID' }) - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - try { - const payload = await parseRequestBody<{ r: string, s: string, sig: string, hc: string, Ea: string }>(c) - if (!payload.r || !payload.s || !payload.sig || !payload.hc || !payload.Ea) { - throw new HTTPException(400, { message: 'r, s, sig, hc, and Ea are required' }) +app.get('/zkpp/:contractID/contract_hash', + zValidator('param', zkppContractParamSchema), + zValidator('query', zkppContractHashQuerySchema), + async function (c) { + const { contractID } = c.req.valid('param') + const { r, s, sig, hc } = c.req.valid('query') + try { + const salt = await getContractSalt(contractID, r, s, sig, hc) + + if (salt) { + return c.json(salt) + } + } catch (e) { + ;(e as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at GET /zkpp/{contractID}/contract_hash: ' + (e as Error).message) } - const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) - if (result) { - return c.json(result) + throw new HTTPException(500, { message: 'internal error' }) + }) + +app.post('/zkpp/:contractID/updatePasswordHash', + zValidator('param', zkppContractParamSchema), + zValidator('json', zkppUpdatePasswordBodySchema), + async function (c) { + const { contractID } = c.req.valid('param') + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + try { + const payload = c.req.valid('json') + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) + + if (result) { + return c.json(result) + } + } catch (e) { + if (e instanceof HTTPException) throw e + ;(e as unknown as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at POST /zkpp/{contractID}/updatePasswordHash: ' + (e as Error).message) } - } catch (e) { - if (e instanceof HTTPException) throw e - ;(e as unknown as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at POST /zkpp/{contractID}/updatePasswordHash: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) -}) + throw new HTTPException(500, { message: 'internal error' }) + }) From 5a82a2d705b49f0c12969991511a277feea9c5b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:47:47 -0400 Subject: [PATCH 26/71] Further simplifications --- src/serve/auth.ts | 1 + src/serve/routes.ts | 231 +++++++++++++++++++------------------------- 2 files changed, 101 insertions(+), 131 deletions(-) diff --git a/src/serve/auth.ts b/src/serve/auth.ts index 4834d2e..d8609c8 100644 --- a/src/serve/auth.ts +++ b/src/serve/auth.ts @@ -11,6 +11,7 @@ declare module 'npm:hono' { interface ContextVariableMap { credentials: AuthCredentials authStrategy: string + validatedBody: unknown } } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index ef404dd..d40a9bc 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -21,7 +21,7 @@ import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltU // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' import { authMiddleware, type AuthCredentials } from './auth.ts' -import type { Hono, Context } from 'npm:hono' +import type { Hono, Context, MiddlewareHandler } from 'npm:hono' import { zValidator } from 'npm:@hono/zod-validator' import * as z from 'npm:zod' import { bodyLimit } from 'npm:hono/body-limit' @@ -42,6 +42,29 @@ const KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/ const NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? = { + '.js': 'application/javascript', + '.mjs': 'application/javascript', + '.css': 'text/css', + '.html': 'text/html', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.ttf': 'font/ttf', + '.otf': 'font/otf', + '.webp': 'image/webp', + '.mp4': 'video/mp4', + '.webm': 'video/webm', + '.map': 'application/json' +} + // Zod schemas for declarative request validation const cidSchema = z.string().regex(CID_REGEX, 'Invalid CID') const nameSchema = z.string().regex(NAME_REGEX, 'Invalid name') @@ -83,6 +106,38 @@ const zkppUpdatePasswordBodySchema = z.object({ Ea: z.string().min(1, 'Ea is required') }) +// Custom validator for endpoints that accept both JSON and form-urlencoded bodies +function zValidatorFormOrJson ( + schema: T +): MiddlewareHandler { + return async (c, next) => { + const contentType = c.req.header('content-type') || '' + let data: unknown + + try { + if (contentType.includes('application/x-www-form-urlencoded')) { + const form = await c.req.parseBody() + data = Object.fromEntries( + Object.entries(form as Record) + .filter(([, v]) => typeof v === 'string') + ) + } else { + data = await c.req.json() + } + } catch { + throw new HTTPException(400, { message: 'Invalid request body' }) + } + + const result = schema.safeParse(data) + if (!result.success) { + throw new HTTPException(400, { message: 'Invalid request body' }) + } + + c.set('validatedBody', result.data as z.infer) + return next() + } +} + const FILE_UPLOAD_MAX_BYTES = nconf.get('server:fileUploadMaxBytes') || 30 * MEGABYTE const SIGNUP_LIMIT_MIN = nconf.get('server:signup:limit:minute') || 2 const SIGNUP_LIMIT_HOUR = nconf.get('server:signup:limit:hour') || 10 @@ -114,16 +169,14 @@ const limiterPerDay = new Bottleneck.Group({ sbp('sbp/selectors/register', { 'backend/server/stopRateLimiters': async function () { - await Promise.allSettled([ - limiterPerMinute.disconnect(), - limiterPerHour.disconnect(), - limiterPerDay.disconnect() - ]) - // The following needs to be done using a private API because `disconnect()` - // isn't enough. - clearInterval((limiterPerMinute as unknown as { interval: ReturnType }).interval) - clearInterval((limiterPerHour as unknown as { interval: ReturnType }).interval) - clearInterval((limiterPerDay as unknown as { interval: ReturnType }).interval) + const limiters = [limiterPerMinute, limiterPerHour, limiterPerDay] + await Promise.allSettled(limiters.map(l => l.disconnect())) + // Bottleneck v2 Group.disconnect() only disconnects the Redis connection (if any). + // The internal `setInterval` from `_startAutoCleanup()` is not cleaned up, causing + // async leaks on shutdown. We must clear it via the private `interval` property. + for (const limiter of limiters) { + clearInterval((limiter as unknown as { interval: ReturnType }).interval) + } } }) @@ -254,6 +307,34 @@ function safePathWithin (base: string, subpath: string): string | null { return resolved } +// Helper to serve static assets with proper caching headers +function serveAsset (c: Context, subpath: string, assetsDir: string): Promise { + const basename = path.basename(subpath) + const filePath = safePathWithin(assetsDir, subpath) + if (!filePath) return Promise.resolve(notFoundNoCache(c)) + + return Deno.readFile(filePath) + .then((file) => { + const headers: Record = {} + + if (basename.includes('-cached')) { + headers['ETag'] = `"${basename}"` + headers['Cache-Control'] = 'public,max-age=31536000,immutable' + } + + if (subpath.includes('js/sw-')) { + console.debug('adding header: Service-Worker-Allowed /') + headers['Service-Worker-Allowed'] = '/' + } + + const ext = path.extname(subpath).toLowerCase() + headers['Content-Type'] = MIME_TYPES[ext] || 'application/octet-stream' + + return c.body(file, 200, headers) + }) + .catch(() => notFoundNoCache(c)) +} + // Get the Hono app via SERVER_INSTANCE const app: Hono = sbp('okTurtles.data/get', SERVER_INSTANCE) @@ -943,113 +1024,14 @@ app.get('/serverMessages', function (c) { app.get('/assets/:subpath{.+}', async function (c) { const subpath = c.req.param('subpath') - const basename = path.basename(subpath) - const filePath = safePathWithin(staticServeConfig.distAssets, subpath) - if (!filePath) return notFoundNoCache(c) - - try { - const file = await Deno.readFile(filePath) - const headers: Record = {} - - // In the build config we told our bundler to use the `[name]-[hash]-cached` template - // to name immutable assets. This is useful because `dist/assets/` currently includes - // a few files without hash in their name. - if (basename.includes('-cached')) { - headers['ETag'] = `"${basename}"` - headers['Cache-Control'] = 'public,max-age=31536000,immutable' - } - - // since our JS is placed under /assets/ and since service workers - // have their scope limited by where they are, we must add this - // header to allow the service worker to function. Details: - // https://w3c.github.io/ServiceWorker/#service-worker-allowed - if (subpath.includes('js/sw-')) { - console.debug('adding header: Service-Worker-Allowed /') - headers['Service-Worker-Allowed'] = '/' - } - - const ext = path.extname(subpath).toLowerCase() - const mimeTypes: Record = { - '.js': 'application/javascript', - '.mjs': 'application/javascript', - '.css': 'text/css', - '.html': 'text/html', - '.json': 'application/json', - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.gif': 'image/gif', - '.svg': 'image/svg+xml', - '.ico': 'image/x-icon', - '.woff': 'font/woff', - '.woff2': 'font/woff2', - '.ttf': 'font/ttf', - '.otf': 'font/otf', - '.webp': 'image/webp', - '.mp4': 'video/mp4', - '.webm': 'video/webm', - '.map': 'application/json' - } - const contentType = mimeTypes[ext] || 'application/octet-stream' - headers['Content-Type'] = contentType - - return c.body(file, 200, headers) - } catch { - return notFoundNoCache(c) - } + return serveAsset(c, subpath, staticServeConfig.distAssets) }) // Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) if (isCheloniaDashboard) { app.get('/dashboard/assets/:subpath{.+}', async function (c) { const subpath = c.req.param('subpath') - const basename = path.basename(subpath) - const filePath = safePathWithin(staticServeConfig.distAssets, subpath) - if (!filePath) return notFoundNoCache(c) - - try { - const file = await Deno.readFile(filePath) - const headers: Record = {} - - if (basename.includes('-cached')) { - headers['ETag'] = `"${basename}"` - headers['Cache-Control'] = 'public,max-age=31536000,immutable' - } - - if (subpath.includes('js/sw-')) { - console.debug('adding header: Service-Worker-Allowed /') - headers['Service-Worker-Allowed'] = '/' - } - - const ext = path.extname(subpath).toLowerCase() - const mimeTypes: Record = { - '.js': 'application/javascript', - '.mjs': 'application/javascript', - '.css': 'text/css', - '.html': 'text/html', - '.json': 'application/json', - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.gif': 'image/gif', - '.svg': 'image/svg+xml', - '.ico': 'image/x-icon', - '.woff': 'font/woff', - '.woff2': 'font/woff2', - '.ttf': 'font/ttf', - '.otf': 'font/otf', - '.webp': 'image/webp', - '.mp4': 'video/mp4', - '.webm': 'video/webm', - '.map': 'application/json' - } - const contentType = mimeTypes[ext] || 'application/octet-stream' - headers['Content-Type'] = contentType - - return c.body(file, 200, headers) - } catch { - return notFoundNoCache(c) - } + return serveAsset(c, subpath, staticServeConfig.distAssets) }) } @@ -1069,25 +1051,12 @@ app.get('/', function (c) { app.post('/zkpp/register/:name', zValidator('param', nameParamSchema), + zValidatorFormOrJson(zkppRegisterBodySchema), async function (c) { const { name } = c.req.valid('param') if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - // Parse body - support both JSON and form-urlencoded - const contentType = c.req.header('content-type') || '' - let payload: { b?: string, r?: string, s?: string, sig?: string, Eh?: string } - if (contentType.includes('application/x-www-form-urlencoded')) { - const form = await c.req.parseBody() - payload = form as Record - } else { - payload = await c.req.json() - } - - // Validate payload - const parseResult = zkppRegisterBodySchema.safeParse(payload) - if (!parseResult.success) { - throw new HTTPException(400, { message: 'Invalid request body' }) - } + const payload = c.get('validatedBody') as z.infer const lookupResult = await sbp('backend/db/lookupName', name) if (lookupResult) { @@ -1095,14 +1064,14 @@ app.post('/zkpp/register/:name', throw new HTTPException(409) } try { - if ('b' in parseResult.data) { - const result = registrationKey(name, parseResult.data.b) + if ('b' in payload) { + const result = registrationKey(name, payload.b) if (result) { return c.json(result) } } else { - const result = register(name, parseResult.data.r, parseResult.data.s, parseResult.data.sig, parseResult.data.Eh) + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) if (result) { return c.json(result) @@ -1111,7 +1080,7 @@ app.post('/zkpp/register/:name', } catch (e) { if (e instanceof HTTPException) throw e ;(e as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at POST /zkpp/{name}: ' + (e as Error).message) + console.error(e, 'Error at POST /zkpp/register/:name: ' + (e as Error).message) } throw new HTTPException(500, { message: 'internal error' }) From 79bcf014ab1168fb4a0147afedb7f4b7d3262434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:49:56 -0400 Subject: [PATCH 27/71] async-ready server lifecycle --- build/main.js | 53799 ++++++++++++++--------------- src/main.ts | 8 +- src/parseArgs.ts | 16 +- src/parseConfig.ts | 4 +- src/serve.ts | 10 +- src/serve/dashboard-server.ts | 11 +- src/serve/database.ts | 344 +- src/serve/index.ts | 167 +- src/serve/routes-test-helpers.ts | 26 +- src/serve/routes.ts | 1471 +- src/serve/server.ts | 1013 +- 11 files changed, 28067 insertions(+), 28802 deletions(-) diff --git a/build/main.js b/build/main.js index f995478..fff6299 100644 --- a/build/main.js +++ b/build/main.js @@ -5,14 +5,7 @@ var __require = __deno_internal_createRequire(import.meta.url); // build/main.js-tmp import { Buffer as Buffer22 } from "node:buffer"; -import { Buffer as Buffer3 } from "node:buffer"; -import { Buffer as Buffer4 } from "node:buffer"; import { Buffer as Buffer5 } from "node:buffer"; -import { Buffer as Buffer6 } from "node:buffer"; -import { Buffer as Buffer7 } from "node:buffer"; -import { Buffer as Buffer8 } from "node:buffer"; -import { Buffer as Buffer9 } from "node:buffer"; -import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto"; import { mkdir, readdir, readFile, rm, unlink, writeFile } from "node:fs/promises"; import { basename as basename9, dirname as dirname9, join as join9, normalize as normalize8, resolve as resolve9 } from "node:path"; import { Buffer as Buffer10 } from "node:buffer"; @@ -3078,31 +3071,6 @@ var wrapTransaction = (fn, db2, { begin, commit, rollback, savepoint, release, r import { Buffer as Buffer11 } from "node:buffer"; import { mkdir as mkdir2 } from "node:fs/promises"; import { basename as basename22, dirname as dirname22, join as join22, resolve as resolve22 } from "node:path"; -import process2 from "node:process"; -import { Readable } from "node:stream"; -import { join as join72 } from "node:path"; -import path5 from "node:path"; -import process5 from "node:process"; -import process6 from "node:process"; -import { createServer as createServerHTTP } from "node:http"; -import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "node:http2"; -import { Http2ServerRequest } from "node:http2"; -import { Readable as Readable2 } from "node:stream"; -import crypto2 from "node:crypto"; -import { Buffer as Buffer13 } from "node:buffer"; -import { basename as basename52 } from "node:path"; -import process7 from "node:process"; -import { Buffer as Buffer14 } from "node:buffer"; -import process8 from "node:process"; -import { Buffer as Buffer15 } from "node:buffer"; -import { isIP } from "node:net"; -import path6 from "node:path"; -import process9 from "node:process"; -import { Readable as Readable3 } from "node:stream"; -import { join as join82 } from "node:path"; -import process10 from "node:process"; -import { pathToFileURL } from "node:url"; -import process11 from "node:process"; import process13 from "node:process"; // deno:https://jsr.io/@std/path/1.1.1/_common/assert_path.ts @@ -4030,6 +3998,15 @@ function resolve8(...pathSegments) { // build/main.js-tmp import { Buffer as Buffer12 } from "node:buffer"; +import process2 from "node:process"; +import { Readable } from "node:stream"; +import { Buffer as Buffer6 } from "node:buffer"; +import { Buffer as Buffer4 } from "node:buffer"; +import { Buffer as Buffer3 } from "node:buffer"; +import { Buffer as Buffer7 } from "node:buffer"; +import { Buffer as Buffer9 } from "node:buffer"; +import { randomBytes as randomBytes2, timingSafeEqual } from "node:crypto"; +import { Buffer as Buffer8 } from "node:buffer"; import { join as join32 } from "node:path"; // deno:https://jsr.io/@std/encoding/1.0.10/_common64.ts @@ -4122,6 +4099,29 @@ import { copyFile, mkdir as mkdir3, readFile as readFile3, writeFile as writeFil import { basename as basename42, dirname as dirname42, join as join62 } from "node:path"; import process4 from "node:process"; import process12 from "node:process"; +import process10 from "node:process"; +import { createServer as createServerHTTP } from "node:http"; +import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "node:http2"; +import { Http2ServerRequest } from "node:http2"; +import { Readable as Readable2 } from "node:stream"; +import crypto2 from "node:crypto"; +import { Buffer as Buffer13 } from "node:buffer"; +import { basename as basename52 } from "node:path"; +import process5 from "node:process"; +import { join as join72 } from "node:path"; +import process9 from "node:process"; +import { Buffer as Buffer14 } from "node:buffer"; +import { isIP } from "node:net"; +import path5 from "node:path"; +import process7 from "node:process"; +import process6 from "node:process"; +import { Readable as Readable3 } from "node:stream"; +import process8 from "node:process"; +import { Buffer as Buffer15 } from "node:buffer"; +import { pathToFileURL } from "node:url"; +import path6 from "node:path"; +import process11 from "node:process"; +import { join as join82 } from "node:path"; import { notStrictEqual, strictEqual } from "node:assert"; import { dirname as dirname62, resolve as resolve42 } from "node:path"; import { readdirSync, statSync } from "node:fs"; @@ -19248,54 +19248,6 @@ var init_esm3 = __esm({ }); } }); -var listenKey; -var esm_default4; -var init_esm4 = __esm({ - "node_modules/.deno/@sbp+okturtles.events@1.0.1/node_modules/@sbp/okturtles.events/dist/esm/index.mjs"() { - init_esm(); - init_esm3(); - listenKey = (evt) => `events/${evt}/listeners`; - esm_default4 = esm_default("sbp/selectors/register", { - "okTurtles.events/_init": function() { - this.errorHandler = (event, e2) => { - console.error(`[okTurtles.events] Error at handler for ${event}`, e2); - }; - }, - "okTurtles.events/on": function(event, handler) { - esm_default("okTurtles.data/add", listenKey(event), handler); - return () => esm_default("okTurtles.events/off", event, handler); - }, - "okTurtles.events/once": function(event, handler) { - const cbWithOff = (...args) => { - handler(...args); - esm_default("okTurtles.events/off", event, cbWithOff); - }; - return esm_default("okTurtles.events/on", event, cbWithOff); - }, - "okTurtles.events/emit": function(event, ...data) { - var _a2; - for (const listener of esm_default("okTurtles.data/get", listenKey(event)) || []) { - try { - listener(...data); - } catch (e2) { - (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); - } - } - }, - // almost identical to Vue.prototype.$off, except we require `event` argument - "okTurtles.events/off": function(event, handler) { - if (handler) { - esm_default("okTurtles.data/remove", listenKey(event), handler); - } else { - esm_default("okTurtles.data/delete", listenKey(event)); - } - }, - "okTurtles.events/setErrorHandler": function(errorHandler2) { - this.errorHandler = errorHandler2; - } - }); - } -}); function pick2(o2, props) { const x3 = /* @__PURE__ */ Object.create(null); for (const k of props) { @@ -19412,666 +19364,12 @@ function debounce(func, wait, immediate) { return debounced; } var has; -var init_esm5 = __esm({ +var init_esm4 = __esm({ "node_modules/.deno/turtledash@1.0.3/node_modules/turtledash/dist/esm/index.js"() { has = Function.prototype.call.bind(Object.prototype.hasOwnProperty); } }); -function runWithRetry(client, channelID, type, getPayload) { - let attemptNo = 0; - const { socket, options: options2 } = client; - const instance = {}; - client.pendingOperations.tSet(type, channelID, instance); - const send = () => { - if (client.socket !== socket || socket?.readyState !== WebSocket.OPEN) - return; - const currentInstance = client.pendingOperations.tGet(type, channelID); - if (currentInstance !== instance) - return; - if (attemptNo++ > options2.maxOpRetries) { - console.warn(`[pubsub] Giving up ${type} for channel`, channelID); - client.pendingOperations.tDelete(type, channelID); - return; - } - const payload = getPayload(); - socket.send(createRequest(type, payload)); - const minDelay = (attemptNo - 1) * options2.opRetryInterval; - const jitter = randomIntFromRange(0, options2.opRetryInterval); - const delay2 = Math.min(200, minDelay) + jitter; - setTimeout(send, delay2); - }; - send(); -} -function createClient(url2, options2 = {}) { - const client = { - customEventHandlers: options2.handlers || {}, - // The current number of connection attempts that failed. - // Reset to 0 upon successful connection. - // Used to compute how long to wait before the next reconnection attempt. - failedConnectionAttempts: 0, - isLocal: /\/\/(localhost|127\.0\.0\.1)([:?/]|$)/.test(url2), - // True if this client has never been connected yet. - isNew: true, - listeners: /* @__PURE__ */ Object.create(null), - messageHandlers: { ...defaultMessageHandlers, ...options2.messageHandlers }, - nextConnectionAttemptDelayID: void 0, - options: { ...defaultOptions, ...options2 }, - pendingOperations: new TieredMap(), - pingTimeoutID: void 0, - shouldReconnect: true, - // The underlying WebSocket object. - // A new one is necessary for every connection or reconnection attempt. - socket: null, - subscriptionSet: /* @__PURE__ */ new Set(), - kvFilter: /* @__PURE__ */ new Map(), - connectionTimeoutID: void 0, - url: url2.replace(/^http/, "ws"), - ...publicMethods - }; - for (const name of Object.keys(defaultClientEventHandlers)) { - client.listeners[name] = (event) => { - try { - defaultClientEventHandlers[name].call(client, event); - client.customEventHandlers[name]?.call(client, event); - } catch (error2) { - esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, error2?.message); - } - }; - } - if (typeof self === "object" && self instanceof EventTarget) { - for (const name of globalEventNames) { - globalEventMap.set(name, client.listeners[name]); - } - } - if (!client.options.manual) { - client.connect(); - } - return client; -} -function createMessage(type, data, meta) { - const message = { ...meta, type, data }; - let string3; - const stringify2 = function() { - if (!string3) - string3 = JSON.stringify(this); - return string3; - }; - Object.defineProperties(message, { - [Symbol.toPrimitive]: { - value: stringify2 - } - }); - return message; -} -function createKvMessage(channelID, key, data) { - return JSON.stringify({ type: NOTIFICATION_TYPE.KV, channelID, key, data }); -} -function createPubMessage(channelID, data) { - return JSON.stringify({ type: NOTIFICATION_TYPE.PUB, channelID, data }); -} -function createRequest(type, data) { - return JSON.stringify(Object.assign({ type }, data)); -} -var NOTIFICATION_TYPE; -var REQUEST_TYPE; -var RESPONSE_TYPE; -var PUSH_SERVER_ACTION_TYPE; -var defaultOptions; -var PUBSUB_ERROR; -var PUBSUB_RECONNECTION_ATTEMPT; -var PUBSUB_RECONNECTION_FAILED; -var PUBSUB_RECONNECTION_SCHEDULED; -var PUBSUB_RECONNECTION_SUCCEEDED; -var PUBSUB_SUBSCRIPTION_SUCCEEDED; -var TieredMap; -var isKvFilterFresh; -var pubPayloadFactory; -var defaultClientEventHandlers; -var defaultMessageHandlers; -var globalEventNames; -var socketEventNames; -var globalEventMap; -var isDefinetelyOffline; -var messageParser; -var publicMethods; -var init_pubsub = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/pubsub/index.mjs"() { - init_esm4(); - init_esm(); - init_esm5(); - NOTIFICATION_TYPE = Object.freeze({ - ENTRY: "entry", - DELETION: "deletion", - KV: "kv", - KV_FILTER: "kv_filter", - PING: "ping", - PONG: "pong", - PUB: "pub", - SUB: "sub", - UNSUB: "unsub", - VERSION_INFO: "version_info" - }); - REQUEST_TYPE = Object.freeze({ - PUB: "pub", - SUB: "sub", - UNSUB: "unsub", - PUSH_ACTION: "push_action", - KV_FILTER: "kv_filter" - }); - RESPONSE_TYPE = Object.freeze({ - ERROR: "error", - OK: "ok" - }); - PUSH_SERVER_ACTION_TYPE = Object.freeze({ - SEND_PUBLIC_KEY: "send-public-key", - STORE_SUBSCRIPTION: "store-subscription", - DELETE_SUBSCRIPTION: "delete-subscription", - SEND_PUSH_NOTIFICATION: "send-push-notification" - }); - defaultOptions = { - logPingMessages: !process.env.CI, - pingTimeout: 45e3, - maxReconnectionDelay: 6e4, - maxRetries: 10, - minReconnectionDelay: 500, - reconnectOnDisconnection: true, - reconnectOnOnline: true, - // Defaults to false to avoid reconnection attempts in case the server doesn't - // respond because of a failed authentication. - reconnectOnTimeout: false, - reconnectionDelayGrowFactor: 2, - timeout: 6e4, - maxOpRetries: 4, - opRetryInterval: 2e3 - }; - PUBSUB_ERROR = "pubsub-error"; - PUBSUB_RECONNECTION_ATTEMPT = "pubsub-reconnection-attempt"; - PUBSUB_RECONNECTION_FAILED = "pubsub-reconnection-failed"; - PUBSUB_RECONNECTION_SCHEDULED = "pubsub-reconnection-scheduled"; - PUBSUB_RECONNECTION_SUCCEEDED = "pubsub-reconnection-succeeded"; - PUBSUB_SUBSCRIPTION_SUCCEEDED = "pubsub-subscription-succeeded"; - TieredMap = class extends Map { - tGet(k1, k2) { - return this.get(k1)?.get(k2); - } - tHas(k1, k2) { - return !!this.get(k1)?.has(k2); - } - tSet(k1, k2, v2) { - let submap = this.get(k1); - if (!submap) { - submap = /* @__PURE__ */ new Map(); - this.set(k1, submap); - } - return submap.set(k2, v2); - } - tDelete(k1, k2) { - const submap = this.get(k1); - if (submap) { - const result = submap.delete(k2); - if (submap.size === 0) { - this.delete(k1); - } - return result; - } - return false; - } - tClear(k1) { - this.delete(k1); - } - }; - isKvFilterFresh = (ourKvFilter, theirKvFilter) => { - if (!ourKvFilter !== !theirKvFilter) { - return false; - } else if (ourKvFilter && theirKvFilter) { - if (ourKvFilter.length !== theirKvFilter.length) { - return false; - } else { - const sortedA = [...ourKvFilter].sort(); - const sortedB = [...theirKvFilter].sort(); - for (let i2 = 0; i2 < sortedA.length; i2++) { - if (sortedA[i2] !== sortedB[i2]) { - return false; - } - } - } - } - return true; - }; - pubPayloadFactory = (client, channelID) => () => { - const kvFilter = client.kvFilter.get(channelID); - return kvFilter ? { kvFilter, channelID } : { channelID }; - }; - defaultClientEventHandlers = { - // Emitted when the connection is closed. - close(event) { - const client = this; - console.debug("[pubsub] Event: close", event.code, event.reason); - client.failedConnectionAttempts++; - if (client.socket) { - for (const name of socketEventNames) { - client.socket.removeEventListener(name, client.listeners[name]); - } - } - client.socket = null; - client.clearAllTimers(); - if (client.shouldReconnect) { - const pendingSubscriptionMap = client.pendingOperations.get(REQUEST_TYPE.SUB); - if (pendingSubscriptionMap) { - for (const [channelID] of pendingSubscriptionMap) { - pendingSubscriptionMap.set(channelID, {}); - } - } - client.subscriptionSet.forEach((channelID) => { - if (!client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { - client.pendingOperations.tSet(REQUEST_TYPE.SUB, channelID, {}); - } - }); - } - client.subscriptionSet.clear(); - client.pendingOperations.tClear(REQUEST_TYPE.UNSUB); - client.pendingOperations.tClear(REQUEST_TYPE.KV_FILTER); - if (client.shouldReconnect && client.options.reconnectOnDisconnection) { - if (client.failedConnectionAttempts > client.options.maxRetries) { - esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_FAILED, client); - } else { - if (!isDefinetelyOffline() || client.isLocal) { - client.scheduleConnectionAttempt(); - } - } - } - }, - // Emitted when an error has occured. - // The socket will be closed automatically by the engine if necessary. - error(event) { - const client = this; - console.warn("[pubsub] Event: error", event); - clearTimeout(client.pingTimeoutID); - }, - // Emitted when a message is received. - // The connection will be terminated if the message is malformed or has an - // unexpected data type (e.g. binary instead of text). - message(event) { - const client = this; - const { data } = event; - if (typeof data !== "string") { - esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, { - message: `Wrong data type: ${typeof data}` - }); - return client.destroy(); - } - let msg = { type: "" }; - try { - msg = messageParser(data); - } catch (error2) { - esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, { - message: `Malformed message: ${error2?.message}` - }); - return client.destroy(); - } - const handler = client.messageHandlers[msg.type]; - if (handler) { - handler.call(client, msg); - } else { - throw new Error(`Unhandled message type: ${msg.type}`); - } - }, - offline() { - console.info("[pubsub] Event: offline"); - const client = this; - client.clearAllTimers(); - client.failedConnectionAttempts = 0; - client.socket?.close(); - }, - online() { - console.info("[pubsub] Event: online"); - const client = this; - if (client.options.reconnectOnOnline && client.shouldReconnect) { - if (!client.socket) { - client.failedConnectionAttempts = 0; - client.scheduleConnectionAttempt(); - } - } - }, - // Emitted when the connection is established. - open() { - console.debug("[pubsub] Event: open"); - const client = this; - const { options: options2 } = this; - client.connectionTimeUsed = void 0; - client.clearAllTimers(); - esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_SUCCEEDED, client); - client.failedConnectionAttempts = -1; - client.isNew = false; - if (options2.pingTimeout > 0 && options2.pingTimeout < Infinity) { - client.pingTimeoutID = setTimeout(() => { - client.socket?.close(); - }, options2.pingTimeout); - } - for (const [channelID] of client.pendingOperations.get(REQUEST_TYPE.SUB) || []) { - runWithRetry(client, channelID, REQUEST_TYPE.SUB, pubPayloadFactory(client, channelID)); - } - }, - "reconnection-attempt"() { - console.info("[pubsub] Trying to reconnect..."); - }, - "reconnection-succeeded"() { - console.info("[pubsub] Connection re-established"); - }, - "reconnection-failed"() { - console.warn("[pubsub] Reconnection failed"); - const client = this; - client.destroy(); - }, - "reconnection-scheduled"(event) { - const { delay: delay2, nth } = event.detail; - console.info(`[pubsub] Scheduled connection attempt ${nth} in ~${delay2} ms`); - }, - "subscription-succeeded"(event) { - const { channelID } = event.detail; - console.debug(`[pubsub] Subscribed to channel ${channelID}`); - } - }; - defaultMessageHandlers = { - [NOTIFICATION_TYPE.ENTRY](msg) { - console.debug("[pubsub] Received ENTRY:", msg); - }, - [NOTIFICATION_TYPE.PING]({ data }) { - const client = this; - if (client.options.logPingMessages) { - console.debug(`[pubsub] Ping received in ${Date.now() - Number(data)} ms`); - } - client.socket?.send(createMessage(NOTIFICATION_TYPE.PONG, data)); - clearTimeout(client.pingTimeoutID); - client.pingTimeoutID = setTimeout(() => { - client.socket?.close(); - }, client.options.pingTimeout); - }, - [NOTIFICATION_TYPE.PUB]({ channelID, data }) { - console.log(`[pubsub] Received data from channel ${channelID}:`, data); - }, - [NOTIFICATION_TYPE.KV]({ channelID, key, data }) { - console.log(`[pubsub] Received KV update from channel ${channelID} ${key}:`, data); - }, - [NOTIFICATION_TYPE.SUB](msg) { - console.debug(`[pubsub] Ignoring ${msg.type} message:`, msg.data); - }, - [NOTIFICATION_TYPE.UNSUB](msg) { - console.debug(`[pubsub] Ignoring ${msg.type} message:`, msg.data); - }, - [RESPONSE_TYPE.ERROR]({ data }) { - const { type, channelID, reason } = data; - console.warn(`[pubsub] Received ERROR response for ${type} request to ${channelID}`); - const client = this; - switch (type) { - case REQUEST_TYPE.SUB: { - console.warn(`[pubsub] Could not subscribe to ${channelID}: ${reason}`); - client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); - break; - } - case REQUEST_TYPE.UNSUB: { - console.warn(`[pubsub] Could not unsubscribe from ${channelID}: ${reason}`); - client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); - break; - } - case REQUEST_TYPE.PUSH_ACTION: { - const { actionType, message } = data; - console.warn(`[pubsub] Received ERROR for PUSH_ACTION request with the action type '${actionType}' and the following message: ${message}`); - break; - } - case REQUEST_TYPE.KV_FILTER: { - console.warn(`[pubsub] Could not set KV filter for ${channelID}: ${reason}`); - client.pendingOperations.tDelete(REQUEST_TYPE.KV_FILTER, channelID); - break; - } - default: { - console.error(`[pubsub] Malformed response: invalid request type ${type}`); - } - } - }, - [RESPONSE_TYPE.OK]({ data: { type, channelID, kvFilter } }) { - const client = this; - switch (type) { - case REQUEST_TYPE.SUB: { - if (client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID)) { - client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); - client.subscriptionSet.add(channelID); - esm_default("okTurtles.events/emit", PUBSUB_SUBSCRIPTION_SUCCEEDED, client, { channelID }); - const ourKvFilter = client.kvFilter.get(channelID); - if (!isKvFilterFresh(ourKvFilter, kvFilter)) { - console.debug(`[pubsub] Subscribed to ${channelID}, need to set new KV filter`); - this.setKvFilter(channelID, ourKvFilter); - } - } else { - console.debug(`[pubsub] Received unexpected sub for ${channelID}`); - } - break; - } - case REQUEST_TYPE.UNSUB: { - if (client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { - console.debug(`[pubsub] Unsubscribed from ${channelID}`); - client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); - client.subscriptionSet.delete(channelID); - } else { - console.debug(`[pubsub] Received unexpected unsub for ${channelID}`); - } - break; - } - case REQUEST_TYPE.KV_FILTER: { - if (client.pendingOperations.tHas(REQUEST_TYPE.KV_FILTER, channelID)) { - const ourKvFilter = client.kvFilter.get(channelID); - if (isKvFilterFresh(ourKvFilter, kvFilter)) { - console.debug(`[pubsub] Set KV filter for ${channelID}`, kvFilter); - client.pendingOperations.tDelete(REQUEST_TYPE.KV_FILTER, channelID); - } else { - console.debug(`[pubsub] Received stale KV filter ack for ${channelID}`, kvFilter, ourKvFilter); - } - } else { - console.debug(`[pubsub] Received unexpected kv-filter for ${channelID}`); - } - break; - } - default: { - console.error(`[pubsub] Malformed response: invalid request type ${type}`); - } - } - } - }; - globalEventNames = ["offline", "online"]; - socketEventNames = ["close", "error", "message", "open"]; - globalEventMap = /* @__PURE__ */ new Map(); - if (typeof self === "object" && self instanceof EventTarget) { - for (const name of globalEventNames) { - const handler = (ev) => { - const h2 = globalEventMap.get(name); - return h2?.(ev); - }; - self.addEventListener(name, handler, false); - } - } - isDefinetelyOffline = () => typeof navigator === "object" && navigator.onLine === false; - messageParser = (data) => { - const msg = JSON.parse(data); - if (typeof msg !== "object" || msg === null) { - throw new TypeError("Message is null or not an object"); - } - const { type } = msg; - if (typeof type !== "string" || type === "") { - throw new TypeError("Message type must be a non-empty string"); - } - return msg; - }; - publicMethods = { - clearAllTimers() { - const client = this; - clearTimeout(client.connectionTimeoutID); - clearTimeout(client.nextConnectionAttemptDelayID); - clearTimeout(client.pingTimeoutID); - client.connectionTimeoutID = void 0; - client.nextConnectionAttemptDelayID = void 0; - client.pingTimeoutID = void 0; - }, - // Performs a connection or reconnection attempt. - connect() { - const client = this; - if (client.socket !== null) { - throw new Error("connect() can only be called if there is no current socket."); - } - if (client.nextConnectionAttemptDelayID) { - throw new Error("connect() must not be called during a reconnection delay."); - } - if (!client.shouldReconnect) { - throw new Error("connect() should no longer be called on this instance."); - } - client.socket = new WebSocket(client.url); - client.socket.send = function(data) { - const send = WebSocket.prototype.send.bind(this); - if (typeof data === "object" && typeof data[Symbol.toPrimitive] === "function") { - return send(data[Symbol.toPrimitive]()); - } - return send(data); - }; - if (client.options.timeout) { - const start = performance.now(); - client.connectionTimeoutID = setTimeout(() => { - client.connectionTimeoutID = void 0; - if (client.options.reconnectOnTimeout) { - client.connectionTimeUsed = performance.now() - start; - } - client.socket?.close(4e3, "timeout"); - }, client.options.timeout); - } - for (const name of socketEventNames) { - client.socket.addEventListener(name, client.listeners[name]); - } - }, - /** - * Immediately close the socket, stop listening for events and clear any cache. - * - * This method is used in unit tests. - * - In particular, no 'close' event handler will be called. - * - Any incoming or outgoing buffered data will be discarded. - * - Any pending messages will be discarded. - */ - destroy() { - const client = this; - client.clearAllTimers(); - client.pendingOperations.clear(); - client.subscriptionSet.clear(); - if (typeof self === "object" && self instanceof EventTarget) { - for (const name of globalEventNames) { - globalEventMap.delete(name); - } - } - if (client.socket) { - for (const name of socketEventNames) { - client.socket.removeEventListener(name, client.listeners[name]); - } - client.socket.close(); - } - client.listeners = /* @__PURE__ */ Object.create(null); - client.socket = null; - client.shouldReconnect = false; - }, - getNextRandomDelay() { - const client = this; - const { maxReconnectionDelay, minReconnectionDelay, reconnectionDelayGrowFactor } = client.options; - const minDelay = minReconnectionDelay * reconnectionDelayGrowFactor ** client.failedConnectionAttempts; - const maxDelay = minDelay * reconnectionDelayGrowFactor; - const connectionTimeUsed = client.connectionTimeUsed; - client.connectionTimeUsed = void 0; - return Math.min( - // See issue #1943: Have the connection time used 'eat into' the - // reconnection time used - Math.max(minReconnectionDelay, connectionTimeUsed ? maxReconnectionDelay - connectionTimeUsed : maxReconnectionDelay), - Math.round(minDelay + (0, Math.random)() * (maxDelay - minDelay)) - ); - }, - // Schedules a connection attempt to happen after a delay computed according to - // a randomized exponential backoff algorithm variant. - scheduleConnectionAttempt() { - const client = this; - if (!client.shouldReconnect) { - throw new Error("Cannot call `scheduleConnectionAttempt()` when `shouldReconnect` is false."); - } - if (client.nextConnectionAttemptDelayID) { - return console.warn("[pubsub] A reconnection attempt is already scheduled."); - } - const delay2 = client.getNextRandomDelay(); - const nth = client.failedConnectionAttempts + 1; - client.nextConnectionAttemptDelayID = setTimeout(() => { - esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_ATTEMPT, client); - client.nextConnectionAttemptDelayID = void 0; - client.connect(); - }, delay2); - esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_SCHEDULED, client, { delay: delay2, nth }); - }, - // Can be used to send ephemeral messages outside of any contract log. - // Does nothing if the socket is not in the OPEN state. - pub(channelID, data) { - if (this.socket?.readyState === WebSocket.OPEN) { - this.socket.send(createPubMessage(channelID, data)); - } - }, - /** - * Sends a SUB request to the server as soon as possible. - * - * - The given channel ID will be cached until we get a relevant server - * response, allowing us to resend the same request if necessary. - * - Any identical UNSUB request that has not been sent yet will be cancelled. - * - Calling this method again before the server has responded has no effect. - * @param channelID - The ID of the channel whose updates we want to subscribe to. - */ - sub(channelID) { - const client = this; - if (!client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID) && !client.subscriptionSet.has(channelID)) { - client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); - runWithRetry(client, channelID, REQUEST_TYPE.SUB, pubPayloadFactory(client, channelID)); - } - }, - /** - * Sends a KV_FILTER request to the server as soon as possible. - */ - setKvFilter(channelID, kvFilter) { - const client = this; - if (kvFilter) { - client.kvFilter.set(channelID, kvFilter); - } else { - client.kvFilter.delete(channelID); - } - if (client.subscriptionSet.has(channelID) && !client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { - runWithRetry(client, channelID, REQUEST_TYPE.KV_FILTER, pubPayloadFactory(client, channelID)); - } - }, - /** - * Sends an UNSUB request to the server as soon as possible. - * - * - The given channel ID will be cached until we get a relevant server - * response, allowing us to resend the same request if necessary. - * - Any identical SUB request that has not been sent yet will be cancelled. - * - Calling this method again before the server has responded has no effect. - * @param channelID - The ID of the channel whose updates we want to unsubscribe from. - */ - unsub(channelID) { - const client = this; - if (!client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID) && (client.subscriptionSet.has(channelID) || client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID))) { - client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); - client.kvFilter.delete(channelID); - runWithRetry(client, channelID, REQUEST_TYPE.UNSUB, () => ({ channelID })); - } - } - }; - for (const name of Object.keys(defaultClientEventHandlers)) { - if (name === "error" || !socketEventNames.includes(name)) { - esm_default("okTurtles.events/on", `pubsub-${name}`, (target, detail) => { - const ev = new CustomEvent(name, { detail }); - target.listeners[name].call(target, ev); - }); - } - } - } -}); -var init_esm6 = __esm({ +var init_esm5 = __esm({ "node_modules/.deno/@chelonia+multiformats@1.0.0/node_modules/@chelonia/multiformats/dist/esm/index.mjs"() { init_base(); init_base32(); @@ -22818,9 +22116,9 @@ var sign; var verifySignature; var encrypt; var decrypt; -var init_esm7 = __esm({ +var init_esm6 = __esm({ "node_modules/.deno/@chelonia+crypto@1.0.1/node_modules/@chelonia/crypto/dist/esm/index.mjs"() { - init_esm6(); + init_esm5(); import_scrypt_async = __toESM(require_scrypt_async(), 1); import_tweetnacl = __toESM(require_nacl_fast(), 1); bufToStr = (() => { @@ -23219,34 +22517,6 @@ var init_errors3 = __esm({ ChelErrorResourceGone = ChelErrorGenerator("ChelErrorResourceGone", ChelErrorUnexpectedHttpResponseCode); } }); -var CHELONIA_RESET; -var CONTRACT_IS_SYNCING; -var CONTRACTS_MODIFIED; -var EVENT_HANDLED; -var EVENT_PUBLISHED; -var EVENT_PUBLISHING_ERROR; -var CONTRACT_REGISTERED; -var CONTRACT_IS_PENDING_KEY_REQUESTS; -var CONTRACT_HAS_RECEIVED_KEYS; -var PERSISTENT_ACTION_FAILURE; -var PERSISTENT_ACTION_SUCCESS; -var PERSISTENT_ACTION_TOTAL_FAILURE; -var init_events = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/events.mjs"() { - CHELONIA_RESET = "chelonia-reset"; - CONTRACT_IS_SYNCING = "contract-is-syncing"; - CONTRACTS_MODIFIED = "contracts-modified"; - EVENT_HANDLED = "event-handled"; - EVENT_PUBLISHED = "event-published"; - EVENT_PUBLISHING_ERROR = "event-publishing-error"; - CONTRACT_REGISTERED = "contract-registered"; - CONTRACT_IS_PENDING_KEY_REQUESTS = "contract-is-pending-key-requests"; - CONTRACT_HAS_RECEIVED_KEYS = "contract-has-received-keys"; - PERSISTENT_ACTION_FAILURE = "persistent-action-failure"; - PERSISTENT_ACTION_SUCCESS = "persistent-action-success"; - PERSISTENT_ACTION_TOTAL_FAILURE = "persistent-action-total_failure"; - } -}); var serdesTagSymbol; var serdesSerializeSymbol; var serdesDeserializeSymbol; @@ -23254,7 +22524,7 @@ var rawResult; var serializer; var deserializerTable; var deserializer; -var init_esm8 = __esm({ +var init_esm7 = __esm({ "node_modules/.deno/@chelonia+serdes@1.0.0/node_modules/@chelonia/serdes/dist/esm/index.js"() { serdesTagSymbol = Symbol("tag"); serdesSerializeSymbol = Symbol("serialize"); @@ -23435,9 +22705,9 @@ var isRawSignedData; var rawSignedIncomingData; var init_signedData = __esm({ "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/signedData.mjs"() { - init_esm7(); + init_esm6(); init_esm(); - init_esm5(); + init_esm4(); init_errors3(); init_functions(); rootStateFn = () => esm_default("chelonia/rootState"); @@ -23708,9 +22978,9 @@ var unwrapMaybeEncryptedData; var maybeEncryptedIncomingData; var init_encryptedData = __esm({ "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/encryptedData.mjs"() { - init_esm7(); + init_esm6(); init_esm(); - init_esm5(); + init_esm4(); init_errors3(); init_signedData(); rootStateFn2 = () => esm_default("chelonia/rootState"); @@ -23973,9 +23243,9 @@ var SPMessage; var keyOps; var init_SPMessage = __esm({ "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/SPMessage.mjs"() { + init_esm6(); init_esm7(); - init_esm8(); - init_esm5(); + init_esm4(); init_encryptedData(); init_functions(); init_signedData(); @@ -24368,9900 +23638,4339 @@ var init_SPMessage = __esm({ ]; } }); -var chelonia_utils_default; -var init_chelonia_utils = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/chelonia-utils.mjs"() { +var headPrefix; +var getContractIdFromLogHead; +var getLogHead; +var checkKey; +var parsePrefixableKey; +var prefixHandlers; +var dbPrimitiveSelectors; +var db_default; +var init_db = __esm({ + "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/db.mjs"() { + init_esm3(); + init_esm2(); init_esm(); - chelonia_utils_default = esm_default("sbp/selectors/register", { - // This selector is a wrapper for the `chelonia/kv/set` selector that uses - // the contract queue and allows referring to keys by name, with default key - // names set to `csk` and `cek` for signatures and encryption, respectively. - // For most 'simple' use cases, this selector is a better choice than - // `chelonia/kv/set`. However, the `chelonia/kv/set` primitive is needed if - // the queueing logic needs to be more advanced, the key to use requires - // custom logic or _if the `onconflict` callback also needs to be queued_. - "chelonia/kv/queuedSet": ({ contractID, key, data, onconflict, ifMatch, encryptionKeyName = "cek", signingKeyName = "csk" }) => { - return esm_default("chelonia/queueInvocation", contractID, () => { - return esm_default("chelonia/kv/set", contractID, key, data, { - ifMatch, - encryptionKeyId: esm_default("chelonia/contract/currentKeyIdByName", contractID, encryptionKeyName), - signingKeyId: esm_default("chelonia/contract/currentKeyIdByName", contractID, signingKeyName), - onconflict - }); - }); - } - }); - } -}); -async function* g(a, s, r) { - let d = new TextEncoder(), y = d.encode(`\r ---${a}`); - if (Array.isArray(s) && s.length < 1) { - await r.abort(Error("At least one part is required")); - return; - } - let l = 0; - for await (let e2 of s) { - l++; - let n, t; - if (!e2.body && e2.parts) if (t = e2.headers.get("content-type"), !t) n = A(), t = `multipart/mixed; boundary="${n}"`; - else if (!t.startsWith("multipart/") || !T.test(t)) { - await r.abort(Error("Invalid multipart content type: " + t)); - return; - } else { - let o2 = t.match(m); - (!o2 || !(n = o2[1] || o2[2])) && (n = A(), t = t.replace(T, `; boundary="${n}"`)); - } - await u(y).pipeTo(r, i), yield; - { - let o2 = [""]; - if (t) { - let p = false; - e2.headers.forEach((f, c) => { - c !== "content-type" ? o2.push(`${c}: ${f}`) : (p = true, o2.push(`${c}: ${t}`)); - }), p || o2.push(`content-type: ${t}`); - } else e2.headers.forEach((p, f) => { - o2.push(`${f}: ${p}`); - }); - e2.parts || !e2.body ? o2.push("") : o2.push("", ""); - let B3 = d.encode(o2.join(`\r -`)); - o2.length = 0, await u(B3).pipeTo(r, i), yield; - } - if (e2.body) { - if (e2.body instanceof ArrayBuffer || ArrayBuffer.isView(e2.body)) await u(e2.body).pipeTo(r, i); - else if (e2.body instanceof Blob) await e2.body.stream().pipeTo(r, i); - else if (e2.body instanceof ReadableStream) await e2.body.pipeTo(r, i); - else { - await r.abort(Error("Invalid body type")); + init_SPMessage(); + init_errors3(); + headPrefix = "head="; + getContractIdFromLogHead = (key) => { + if (!key.startsWith(headPrefix)) return; + return key.slice(headPrefix.length); + }; + getLogHead = (contractID) => `${headPrefix}${contractID}`; + checkKey = (key) => { + if (/[\x00-\x1f\x7f\t\\/<>:"|?*]/.test(key)) { + throw new Error(`bad key: ${JSON.stringify(key)}`); } - yield; - } else if (e2.parts) { - if (!n) { - await r.abort(Error("Runtime exception: undefined part boundary")); - return; + }; + parsePrefixableKey = (key) => { + const i2 = key.indexOf(":"); + if (i2 === -1) { + return ["", key]; } - yield* g(n, e2.parts, r), yield; - } - } - if (!l) { - await r.abort(Error("At least one part is required")); - return; - } - let b = d.encode(`\r ---${a}--`); - await u(b).pipeTo(r, i); -} -var m; -var M; -var u; -var T; -var h; -var A; -var i; -var w; -var x; -var init_encodeMultipartMessage = __esm({ - "node_modules/.deno/@apeleghq+multipart-parser@1.0.18/node_modules/@apeleghq/multipart-parser/dist/encodeMultipartMessage.mjs"() { - m = /;\s*boundary=(?:"([0-9a-zA-Z'()+_,\-./:=? ]{0,69}[0-9a-zA-Z'()+_,\-./:=?])"|([0-9a-zA-Z'+_\-.]{0,69}[0-9a-zA-Z'+_\-.]))/; - M = (a) => new ReadableStream({ pull(r) { - if (ArrayBuffer.isView(a)) r.enqueue(a.buffer.slice(a.byteOffset, a.byteOffset + a.byteLength)); - else if (a instanceof ArrayBuffer) r.enqueue(a); - else throw new TypeError("Expected ArrayBuffer or an ArrayBuffer view."); - r.close(); - } }); - u = M; - T = /;\s*boundary=(?:"([^"]+)"|([^;",]+))/; - h = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-."; - A = () => { - let a = new Uint8Array(24); - return globalThis.crypto.getRandomValues(a), Array.from(a).map((s) => h[s % h.length]).join(""); - }; - i = { preventClose: true }; - w = (a, s) => { - let r = new TransformStream(), d = g(a, s, r.writable), y = false, l = r.readable.getReader(); - return new ReadableStream({ start(e2) { - (async () => { - for (; ; ) try { - let n = await l.read(); - if (n.done) { - let t = new Uint8Array([13, 10]); - e2.enqueue(t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength)), e2.close(); - return; - } - e2.enqueue(n.value); - } catch (n) { - e2.error(n); - return; + const prefix = key.slice(0, i2 + 1); + if (prefix in prefixHandlers) { + return [prefix, key.slice(prefix.length)]; + } + throw new ChelErrorDBConnection(`Unknown prefix in '${key}'.`); + }; + prefixHandlers = { + // Decode buffers, but don't transform other values. + "": (value) => Buffer5.isBuffer(value) ? value.toString("utf8") : value, + "any:": (value) => value + /* + // 2025-03-24: Commented out because it's not used; currently, only `any:` + // is used in the `/file` route. + // Throw if the value if not a buffer. + 'blob:': value => { + if (Buffer.isBuffer(value)) { + return value + } + throw new ChelErrorDBConnection('Unexpected value: expected a buffer.') + } + */ + }; + esm_default("sbp/selectors/unsafe", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys", "chelonia.db/keyCount"]); + dbPrimitiveSelectors = process.env.LIGHTWEIGHT_CLIENT === "true" ? { + "chelonia.db/get": function(key) { + const id = getContractIdFromLogHead(key); + if (!id) + return Promise.resolve(); + const state = esm_default("chelonia/rootState").contracts[id]; + const value = state?.HEAD ? JSON.stringify({ + HEAD: state.HEAD, + height: state.height, + previousKeyOp: state.previousKeyOp + }) : void 0; + return Promise.resolve(value); + }, + "chelonia.db/set": function() { + return Promise.resolve(); + }, + "chelonia.db/delete": function() { + return Promise.resolve(true); + }, + "chelonia.db/iterKeys": async function* () { + }, + "chelonia.db/keyCount": function() { + return Promise.resolve(0); + } + } : { + // eslint-disable-next-line require-await + "chelonia.db/get": async function(prefixableKey) { + const [prefix, key] = parsePrefixableKey(prefixableKey); + const value = esm_default("okTurtles.data/get", key); + if (value === void 0) { + return; + } + return prefixHandlers[prefix](value); + }, + // eslint-disable-next-line require-await + "chelonia.db/set": async function(key, value) { + checkKey(key); + return esm_default("okTurtles.data/set", key, value); + }, + // eslint-disable-next-line require-await + "chelonia.db/delete": async function(key) { + return esm_default("okTurtles.data/delete", key); + }, + "chelonia.db/iterKeys": async function* () { + yield* esm_default("okTurtles.data/iterKeys"); + }, + "chelonia.db/keyCount": function() { + return Promise.resolve(esm_default("okTurtles.data/keyCount")); + } + }; + db_default = esm_default("sbp/selectors/register", { + ...dbPrimitiveSelectors, + "chelonia/db/getEntryMeta": async (contractID, height) => { + const entryMetaJson = await esm_default("chelonia.db/get", `_private_hidx=${contractID}#${height}`); + if (!entryMetaJson) + return; + return JSON.parse(entryMetaJson); + }, + "chelonia/db/setEntryMeta": async (contractID, height, entryMeta) => { + const entryMetaJson = JSON.stringify(entryMeta); + await esm_default("chelonia.db/set", `_private_hidx=${contractID}#${height}`, entryMetaJson); + }, + "chelonia/db/latestHEADinfo": async (contractID) => { + const r = await esm_default("chelonia.db/get", getLogHead(contractID)); + return r && JSON.parse(r); + }, + "chelonia/db/deleteLatestHEADinfo": (contractID) => { + return esm_default("chelonia.db/set", getLogHead(contractID), ""); + }, + "chelonia/db/getEntry": async function(hash3) { + try { + const value = await esm_default("chelonia.db/get", hash3); + if (!value) + throw new Error(`no entry for ${hash3}!`); + return SPMessage.deserialize(value, this.transientSecretKeys, void 0, this.config.unwrapMaybeEncryptedData); + } catch (e2) { + throw new ChelErrorDBConnection(`${e2.name} during getEntry: ${e2.message}`); + } + }, + "chelonia/db/addEntry": function(entry) { + return esm_default("okTurtles.eventQueue/queueEvent", `chelonia/db/${entry.contractID()}`, ["chelonia/private/db/addEntry", entry]); + }, + // NEVER call this directly yourself! _always_ call 'chelonia/db/addEntry' instead + "chelonia/private/db/addEntry": async function(entry) { + try { + const { previousHEAD: entryPreviousHEAD, previousKeyOp: entryPreviousKeyOp, height: entryHeight } = entry.head(); + const contractID = entry.contractID(); + if (await esm_default("chelonia.db/get", entry.hash())) { + console.warn(`[chelonia.db] entry exists: ${entry.hash()}`); + return entry.hash(); } - })().catch(() => { - }); - }, async pull() { - if (y) return; - (await d.next()).done && (y = true, await r.writable.close()); - } }); - }; - x = w; - } -}); -var v; -var I; -var B; -var m2; -var o; -var R; -var S; -var init_decrypt = __esm({ - "node_modules/.deno/@apeleghq+rfc8188@1.0.8/node_modules/@apeleghq/rfc8188/dist/decrypt.mjs"() { - v = async (n, T2, w3, L) => { - let u2 = await globalThis.crypto.subtle.importKey("raw", T2, "HKDF", false, ["deriveKey", "deriveBits"]), d = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: n.cek_info, salt: w3 }, u2, n.params, false, L), A2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: n.nonce_info, salt: w3 }, u2, n.nonce_length << 3); - return [d, function* () { - let s = new ArrayBuffer(n.nonce_length), e2 = new DataView(s), y = new Uint8Array(s), i2 = new Uint8Array(A2), b = 4294967295, f = (n.nonce_length >> 2) - 1, l = new Array(f).fill(0); - for (; ; ) { - for (let a = 0; a <= b; a++) { - e2.setUint32(e2.byteLength - 4, a, false); - let t = new Uint8Array(n.nonce_length); - for (let r = 0; r < t.length; r++) t[r] = i2[r] ^ y[r]; - yield t; - } - for (let a = 0; a < f; a++) { - if (a === f - 1 && l[a] === b) throw new RangeError("Maximum number of segments exceeded"); - if (l[a] = (l[a] + 1) % (b + 1), e2.setUint32(e2.byteLength - 4 * (a + 2), l[a], false), l[a] !== 0) break; - } - } - }()]; - }; - I = v; - B = (n) => ArrayBuffer.isView(n) ? new Uint8Array(n.buffer).subarray(n.byteOffset, n.byteOffset + n.byteLength) : new Uint8Array(n); - m2 = B; - o = { salt: {}, recordSize: {}, keyIdLen: {}, keyId: {}, payload: {}, done: {} }; - R = (n, T2, w3, L) => { - let u2 = new Uint8Array(16), d, A2, E2, s = 0, e2 = 0, y = new Uint8Array(256), i2 = o.salt, b = new TransformStream({ start: () => { - }, transform: async (f, l) => { - let a = m2(f), t = 0; - for (; t < f.byteLength; ) switch (i2) { - case o.salt: { - let r = a.subarray(t, t + u2.byteLength - e2); - if (u2.set(r, e2), e2 += r.byteLength, t += r.byteLength, e2 === u2.byteLength) { - e2 = 0, i2 = o.recordSize; - continue; + const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); + if (!entry.isFirstMessage()) { + if (!HEADinfo) { + throw new Error(`No latest HEAD for ${contractID} when attempting to process entry with previous HEAD ${entryPreviousHEAD} at height ${entryHeight}`); } - break; - } - case o.recordSize: { - let r = a.subarray(t, t + 4 - e2), g2 = new ArrayBuffer(4), h2 = new Uint8Array(g2), c = new DataView(g2); - if (h2.set(r, e2), s |= c.getUint32(0, false), e2 += r.byteLength, t += r.byteLength, e2 === 4) { - if (s <= n.tag_length + 1 || s > (L == null ? 4294967295 : Math.min(4294967295, L))) throw new RangeError("Invalid record size: " + s); - e2 = 0, i2 = o.keyIdLen; - continue; + const { HEAD: contractHEAD, previousKeyOp: contractPreviousKeyOp, height: contractHeight } = HEADinfo; + if (entryPreviousHEAD !== contractHEAD) { + console.warn(`[chelonia.db] bad previousHEAD: ${entryPreviousHEAD}! Expected: ${contractHEAD} for contractID: ${contractID}`); + throw new ChelErrorDBBadPreviousHEAD(`bad previousHEAD: ${entryPreviousHEAD}. Expected ${contractHEAD} for contractID: ${contractID}`); + } else if (entryPreviousKeyOp !== contractPreviousKeyOp) { + console.error(`[chelonia.db] bad previousKeyOp: ${entryPreviousKeyOp}! Expected: ${contractPreviousKeyOp} for contractID: ${contractID}`); + throw new ChelErrorDBBadPreviousHEAD(`bad previousKeyOp: ${entryPreviousKeyOp}. Expected ${contractPreviousKeyOp} for contractID: ${contractID}`); + } else if (!Number.isSafeInteger(entryHeight) || entryHeight !== contractHeight + 1) { + console.error(`[chelonia.db] bad height: ${entryHeight}! Expected: ${contractHeight + 1} for contractID: ${contractID}`); + throw new ChelErrorDBBadPreviousHEAD(`[chelonia.db] bad height: ${entryHeight}! Expected: ${contractHeight + 1} for contractID: ${contractID}`); } - break; - } - case o.keyIdLen: { - y[0] = a[t++], i2 = o.keyId; - continue; - } - case o.keyId: { - let r = a.subarray(t, t + y[0] - e2); - if (y.set(r, 1 + e2), e2 += r.byteLength, t += r.byteLength, e2 === y[0]) { - let g2 = await w3(y.subarray(1, 1 + y[0])); - w3 = void 0; - let h2 = await I(n, g2, u2, ["decrypt"]); - A2 = h2[0], E2 = h2[1], d = new Uint8Array(s), e2 = 0, i2 = o.payload; - continue; + } else { + if (HEADinfo) { + console.error(`[chelonia.db] bad previousHEAD: ${entryPreviousHEAD}! Expected: for contractID: ${contractID}`); + throw new ChelErrorDBBadPreviousHEAD(`bad previousHEAD: ${entryPreviousHEAD}. Expected for contractID: ${contractID}`); + } else if (entryHeight !== 0) { + console.error(`[chelonia.db] bad height: ${entryHeight}! Expected: 0 for contractID: ${contractID}`); + throw new ChelErrorDBBadPreviousHEAD(`[chelonia.db] bad height: ${entryHeight}! Expected: 0 for contractID: ${contractID}`); } - break; } - case o.payload: { - let r = a.subarray(t, t + s - e2); - if (d.set(r, e2), e2 += r.byteLength, t += r.byteLength, e2 === s) { - let h2 = E2.next().value, c = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: h2, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), p = c.byteLength - 1; - for (; p > 0 && c[p] === 0; p--) ; - if (c[p] === 2) { - if (t !== f.byteLength) throw new Error("Unexpected terminal padding delimiter"); - i2 = o.done; - } else if (c[p] !== 1) throw new Error("Invalid padding delimiter"); - l.enqueue(c.buffer.slice(0, p)), c.fill(0), e2 = 0; - continue; - } - break; + await esm_default("chelonia.db/set", entry.hash(), entry.serialize()); + await esm_default("chelonia.db/set", getLogHead(contractID), JSON.stringify({ + HEAD: entry.hash(), + previousKeyOp: entry.isKeyOp() ? entry.hash() : entry.previousKeyOp(), + height: entry.height() + })); + console.debug(`[chelonia.db] HEAD for ${contractID} updated to:`, entry.hash()); + await esm_default("chelonia/db/setEntryMeta", contractID, entryHeight, { + // The hash is used for reverse lookups (height to CID) + hash: entry.hash(), + // The date isn't currently used, but will be used for filtering messages + date: (/* @__PURE__ */ new Date()).toISOString(), + // isKeyOp is used for filtering messages (the actual filtering is + // done more efficiently a separate index key, but `isKeyOp` allows + // us to bootstrap this process without having to load the full message) + // The separate index key bears the prefix `_private_keyop_idx_`. + ...entry.isKeyOp() && { isKeyOp: true } + }); + return entry.hash(); + } catch (e2) { + if (e2.name.includes("ErrorDB")) { + throw e2; } - default: - throw new Error("Invalid state"); + throw new ChelErrorDBConnection(`${e2.name} during addEntry: ${e2.message}`); + } + }, + "chelonia/db/lastEntry": async function(contractID) { + try { + const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); + if (!latestHEADinfo) + throw new Error(`contract ${contractID} has no latest hash!`); + return esm_default("chelonia/db/getEntry", latestHEADinfo.HEAD); + } catch (e2) { + throw new ChelErrorDBConnection(`${e2.name} during lastEntry: ${e2.message}`); } - }, flush: async (f) => { - switch (i2) { - case o.done: - return; - case o.payload: { - if (e2 < 1 + n.tag_length) throw new Error("Unexpected end of data"); - let a = E2.next().value, t = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: a, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), r = t.byteLength - 1; - for (; r > 0 && t[r] === 0; r--) ; - if (t[r] !== 2) throw new Error("Unexpected non-terminal padding delimiter"); - f.enqueue(t.buffer.slice(0, r)), t.fill(0); - return; - } - default: - throw new Error("Invalid state"); - } - } }); - return T2.pipeThrough(b), b.readable; - }; - S = R; - } -}); -var x2; -var e; -var init_encodings = __esm({ - "node_modules/.deno/@apeleghq+rfc8188@1.0.8/node_modules/@apeleghq/rfc8188/dist/encodings.mjs"() { - x2 = { params: { name: "AES-GCM", length: 128 }, get cek_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 49, 50, 56, 103, 99, 109, 0]); - }, get nonce_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); - }, block_size: 16, tag_length: 16, nonce_length: 12 }; - e = { params: { name: "AES-GCM", length: 256 }, get cek_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 50, 53, 54, 103, 99, 109, 0]); - }, get nonce_info() { - return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); - }, block_size: 16, tag_length: 16, nonce_length: 12 }; - } -}); -var R2; -var E; -var B2; -var w2; -var N; -var U; -var K; -var init_encrypt = __esm({ - "node_modules/.deno/@apeleghq+rfc8188@1.0.8/node_modules/@apeleghq/rfc8188/dist/encrypt.mjs"() { - R2 = async (e2, b, f, i2) => { - let A2 = await globalThis.crypto.subtle.importKey("raw", b, "HKDF", false, ["deriveKey", "deriveBits"]), y = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: e2.cek_info, salt: f }, A2, e2.params, false, i2), u2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: e2.nonce_info, salt: f }, A2, e2.nonce_length << 3); - return [y, function* () { - let L = new ArrayBuffer(e2.nonce_length), c = new DataView(L), h2 = new Uint8Array(L), a = new Uint8Array(u2), g2 = 4294967295, o2 = (e2.nonce_length >> 2) - 1, s = new Array(o2).fill(0); - for (; ; ) { - for (let t = 0; t <= g2; t++) { - c.setUint32(c.byteLength - 4, t, false); - let n = new Uint8Array(e2.nonce_length); - for (let r = 0; r < n.length; r++) n[r] = a[r] ^ h2[r]; - yield n; - } - for (let t = 0; t < o2; t++) { - if (t === o2 - 1 && s[t] === g2) throw new RangeError("Maximum number of segments exceeded"); - if (s[t] = (s[t] + 1) % (g2 + 1), c.setUint32(c.byteLength - 4 * (t + 2), s[t], false), s[t] !== 0) break; - } - } - }()]; - }; - E = R2; - B2 = (e2) => ArrayBuffer.isView(e2) ? new Uint8Array(e2.buffer).subarray(e2.byteOffset, e2.byteOffset + e2.byteLength) : new Uint8Array(e2); - w2 = B2; - N = () => { - let e2 = new Uint8Array(16); - return globalThis.crypto.getRandomValues(e2), e2; - }; - U = async (e2, b, f, i2, A2, y) => { - if (f <= e2.tag_length + 1 || f > 4294967295) throw new RangeError("Invalid record size: " + f); - if (i2.byteLength > 255) throw new RangeError("Key ID too long"); - if (y && y.byteLength !== 16) throw new RangeError("Invald salt length: " + y.byteLength); - let u2 = f - e2.tag_length - 1, l = y ? w2(y) : N(), [L, c] = await E(e2, A2, l, ["encrypt"]); - A2 = void 0; - let h2 = new Uint8Array(u2), a = 0, g2 = new TransformStream({ start: (o2) => { - let s = l.byteLength + 4 + 1 + i2.byteLength, t = new ArrayBuffer(s); - new Uint8Array(t, 0, l.byteLength).set(l); - let r = new DataView(t, l.byteLength, 5); - r.setUint32(0, f, false), r.setUint8(4, i2.byteLength); - let d = new Uint8Array(t, l.byteLength + 4 + 1, i2.byteLength), m3 = w2(i2); - d.set(m3), o2.enqueue(t); - }, transform: async (o2, s) => { - let t = w2(o2), n = 0; - for (; n < o2.byteLength; ) { - let r = t.subarray(n, n + u2 - a); - if (h2.set(r, a), a += r.byteLength, n += r.byteLength, a === u2) { - let m3 = c.next().value, p = new Uint8Array(u2 + 1); - p.set(h2.subarray(0, a)), p[a] = 1; - let T2 = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: m3, tagLength: e2.tag_length << 3 }, L, p); - s.enqueue(T2), a = 0; - } - } - }, flush: async (o2) => { - let t = c.next().value, n = new Uint8Array(a + 1); - n.set(h2.subarray(0, a)), n[a] = 2; - let r = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: t, tagLength: e2.tag_length << 3 }, L, n); - o2.enqueue(r), h2.fill(0), n.fill(0); - } }); - return b.pipeThrough(g2), g2.readable; - }; - K = U; - } -}); -var wm; -var Secret; -var init_Secret = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/Secret.mjs"() { - init_esm8(); - wm = /* @__PURE__ */ new WeakMap(); - Secret = class { - static [serdesDeserializeSymbol](secret) { - return new this(secret); - } - static [serdesSerializeSymbol](secret) { - return wm.get(secret); - } - static get [serdesTagSymbol]() { - return "__chelonia_Secret"; - } - constructor(value) { - wm.set(this, value); - } - valueOf() { - return wm.get(this); } - }; + }); } }); -var INVITE_STATUS; -var init_constants = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/constants.mjs"() { - INVITE_STATUS = { - REVOKED: "revoked", - VALID: "valid", - USED: "used" +var require_lru_cache = __commonJS({ + "node_modules/.deno/lru-cache@7.14.0/node_modules/lru-cache/index.js"(exports2, module14) { + var perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date; + var hasAbortController = typeof AbortController === "function"; + var AC = hasAbortController ? AbortController : class AbortController { + constructor() { + this.signal = new AS(); + } + abort() { + this.signal.dispatchEvent("abort"); + } }; - } -}); -function eventsAfter(contractID, { sinceHeight, limit, sinceHash, stream = true }) { - if (!contractID) { - throw new Error("Missing contract ID"); - } - let lastUrl; - const fetchEventsStreamReader = async () => { - requestLimit = Math.min(limit ?? MAX_EVENTS_AFTER, remainingEvents); - lastUrl = `${this.config.connectionURL}/eventsAfter/${contractID}/${sinceHeight}${Number.isInteger(requestLimit) ? `/${requestLimit}` : ""}`; - const eventsResponse = await this.config.fetch(lastUrl, { signal }); - if (!eventsResponse.ok) { - const msg = `${eventsResponse.status}: ${eventsResponse.statusText}`; - if (eventsResponse.status === 404 || eventsResponse.status === 410) { - throw new ChelErrorResourceGone(msg, { cause: eventsResponse.status }); + var hasAbortSignal = typeof AbortSignal === "function"; + var hasACAbortSignal = typeof AC.AbortSignal === "function"; + var AS = hasAbortSignal ? AbortSignal : hasACAbortSignal ? AC.AbortController : class AbortSignal { + constructor() { + this.aborted = false; + this._listeners = []; } - throw new ChelErrorUnexpectedHttpResponseCode(msg, { cause: eventsResponse.status }); - } - if (!eventsResponse.body) - throw new Error("Missing body"); - latestHeight = parseInt(eventsResponse.headers.get("shelter-headinfo-height"), 10); - if (!Number.isSafeInteger(latestHeight)) - throw new Error("Invalid latest height"); - requestCount++; - return eventsResponse.body.getReader(); - }; - if (!Number.isSafeInteger(sinceHeight) || sinceHeight < 0) { - throw new TypeError("Invalid since height value. Expected positive integer."); - } - const signal = this.abortController.signal; - let requestCount = 0; - let remainingEvents = limit ?? Number.POSITIVE_INFINITY; - let eventsStreamReader; - let latestHeight; - let state = "fetch"; - let requestLimit; - let count; - let buffer = ""; - let currentEvent; - const s = new ReadableStream({ - // The pull function is called whenever the internal buffer of the stream - // becomes empty and needs more data. - async pull(controller) { - try { - for (; ; ) { - switch (state) { - // When in 'fetch' state, initiate a new fetch request to obtain a - // stream reader for events. - case "fetch": { - eventsStreamReader = await fetchEventsStreamReader(); - state = "read-new-response"; - count = 0; - break; - } - case "read-eos": - // End of stream case - case "read-new-response": - // Just started reading a new response - case "read": { - const { done, value } = await eventsStreamReader.read(); - if (done) { - if (remainingEvents === 0 || sinceHeight >= latestHeight) { - controller.close(); - return; - } else if (state === "read-new-response" || buffer) { - throw new Error("Invalid response: done too early"); - } else { - state = "fetch"; - break; - } - } - if (!value) { - throw new Error("Invalid response: missing body"); - } - buffer = buffer + Buffer3.from(value).toString().trim(); - if (!buffer) - break; - if (state === "read-new-response") { - if (buffer[0] !== "[") { - throw new Error("Invalid response: no array start delimiter"); - } - buffer = buffer.slice(1); - } else if (state === "read-eos") { - throw new Error("Invalid data at the end of response"); - } - state = "events"; - break; - } - case "events": { - const nextIdx = buffer.search(/(?<=\s*)[,\]]/); - if (nextIdx < 0) { - state = "read"; - break; - } - let enqueued = false; - try { - const eventValue = buffer.slice(0, nextIdx).trim(); - if (eventValue) { - if (count === requestLimit) { - throw new Error("Received too many events"); - } - currentEvent = JSON.parse(b64ToStr(JSON.parse(eventValue))).message; - if (count === 0) { - const hash3 = SPMessage.deserializeHEAD(currentEvent).hash; - const height = SPMessage.deserializeHEAD(currentEvent).head.height; - if (height !== sinceHeight || sinceHash && sinceHash !== hash3) { - if (height === sinceHeight && sinceHash && sinceHash !== hash3) { - throw new ChelErrorForkedChain(`Forked chain: hash(${hash3}) !== since(${sinceHash})`); - } else { - throw new Error(`Unexpected data: hash(${hash3}) !== since(${sinceHash || ""}) or height(${height}) !== since(${sinceHeight})`); - } - } - } - if (count++ !== 0 || requestCount !== 0) { - controller.enqueue(currentEvent); - enqueued = true; - remainingEvents--; - } - } - if (buffer[nextIdx] === "]") { - if (currentEvent) { - const deserialized = SPMessage.deserializeHEAD(currentEvent); - sinceHeight = deserialized.head.height; - sinceHash = deserialized.hash; - state = "read-eos"; - } else { - state = "eod"; - } - buffer = buffer.slice(nextIdx + 1).trim(); - } else if (currentEvent) { - buffer = buffer.slice(nextIdx + 1).trimStart(); - } else { - throw new Error("Missing end delimiter"); - } - if (enqueued) { - return; - } - } catch (e2) { - console.error("[chelonia] Error during event parsing", e2); - throw e2; - } - break; - } - case "eod": { - if (remainingEvents === 0 || sinceHeight >= latestHeight) { - controller.close(); - } else { - throw new Error("Unexpected end of data"); - } - return; - } - } + dispatchEvent(type) { + if (type === "abort") { + this.aborted = true; + const e2 = { type, target: this }; + this.onabort(e2); + this._listeners.forEach((f) => f(e2), this); } - } catch (e2) { - console.error("[eventsAfter] Error", { lastUrl }, e2); - eventsStreamReader?.cancel("Error during pull").catch((e22) => { - console.error("Error canceling underlying event stream reader on error", e2, e22); - }); - throw e2; } - } - }); - if (stream) - return s; - return collectEventStream(s); -} -function buildShelterAuthorizationHeader(contractID, state) { - if (!state) - state = esm_default(this.config.stateSelector)[contractID]; - const SAKid = findKeyIdByName(state, "#sak"); - if (!SAKid) { - throw new Error(`Missing #sak in ${contractID}`); - } - const SAK = this.transientSecretKeys[SAKid]; - if (!SAK) { - throw new Error(`Missing secret #sak (${SAKid}) in ${contractID}`); - } - const deserializedSAK = typeof SAK === "string" ? deserializeKey(SAK) : SAK; - const nonceBytes = new Uint8Array(15); - globalThis.crypto.getRandomValues(nonceBytes); - const data = `${contractID} ${esm_default("chelonia/time")}.${Buffer3.from(nonceBytes).toString("base64")}`; - return `shelter ${data}.${sign(deserializedSAK, data)}`; -} -function verifyShelterAuthorizationHeader(authorization, rootState) { - const regex = /^shelter (([a-zA-Z0-9]+) ([0-9]+)\.([a-zA-Z0-9+/=]{20}))\.([a-zA-Z0-9+/=]+)$/i; - if (authorization.length > 1024) { - throw new Error("Authorization header too long"); - } - const matches = authorization.match(regex); - if (!matches) { - throw new Error("Unable to parse shelter authorization header"); - } - const [, data, contractID, timestamp, , signature] = matches; - if (Math.abs(parseInt(timestamp) - Date.now()) > 6e4) { - throw new Error("Invalid signature time range"); - } - if (!rootState) - rootState = esm_default("chelonia/rootState"); - if (!has(rootState, contractID)) { - throw new Error(`Contract ${contractID} from shelter authorization header not found`); - } - const SAKid = findKeyIdByName(rootState[contractID], "#sak"); - if (!SAKid) { - throw new Error(`Missing #sak in ${contractID}`); - } - const SAK = rootState[contractID]._vm.authorizedKeys[SAKid].data; - if (!SAK) { - throw new Error(`Missing secret #sak (${SAKid}) in ${contractID}`); - } - const deserializedSAK = deserializeKey(SAK); - verifySignature(deserializedSAK, data, signature); - return contractID; -} -var MAX_EVENTS_AFTER; -var copiedExistingData; -var findKeyIdByName; -var findForeignKeysByContractID; -var findRevokedKeyIdsByName; -var findSuitableSecretKeyId; -var findSuitablePublicKeyIds; -var validateActionPermissions; -var validateKeyPermissions; -var validateKeyAddPermissions; -var validateKeyDelPermissions; -var validateKeyUpdatePermissions; -var keyAdditionProcessor; -var subscribeToForeignKeyContracts; -var recreateEvent; -var getContractIDfromKeyId; -var clearObject; -var reactiveClearObject; -var checkCanBeGarbageCollected; -var collectEventStream; -var logEvtError; -var handleFetchResult; -var init_utils = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/utils.mjs"() { - init_esm7(); - init_esm(); - init_esm5(); - init_SPMessage(); - init_Secret(); - init_constants(); - init_errors3(); - init_events(); - init_functions(); - init_signedData(); - MAX_EVENTS_AFTER = Number.parseInt(process.env.MAX_EVENTS_AFTER || "", 10) || Infinity; - copiedExistingData = Symbol("copiedExistingData"); - findKeyIdByName = (state, name) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).find((k) => k.name === name && k._notAfterHeight == null)?.id; - findForeignKeysByContractID = (state, contractID) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => k._notAfterHeight == null && k.foreignKey?.includes(contractID)).map((k) => k.id); - findRevokedKeyIdsByName = (state, name) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys || {}).filter((k) => k.name === name && k._notAfterHeight != null).map((k) => k.id); - findSuitableSecretKeyId = (state, permissions, purposes, ringLevel, allowedActions) => { - return state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => { - return k._notAfterHeight == null && k.ringLevel <= (ringLevel ?? Number.POSITIVE_INFINITY) && esm_default("chelonia/haveSecretKey", k.id) && (Array.isArray(permissions) ? permissions.reduce((acc, permission) => acc && (k.permissions === "*" || k.permissions.includes(permission)), true) : permissions === k.permissions) && purposes.reduce((acc, purpose) => acc && k.purpose.includes(purpose), true) && (Array.isArray(allowedActions) ? allowedActions.reduce((acc, action) => acc && (k.allowedActions === "*" || !!k.allowedActions?.includes(action)), true) : allowedActions ? allowedActions === k.allowedActions : true); - }).sort((a, b) => b.ringLevel - a.ringLevel)[0]?.id; - }; - findSuitablePublicKeyIds = (state, permissions, purposes, ringLevel) => { - return state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => k._notAfterHeight == null && k.ringLevel <= (ringLevel ?? Number.POSITIVE_INFINITY) && (Array.isArray(permissions) ? permissions.reduce((acc, permission) => acc && (k.permissions === "*" || k.permissions.includes(permission)), true) : permissions === k.permissions) && purposes.reduce((acc, purpose) => acc && k.purpose.includes(purpose), true)).sort((a, b) => b.ringLevel - a.ringLevel).map((k) => k.id); - }; - validateActionPermissions = (msg, signingKey, state, opT, opV) => { - const data = isSignedData(opV) ? opV.valueOf() : opV; - if (signingKey.allowedActions !== "*" && (!Array.isArray(signingKey.allowedActions) || !signingKey.allowedActions.includes(data.action))) { - logEvtError(msg, `Signing key ${signingKey.id} is not allowed for action ${data.action}`); - return false; + onabort() { } - if (isSignedData(opV)) { - const s = opV; - const innerSigningKey = state._vm?.authorizedKeys?.[s.signingKeyId]; - if (!innerSigningKey && msg._direction === "outgoing") - return true; - if (!innerSigningKey || !Array.isArray(innerSigningKey.purpose) || !innerSigningKey.purpose.includes("sig") || innerSigningKey.permissions !== "*" && (!Array.isArray(innerSigningKey.permissions) || !innerSigningKey.permissions.includes(opT + "#inner"))) { - logEvtError(msg, `Signing key ${s.signingKeyId} is missing permissions for operation ${opT}`); - return false; + addEventListener(ev, fn) { + if (ev === "abort") { + this._listeners.push(fn); } - if (innerSigningKey.allowedActions !== "*" && (!Array.isArray(innerSigningKey.allowedActions) || !innerSigningKey.allowedActions.includes(data.action + "#inner"))) { - logEvtError(msg, `Signing key ${innerSigningKey.id} is not allowed for action ${data.action}`); - return false; + } + removeEventListener(ev, fn) { + if (ev === "abort") { + this._listeners = this._listeners.filter((f) => f !== fn); } } - return true; }; - validateKeyPermissions = (msg, config2, state, signingKeyId, opT, opV) => { - const signingKey = state._vm?.authorizedKeys?.[signingKeyId]; - if (!signingKey || !Array.isArray(signingKey.purpose) || !signingKey.purpose.includes("sig") || signingKey.permissions !== "*" && (!Array.isArray(signingKey.permissions) || !signingKey.permissions.includes(opT))) { - logEvtError(msg, `Signing key ${signingKeyId} is missing permissions for operation ${opT}`); - return false; - } - if (opT === SPMessage.OP_ACTION_UNENCRYPTED && !validateActionPermissions(msg, signingKey, state, opT, opV)) { - return false; + var warned = /* @__PURE__ */ new Set(); + var deprecatedOption = (opt, instead) => { + const code2 = `LRU_CACHE_OPTION_${opt}`; + if (shouldWarn(code2)) { + warn(code2, `${opt} option`, `options.${instead}`, LRUCache); } - if (!config2.skipActionProcessing && opT === SPMessage.OP_ACTION_ENCRYPTED && !validateActionPermissions(msg, signingKey, state, opT, opV.valueOf())) { - return false; + }; + var deprecatedMethod = (method, instead) => { + const code2 = `LRU_CACHE_METHOD_${method}`; + if (shouldWarn(code2)) { + const { prototype } = LRUCache; + const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, method); + warn(code2, `${method} method`, `cache.${instead}()`, get2); } - return true; }; - validateKeyAddPermissions = function(contractID, signingKey, state, v2, skipPrivateCheck) { - const signingKeyPermissions = Array.isArray(signingKey.permissions) ? new Set(signingKey.permissions) : signingKey.permissions; - const signingKeyAllowedActions = Array.isArray(signingKey.allowedActions) ? new Set(signingKey.allowedActions) : signingKey.allowedActions; - if (!state._vm?.authorizedKeys?.[signingKey.id]) { - throw new Error("Singing key for OP_KEY_ADD or OP_KEY_UPDATE must exist in _vm.authorizedKeys. contractID=" + contractID + " signingKeyId=" + signingKey.id); + var deprecatedProperty = (field, instead) => { + const code2 = `LRU_CACHE_PROPERTY_${field}`; + if (shouldWarn(code2)) { + const { prototype } = LRUCache; + const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, field); + warn(code2, `${field} property`, `cache.${instead}`, get2); } - const localSigningKey = state._vm.authorizedKeys[signingKey.id]; - v2.forEach((wk) => { - const data = this.config.unwrapMaybeEncryptedData(wk); - if (!data) - return; - const k = data.data; - if (!skipPrivateCheck && signingKey._private && !data.encryptionKeyId) { - throw new Error("Signing key is private but it tried adding a public key"); - } - if (!Number.isSafeInteger(k.ringLevel) || k.ringLevel < localSigningKey.ringLevel) { - throw new Error("Signing key has ringLevel " + localSigningKey.ringLevel + " but attempted to add or update a key with ringLevel " + k.ringLevel); - } - if (signingKeyPermissions !== "*") { - if (!Array.isArray(k.permissions) || !k.permissions.reduce((acc, cv) => acc && signingKeyPermissions.has(cv), true)) { - throw new Error("Unable to add or update a key with more permissions than the signing key. signingKey permissions: " + String(signingKey?.permissions) + "; key add permissions: " + String(k.permissions)); - } - } - if (signingKeyAllowedActions !== "*" && k.allowedActions) { - if (!signingKeyAllowedActions || !Array.isArray(k.allowedActions) || !k.allowedActions.reduce((acc, cv) => acc && signingKeyAllowedActions.has(cv), true)) { - throw new Error("Unable to add or update a key with more allowed actions than the signing key. signingKey allowed actions: " + String(signingKey?.allowedActions) + "; key add allowed actions: " + String(k.allowedActions)); - } - } - }); }; - validateKeyDelPermissions = function(contractID, signingKey, state, v2) { - if (!state._vm?.authorizedKeys?.[signingKey.id]) { - throw new Error("Singing key for OP_KEY_DEL must exist in _vm.authorizedKeys. contractID=" + contractID + " signingKeyId=" + signingKey.id); + var emitWarning = (...a) => { + typeof process === "object" && process && typeof process.emitWarning === "function" ? process.emitWarning(...a) : console.error(...a); + }; + var shouldWarn = (code2) => !warned.has(code2); + var warn = (code2, what, instead, fn) => { + warned.add(code2); + const msg = `The ${what} is deprecated. Please use ${instead} instead.`; + emitWarning(msg, "DeprecationWarning", code2, fn); + }; + var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n); + var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null; + var ZeroArray = class extends Array { + constructor(size) { + super(size); + this.fill(0); } - const localSigningKey = state._vm.authorizedKeys[signingKey.id]; - v2.forEach((wid) => { - const data = this.config.unwrapMaybeEncryptedData(wid); - if (!data) - return; - const id = data.data; - const k = state._vm.authorizedKeys[id]; - if (!k) { - throw new Error("Nonexisting key ID " + id); - } - if (signingKey._private) { - throw new Error("Signing key is private"); - } - if (!k._private !== !data.encryptionKeyId) { - throw new Error("_private attribute must be preserved"); - } - if (!Number.isSafeInteger(k.ringLevel) || k.ringLevel < localSigningKey.ringLevel) { - throw new Error("Signing key has ringLevel " + localSigningKey.ringLevel + " but attempted to remove a key with ringLevel " + k.ringLevel); + }; + var Stack = class { + constructor(max) { + if (max === 0) { + return []; } - }); + const UintArray = getUintArray(max); + this.heap = new UintArray(max); + this.length = 0; + } + push(n) { + this.heap[this.length++] = n; + } + pop() { + return this.heap[--this.length]; + } }; - validateKeyUpdatePermissions = function(contractID, signingKey, state, v2) { - const updatedMap = /* @__PURE__ */ Object.create(null); - const keys = v2.map((wuk) => { - const data = this.config.unwrapMaybeEncryptedData(wuk); - if (!data) - return void 0; - const uk = data.data; - const existingKey = state._vm.authorizedKeys[uk.oldKeyId]; - if (!existingKey) { - throw new ChelErrorWarning("Missing old key ID " + uk.oldKeyId); + var LRUCache = class _LRUCache { + constructor(options2 = {}) { + const { + max = 0, + ttl, + ttlResolution = 1, + ttlAutopurge, + updateAgeOnGet, + updateAgeOnHas, + allowStale, + dispose, + disposeAfter, + noDisposeOnSet, + noUpdateTTL, + maxSize = 0, + maxEntrySize = 0, + sizeCalculation, + fetchMethod, + fetchContext, + noDeleteOnFetchRejection, + noDeleteOnStaleGet + } = options2; + const { length: length2, maxAge: maxAge2, stale } = options2 instanceof _LRUCache ? {} : options2; + if (max !== 0 && !isPosInt(max)) { + throw new TypeError("max option must be a nonnegative integer"); } - if (!existingKey._private !== !data.encryptionKeyId) { - throw new Error("_private attribute must be preserved"); + const UintArray = max ? getUintArray(max) : Array; + if (!UintArray) { + throw new Error("invalid max value: " + max); } - if (uk.name !== existingKey.name) { - throw new Error("Name cannot be updated"); + this.max = max; + this.maxSize = maxSize; + this.maxEntrySize = maxEntrySize || this.maxSize; + this.sizeCalculation = sizeCalculation || length2; + if (this.sizeCalculation) { + if (!this.maxSize && !this.maxEntrySize) { + throw new TypeError( + "cannot set sizeCalculation without setting maxSize or maxEntrySize" + ); + } + if (typeof this.sizeCalculation !== "function") { + throw new TypeError("sizeCalculation set to non-function"); + } } - if (!uk.id !== !uk.data) { - throw new Error("Both or none of the id and data attributes must be provided. Old key ID: " + uk.oldKeyId); + this.fetchMethod = fetchMethod || null; + if (this.fetchMethod && typeof this.fetchMethod !== "function") { + throw new TypeError( + "fetchMethod must be a function if specified" + ); } - if (uk.data && existingKey.meta?.private && !uk.meta?.private) { - throw new Error("Missing private key. Old key ID: " + uk.oldKeyId); + this.fetchContext = fetchContext; + if (!this.fetchMethod && fetchContext !== void 0) { + throw new TypeError( + "cannot set fetchContext without fetchMethod" + ); } - if (uk.id && uk.id !== uk.oldKeyId) { - updatedMap[uk.id] = uk.oldKeyId; + this.keyMap = /* @__PURE__ */ new Map(); + this.keyList = new Array(max).fill(null); + this.valList = new Array(max).fill(null); + this.next = new UintArray(max); + this.prev = new UintArray(max); + this.head = 0; + this.tail = 0; + this.free = new Stack(max); + this.initialFill = 1; + this.size = 0; + if (typeof dispose === "function") { + this.dispose = dispose; } - const updatedKey = omit2(existingKey, [ - "_notAfterHeight", - "_notBeforeHeight" - ]); - if (uk.permissions) { - updatedKey.permissions = uk.permissions; - } - if (uk.allowedActions) { - updatedKey.allowedActions = uk.allowedActions; - } - if (uk.purpose) { - updatedKey.purpose = uk.purpose; - } - if (uk.meta) { - updatedKey.meta = uk.meta; - } else if (updatedKey.meta) { - Object.defineProperty(updatedKey.meta, copiedExistingData, { value: true }); - } - if (uk.id) { - updatedKey.id = uk.id; - } - if (uk.data) { - updatedKey.data = uk.data; - } - return updatedKey; - }).filter(Boolean); - validateKeyAddPermissions.call(this, contractID, signingKey, state, keys, true); - return [keys, updatedMap]; - }; - keyAdditionProcessor = function(_msg, hash3, keys, state, contractID, _signingKey, internalSideEffectStack) { - const decryptedKeys = []; - const keysToPersist = []; - const storeSecretKey = (key, decryptedKey) => { - const decryptedDeserializedKey = deserializeKey(decryptedKey); - const transient = !!key.meta?.private?.transient; - esm_default("chelonia/storeSecretKeys", new Secret([ - { - key: decryptedDeserializedKey, - // We always set this to true because this could be done from - // an outgoing message - transient: true - } - ])); - if (!transient) { - keysToPersist.push({ key: decryptedDeserializedKey, transient }); + if (typeof disposeAfter === "function") { + this.disposeAfter = disposeAfter; + this.disposed = []; + } else { + this.disposeAfter = null; + this.disposed = null; } - }; - for (const wkey of keys) { - const data = this.config.unwrapMaybeEncryptedData(wkey); - if (!data) - continue; - const key = data.data; - let decryptedKey; - if (key.meta?.private?.content && !has(key.meta, copiedExistingData)) { - if (key.id && !esm_default("chelonia/haveSecretKey", key.id, !key.meta.private.transient)) { - const decryptedKeyResult = this.config.unwrapMaybeEncryptedData(key.meta.private.content); - if (decryptedKeyResult) { - if (decryptedKeyResult.encryptionKeyId == null) { - throw new Error("Expected encrypted data but got unencrypted data for key with ID: " + key.id); - } - decryptedKey = decryptedKeyResult.data; - decryptedKeys.push([key.id, decryptedKey]); - storeSecretKey(key, decryptedKey); + this.noDisposeOnSet = !!noDisposeOnSet; + this.noUpdateTTL = !!noUpdateTTL; + this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection; + if (this.maxEntrySize !== 0) { + if (this.maxSize !== 0) { + if (!isPosInt(this.maxSize)) { + throw new TypeError( + "maxSize must be a positive integer if specified" + ); } } - } - if (key.name === "#sak") { - if (data.encryptionKeyId) { - throw new Error("#sak may not be encrypted"); - } - if (key.permissions && (!Array.isArray(key.permissions) || key.permissions.length !== 0)) { - throw new Error("#sak may not have permissions"); - } - if (!Array.isArray(key.purpose) || key.purpose.length !== 1 || key.purpose[0] !== "sak") { - throw new Error("#sak must have exactly one purpose: 'sak'"); + if (!isPosInt(this.maxEntrySize)) { + throw new TypeError( + "maxEntrySize must be a positive integer if specified" + ); } - if (key.ringLevel !== 0) { - throw new Error("#sak must have ringLevel 0"); + this.initializeSizeTracking(); + } + this.allowStale = !!allowStale || !!stale; + this.noDeleteOnStaleGet = !!noDeleteOnStaleGet; + this.updateAgeOnGet = !!updateAgeOnGet; + this.updateAgeOnHas = !!updateAgeOnHas; + this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1; + this.ttlAutopurge = !!ttlAutopurge; + this.ttl = ttl || maxAge2 || 0; + if (this.ttl) { + if (!isPosInt(this.ttl)) { + throw new TypeError( + "ttl must be a positive integer if specified" + ); } + this.initializeTTLTracking(); } - if (key.name.startsWith("#inviteKey-")) { - if (!state._vm.invites) - state._vm.invites = /* @__PURE__ */ Object.create(null); - const inviteSecret = decryptedKey || (has(this.transientSecretKeys, key.id) ? serializeKey(this.transientSecretKeys[key.id], true) : void 0); - state._vm.invites[key.id] = { - status: INVITE_STATUS.VALID, - initialQuantity: key.meta.quantity, - quantity: key.meta.quantity, - expires: key.meta.expires, - inviteSecret, - responses: [] - }; + if (this.max === 0 && this.ttl === 0 && this.maxSize === 0) { + throw new TypeError( + "At least one of max, maxSize, or ttl is required" + ); } - if (key.meta?.keyRequest?.contractID && findSuitableSecretKeyId(state, [SPMessage.OP_KEY_ADD], ["sig"])) { - const data2 = this.config.unwrapMaybeEncryptedData(key.meta.keyRequest.contractID); - if (data2 && internalSideEffectStack) { - const keyRequestContractID = data2.data; - const reference = this.config.unwrapMaybeEncryptedData(key.meta.keyRequest.reference); - internalSideEffectStack.push(() => { - esm_default("chelonia/private/queueEvent", keyRequestContractID, () => { - const rootState = esm_default(this.config.stateSelector); - const originatingContractState = rootState[contractID]; - if (esm_default("chelonia/contract/hasKeyShareBeenRespondedBy", originatingContractState, keyRequestContractID, reference)) { - return; - } - if (!has(rootState, keyRequestContractID)) { - this.config.reactiveSet(rootState, keyRequestContractID, /* @__PURE__ */ Object.create(null)); - } - const targetState = rootState[keyRequestContractID]; - if (!targetState._volatile) { - this.config.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); - } - if (!targetState._volatile.pendingKeyRequests) { - this.config.reactiveSet(rootState[keyRequestContractID]._volatile, "pendingKeyRequests", []); - } - if (targetState._volatile.pendingKeyRequests.some((pkr) => { - return pkr && pkr.contractID === contractID && pkr.hash === hash3; - })) { - return; - } - targetState._volatile.pendingKeyRequests.push({ - contractID, - name: key.name, - hash: hash3, - reference: reference?.data - }); - this.setPostSyncOp(contractID, "pending-keys-for-" + keyRequestContractID, [ - "okTurtles.events/emit", - CONTRACT_IS_PENDING_KEY_REQUESTS, - { contractID: keyRequestContractID } - ]); - }).catch((e2) => { - console.error("Error while setting or updating pendingKeyRequests", { contractID, keyRequestContractID, reference }, e2); - }); - }); + if (!this.ttlAutopurge && !this.max && !this.maxSize) { + const code2 = "LRU_CACHE_UNBOUNDED"; + if (shouldWarn(code2)) { + warned.add(code2); + const msg = "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption."; + emitWarning(msg, "UnboundedCacheWarning", code2, _LRUCache); } } + if (stale) { + deprecatedOption("stale", "allowStale"); + } + if (maxAge2) { + deprecatedOption("maxAge", "ttl"); + } + if (length2) { + deprecatedOption("length", "sizeCalculation"); + } } - if (keysToPersist.length) { - internalSideEffectStack?.push(() => { - esm_default("chelonia/storeSecretKeys", new Secret(keysToPersist)); - }); + getRemainingTTL(key) { + return this.has(key, { updateAgeOnHas: false }) ? Infinity : 0; } - internalSideEffectStack?.push(() => subscribeToForeignKeyContracts.call(this, contractID, state)); - }; - subscribeToForeignKeyContracts = function(contractID, state) { - try { - Object.values(state._vm.authorizedKeys).filter((key) => !!key.foreignKey && findKeyIdByName(state, key.name) != null).forEach((key) => { - const foreignKey = String(key.foreignKey); - const fkUrl = new URL(foreignKey); - const foreignContract = fkUrl.pathname; - const foreignKeyName = fkUrl.searchParams.get("keyName"); - if (!foreignContract || !foreignKeyName) { - console.warn("Invalid foreign key: missing contract or key name", { - contractID, - keyId: key.id - }); - return; + initializeTTLTracking() { + this.ttls = new ZeroArray(this.max); + this.starts = new ZeroArray(this.max); + this.setItemTTL = (index, ttl, start = perf.now()) => { + this.starts[index] = ttl !== 0 ? start : 0; + this.ttls[index] = ttl; + if (ttl !== 0 && this.ttlAutopurge) { + const t = setTimeout(() => { + if (this.isStale(index)) { + this.delete(this.keyList[index]); + } + }, ttl + 1); + if (t.unref) { + t.unref(); + } } - const rootState = esm_default(this.config.stateSelector); - const signingKey = findSuitableSecretKeyId(state, [SPMessage.OP_KEY_DEL], ["sig"], key.ringLevel); - const canMirrorOperations = !!signingKey; - if (!canMirrorOperations) - return; - if (Array.isArray(rootState?.[foreignContract]?._volatile?.watch)) { - if (rootState[foreignContract]._volatile.watch.find((v2) => v2[0] === key.name && v2[1] === contractID)) { - return; + }; + this.updateItemAge = (index) => { + this.starts[index] = this.ttls[index] !== 0 ? perf.now() : 0; + }; + let cachedNow = 0; + const getNow = () => { + const n = perf.now(); + if (this.ttlResolution > 0) { + cachedNow = n; + const t = setTimeout( + () => cachedNow = 0, + this.ttlResolution + ); + if (t.unref) { + t.unref(); } } - if (!has(state._vm, "pendingWatch")) { - this.config.reactiveSet(state._vm, "pendingWatch", /* @__PURE__ */ Object.create(null)); + return n; + }; + this.getRemainingTTL = (key) => { + const index = this.keyMap.get(key); + if (index === void 0) { + return 0; } - if (!has(state._vm.pendingWatch, foreignContract)) { - this.config.reactiveSet(state._vm.pendingWatch, foreignContract, []); + return this.ttls[index] === 0 || this.starts[index] === 0 ? Infinity : this.starts[index] + this.ttls[index] - (cachedNow || getNow()); + }; + this.isStale = (index) => { + return this.ttls[index] !== 0 && this.starts[index] !== 0 && (cachedNow || getNow()) - this.starts[index] > this.ttls[index]; + }; + } + updateItemAge(index) { + } + setItemTTL(index, ttl, start) { + } + isStale(index) { + return false; + } + initializeSizeTracking() { + this.calculatedSize = 0; + this.sizes = new ZeroArray(this.max); + this.removeItemSize = (index) => { + this.calculatedSize -= this.sizes[index]; + this.sizes[index] = 0; + }; + this.requireSize = (k, v2, size, sizeCalculation) => { + if (!isPosInt(size)) { + if (sizeCalculation) { + if (typeof sizeCalculation !== "function") { + throw new TypeError("sizeCalculation must be a function"); + } + size = sizeCalculation(v2, k); + if (!isPosInt(size)) { + throw new TypeError( + "sizeCalculation return invalid (expect positive integer)" + ); + } + } else { + throw new TypeError( + "invalid size value (must be positive integer)" + ); + } } - if (!state._vm.pendingWatch[foreignContract].find(([n]) => n === foreignKeyName)) { - state._vm.pendingWatch[foreignContract].push([foreignKeyName, key.id]); + return size; + }; + this.addItemSize = (index, size) => { + this.sizes[index] = size; + const maxSize = this.maxSize - this.sizes[index]; + while (this.calculatedSize > maxSize) { + this.evict(true); } - this.setPostSyncOp(contractID, `watchForeignKeys-${contractID}`, [ - "chelonia/private/watchForeignKeys", - contractID - ]); - }); - } catch (e2) { - console.warn("Error at subscribeToForeignKeyContracts: " + (e2.message || e2)); - } - }; - recreateEvent = (entry, state, contractsState, disableAutoDedup) => { - const { HEAD: previousHEAD, height: previousHeight, previousKeyOp } = contractsState || {}; - if (!previousHEAD) { - throw new Error("recreateEvent: Giving up because the contract has been removed"); - } - const head = entry.head(); - const [opT, rawOpV] = entry.rawOp(); - const recreateOperation = (opT2, rawOpV2) => { - const opV = rawOpV2.valueOf(); - const recreateOperationInternal = (opT3, opV2) => { - let newOpV2; - if (opT3 === SPMessage.OP_KEY_ADD) { - if (!Array.isArray(opV2)) - throw new Error("Invalid message format"); - newOpV2 = opV2.filter((k) => { - const kId = k.valueOf().id; - return !has(state._vm.authorizedKeys, kId) || state._vm.authorizedKeys[kId]._notAfterHeight != null; - }); - if (newOpV2.length === 0) { - console.info("Omitting empty OP_KEY_ADD", { head }); - } else if (newOpV2.length === opV2.length) { - return opV2; + this.calculatedSize += this.sizes[index]; + }; + } + removeItemSize(index) { + } + addItemSize(index, size) { + } + requireSize(k, v2, size, sizeCalculation) { + if (size || sizeCalculation) { + throw new TypeError( + "cannot set size without setting maxSize or maxEntrySize on cache" + ); + } + } + *indexes({ allowStale = this.allowStale } = {}) { + if (this.size) { + for (let i2 = this.tail; true; ) { + if (!this.isValidIndex(i2)) { + break; } - } else if (opT3 === SPMessage.OP_KEY_DEL) { - if (!Array.isArray(opV2)) - throw new Error("Invalid message format"); - newOpV2 = opV2.filter((keyId2) => { - const kId = Object(keyId2).valueOf(); - return has(state._vm.authorizedKeys, kId) && state._vm.authorizedKeys[kId]._notAfterHeight == null; - }); - if (newOpV2.length === 0) { - console.info("Omitting empty OP_KEY_DEL", { head }); - } else if (newOpV2.length === opV2.length) { - return opV2; + if (allowStale || !this.isStale(i2)) { + yield i2; } - } else if (opT3 === SPMessage.OP_KEY_UPDATE) { - if (!Array.isArray(opV2)) - throw new Error("Invalid message format"); - newOpV2 = opV2.filter((k) => { - const oKId = k.valueOf().oldKeyId; - const nKId = k.valueOf().id; - return nKId == null || has(state._vm.authorizedKeys, oKId) && state._vm.authorizedKeys[oKId]._notAfterHeight == null; - }); - if (newOpV2.length === 0) { - console.info("Omitting empty OP_KEY_UPDATE", { head }); - } else if (newOpV2.length === opV2.length) { - return opV2; + if (i2 === this.head) { + break; + } else { + i2 = this.prev[i2]; + } + } + } + } + *rindexes({ allowStale = this.allowStale } = {}) { + if (this.size) { + for (let i2 = this.head; true; ) { + if (!this.isValidIndex(i2)) { + break; + } + if (allowStale || !this.isStale(i2)) { + yield i2; } - } else if (opT3 === SPMessage.OP_ATOMIC) { - if (!Array.isArray(opV2)) - throw new Error("Invalid message format"); - newOpV2 = opV2.map(([t, v2]) => [t, recreateOperationInternal(t, v2)]).filter(([, v2]) => !!v2); - if (newOpV2.length === 0) { - console.info("Omitting empty OP_ATOMIC", { head }); - } else if (newOpV2.length === opV2.length && newOpV2.reduce((acc, cv, i2) => acc && cv === opV2[i2], true)) { - return opV2; + if (i2 === this.tail) { + break; } else { - return newOpV2; + i2 = this.next[i2]; } - } else { - return opV2; } - }; - const newOpV = recreateOperationInternal(opT2, opV); - if (newOpV === opV) { - return rawOpV2; - } else if (newOpV === void 0) { - return; } - if (typeof rawOpV2.recreate !== "function") { - throw new Error("Unable to recreate operation"); + } + isValidIndex(index) { + return this.keyMap.get(this.keyList[index]) === index; + } + *entries() { + for (const i2 of this.indexes()) { + yield [this.keyList[i2], this.valList[i2]]; } - return rawOpV2.recreate(newOpV); - }; - const newRawOpV = disableAutoDedup ? rawOpV : recreateOperation(opT, rawOpV); - if (!newRawOpV) - return; - const newOp = [opT, newRawOpV]; - entry = SPMessage.cloneWith(head, newOp, { - previousKeyOp, - previousHEAD, - height: previousHeight + 1 - }); - return entry; - }; - getContractIDfromKeyId = (contractID, signingKeyId, state) => { - if (!signingKeyId) - return; - return signingKeyId && state._vm?.authorizedKeys?.[signingKeyId]?.foreignKey ? new URL(state._vm.authorizedKeys[signingKeyId].foreignKey).pathname : contractID; - }; - clearObject = (o2) => { - Object.keys(o2).forEach((k) => delete o2[k]); - }; - reactiveClearObject = (o2, fn) => { - Object.keys(o2).forEach((k) => fn(o2, k)); - }; - checkCanBeGarbageCollected = function(id) { - const rootState = esm_default(this.config.stateSelector); - return ( - // Check persistent references - (!has(rootState.contracts, id) || !rootState.contracts[id] || !has(rootState.contracts[id], "references")) && // Check ephemeral references - !has(this.ephemeralReferenceCount, id) && // Check foreign keys (i.e., that no keys from this contract are being watched) - (!has(rootState, id) || !has(rootState[id], "_volatile") || !has(rootState[id]._volatile, "watch") || rootState[id]._volatile.watch.length === 0 || rootState[id]._volatile.watch.filter(([, cID]) => this.subscriptionSet.has(cID)).length === 0) - ); - }; - collectEventStream = async (s) => { - const reader = s.getReader(); - const r = []; - for (; ; ) { - const { done, value } = await reader.read(); - if (done) - break; - r.push(value); } - return r; - }; - logEvtError = (msg, ...args) => { - if (msg._direction === "outgoing") { - console.warn(...args); - } else { - console.error(...args); + *rentries() { + for (const i2 of this.rindexes()) { + yield [this.keyList[i2], this.valList[i2]]; + } } - }; - handleFetchResult = (type) => { - return function(r) { - if (!r.ok) { - const msg = `${r.status}: ${r.statusText}`; - if (r.status === 404 || r.status === 410) { - throw new ChelErrorResourceGone(msg, { cause: r.status }); - } - throw new ChelErrorUnexpectedHttpResponseCode(msg, { cause: r.status }); + *keys() { + for (const i2 of this.indexes()) { + yield this.keyList[i2]; } - return r[type](); - }; - }; - } -}); -var supportsRequestStreams; -var streamToUint8Array; -var ArrayBufferToUint8ArrayStream; -var computeChunkDescriptors; -var fileStream; -var aes256gcmHandlers; -var noneHandlers; -var cipherHandlers; -var files_default; -var init_files = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/files.mjs"() { - init_encodeMultipartMessage(); - init_decrypt(); - init_encodings(); - init_encrypt(); - init_esm7(); - init_bytes(); - init_esm(); - init_esm5(); - init_functions(); - init_utils(); - supportsRequestStreams = typeof window !== "object" || (() => { - let duplexAccessed = false; - const hasContentType = new Request("", { - body: new ReadableStream(), - method: "POST", - get duplex() { - duplexAccessed = true; - return "half"; + } + *rkeys() { + for (const i2 of this.rindexes()) { + yield this.keyList[i2]; } - }).headers.has("content-type"); - return duplexAccessed && !hasContentType; - })(); - streamToUint8Array = async (s) => { - const reader = s.getReader(); - const chunks = []; - let length2 = 0; - for (; ; ) { - const result = await reader.read(); - if (result.done) - break; - chunks.push(coerce(result.value)); - length2 += result.value.byteLength; - } - const body = new Uint8Array(length2); - chunks.reduce((offset, chunk) => { - body.set(chunk, offset); - return offset + chunk.byteLength; - }, 0); - return body; - }; - ArrayBufferToUint8ArrayStream = async function(connectionURL, s) { - if (supportsRequestStreams === true) { - await this.config.fetch(`${connectionURL}/streams-test`, { - method: "POST", - body: new ReadableStream({ - start(c) { - c.enqueue(Buffer4.from("ok")); - c.close(); - } - }), - duplex: "half" - }).then((r) => { - if (!r.ok) - throw new Error("Unexpected response"); - supportsRequestStreams = 2; - }).catch(() => { - console.info("files: Disabling streams support because the streams test failed"); - supportsRequestStreams = false; - }); } - if (!supportsRequestStreams) { - return await streamToUint8Array(s); + *values() { + for (const i2 of this.indexes()) { + yield this.valList[i2]; + } } - return s.pipeThrough( - // eslint-disable-next-line no-undef - new TransformStream({ - transform(chunk, controller) { - controller.enqueue(coerce(chunk)); - } - }) - ); - }; - computeChunkDescriptors = (inStream) => { - let length2 = 0; - const [lengthStream, cidStream] = inStream.tee(); - const lengthPromise = new Promise((resolve82, reject) => { - lengthStream.pipeTo(new WritableStream({ - write(chunk) { - length2 += chunk.byteLength; - }, - close() { - resolve82(length2); - }, - abort(reason) { - reject(reason); - } - })); - }); - const cidPromise = createCIDfromStream(cidStream, multicodes.SHELTER_FILE_CHUNK); - return Promise.all([lengthPromise, cidPromise]); - }; - fileStream = (chelonia, manifest2) => { - const dataGenerator = async function* () { - let readSize = 0; - for (const chunk of manifest2.chunks) { - if (!Array.isArray(chunk) || typeof chunk[0] !== "number" || typeof chunk[1] !== "string") { - throw new Error("Invalid chunk descriptor"); - } - const chunkResponse = await chelonia.config.fetch(`${chelonia.config.connectionURL}/file/${chunk[1]}`, { - method: "GET", - signal: chelonia.abortController.signal - }); - if (!chunkResponse.ok) { - throw new Error("Unable to retrieve manifest"); - } - const chunkBinary = await chunkResponse.arrayBuffer(); - if (chunkBinary.byteLength !== chunk[0]) - throw new Error("mismatched chunk size"); - readSize += chunkBinary.byteLength; - if (readSize > manifest2.size) - throw new Error("read size exceeds declared size"); - if (createCID(coerce(chunkBinary), multicodes.SHELTER_FILE_CHUNK) !== chunk[1]) { - throw new Error("mismatched chunk hash"); - } - yield chunkBinary; - } - if (readSize !== manifest2.size) - throw new Error("mismatched size"); - }; - const dataIterator = dataGenerator(); - return new ReadableStream({ - async pull(controller) { - try { - const chunk = await dataIterator.next(); - if (chunk.done) { - controller.close(); - return; - } - controller.enqueue(chunk.value); - } catch (e2) { - controller.error(e2); - } + *rvalues() { + for (const i2 of this.rindexes()) { + yield this.valList[i2]; } - }); - }; - aes256gcmHandlers = { - upload: (_chelonia, manifestOptions) => { - const params = manifestOptions["cipher-params"]; - let IKM = params?.IKM; - const recordSize = params?.rs ?? 1 << 16; - if (!IKM) { - IKM = new Uint8Array(33); - self.crypto.getRandomValues(IKM); - } - const keyId2 = blake32Hash("aes256gcm-keyId" + blake32Hash(IKM)).slice(-8); - const binaryKeyId = Buffer4.from(keyId2); - return { - cipherParams: { - keyId: keyId2 - }, - streamHandler: async (stream) => { - return await K(e, stream, recordSize, binaryKeyId, IKM); - }, - downloadParams: { - IKM: Buffer4.from(IKM).toString("base64"), - rs: recordSize + } + [Symbol.iterator]() { + return this.entries(); + } + find(fn, getOptions = {}) { + for (const i2 of this.indexes()) { + if (fn(this.valList[i2], this.keyList[i2], this)) { + return this.get(this.keyList[i2], getOptions); } - }; - }, - download: (chelonia, downloadParams, manifest2) => { - const IKMb64 = downloadParams.IKM; - if (!IKMb64) { - throw new Error("Missing IKM in downloadParams"); } - const IKM = Buffer4.from(IKMb64, "base64"); - const keyId2 = blake32Hash("aes256gcm-keyId" + blake32Hash(IKM)).slice(-8); - if (!manifest2["cipher-params"] || !manifest2["cipher-params"].keyId) { - throw new Error("Missing cipher-params"); - } - if (keyId2 !== manifest2["cipher-params"].keyId) { - throw new Error("Key ID mismatch"); + } + forEach(fn, thisp = this) { + for (const i2 of this.indexes()) { + fn.call(thisp, this.valList[i2], this.keyList[i2], this); } - const maxRecordSize = downloadParams.rs ?? 1 << 27; - return { - payloadHandler: async () => { - const bytes = await streamToUint8Array(S(e, fileStream(chelonia, manifest2), (actualKeyId) => { - if (Buffer4.from(actualKeyId).toString() !== keyId2) { - throw new Error("Invalid key ID"); - } - return IKM; - }, maxRecordSize)); - return new Blob([bytes], { type: manifest2.type || "application/octet-stream" }); - } - }; } - }; - noneHandlers = { - upload: () => { - return { - cipherParams: void 0, - streamHandler: (stream) => { - return stream; - }, - downloadParams: void 0 - }; - }, - download: (chelonia, _downloadParams, manifest2) => { - return { - payloadHandler: async () => { - const bytes = await streamToUint8Array(fileStream(chelonia, manifest2)); - return new Blob([bytes], { type: manifest2.type || "application/octet-stream" }); - } - }; + rforEach(fn, thisp = this) { + for (const i2 of this.rindexes()) { + fn.call(thisp, this.valList[i2], this.keyList[i2], this); + } } - }; - cipherHandlers = { - aes256gcm: aes256gcmHandlers, - none: noneHandlers - }; - files_default = esm_default("sbp/selectors/register", { - "chelonia/fileUpload": async function(chunks, manifestOptions, { billableContractID } = {}) { - if (!Array.isArray(chunks)) - chunks = [chunks]; - const chunkDescriptors = []; - const cipherHandler = await cipherHandlers[manifestOptions.cipher]?.upload?.(this, manifestOptions); - if (!cipherHandler) - throw new Error("Unsupported cipher"); - const cipherParams = cipherHandler.cipherParams; - const transferParts = await Promise.all(chunks.map(async (chunk, i2) => { - const stream2 = chunk.stream(); - const encryptedStream = await cipherHandler.streamHandler(stream2); - const [body, s] = encryptedStream.tee(); - chunkDescriptors.push(computeChunkDescriptors(s)); - return { - headers: new Headers([ - ["content-disposition", `form-data; name="${i2}"; filename="${i2}"`], - ["content-type", "application/octet-stream"] - ]), - body - }; - })); - transferParts.push({ - headers: new Headers([ - ["content-disposition", 'form-data; name="manifest"; filename="manifest.json"'], - ["content-type", "application/vnd.shelter.filemanifest"] - ]), - body: new ReadableStream({ - async start(controller) { - const chunks2 = await Promise.all(chunkDescriptors); - const manifest2 = { - version: "1.0.0", - // ?? undefined coerces null and undefined to undefined - // This ensures that null or undefined values don't make it to the - // JSON (otherwise, null values _would_ be stringified as 'null') - type: manifestOptions.type ?? void 0, - meta: manifestOptions.meta ?? void 0, - cipher: manifestOptions.cipher, - "cipher-params": cipherParams, - size: chunks2.reduce((acc, [cv]) => acc + cv, 0), - chunks: chunks2, - "name-map": manifestOptions["name-map"] ?? void 0, - alternatives: manifestOptions.alternatives ?? void 0 - }; - controller.enqueue(Buffer4.from(JSON.stringify(manifest2))); - controller.close(); - } - }) - }); - const boundary = typeof self.crypto?.randomUUID === "function" ? self.crypto.randomUUID() : new Array(36).fill("").map(() => "abcdefghijklmnopqrstuvwxyz"[(0, Math.random)() * 26 | 0]).join(""); - const stream = x(boundary, transferParts); - const deletionToken = "deletionToken" + generateSalt(); - const deletionTokenHash = blake32Hash(deletionToken); - const uploadResponse = await this.config.fetch(`${this.config.connectionURL}/file`, { - method: "POST", - signal: this.abortController.signal, - body: await ArrayBufferToUint8ArrayStream.call(this, this.config.connectionURL, stream), - headers: new Headers([ - ...billableContractID ? [["authorization", buildShelterAuthorizationHeader.call(this, billableContractID)]] : [], - ["content-type", `multipart/form-data; boundary=${boundary}`], - ["shelter-deletion-token-digest", deletionTokenHash] - ]), - duplex: "half" - }); - if (!uploadResponse.ok) - throw new Error("Error uploading file"); - return { - download: { - manifestCid: await uploadResponse.text(), - downloadParams: cipherHandler.downloadParams - }, - delete: deletionToken - }; - }, - "chelonia/fileDownload": async function(downloadOptions, manifestChecker) { - const { manifestCid, downloadParams } = downloadOptions.valueOf(); - const manifestResponse = await this.config.fetch(`${this.config.connectionURL}/file/${manifestCid}`, { - method: "GET", - signal: this.abortController.signal - }); - if (!manifestResponse.ok) { - throw new Error("Unable to retrieve manifest"); - } - const manifestBinary = await manifestResponse.arrayBuffer(); - if (createCID(coerce(manifestBinary), multicodes.SHELTER_FILE_MANIFEST) !== manifestCid) { - throw new Error("mismatched manifest hash"); - } - const manifest2 = JSON.parse(Buffer4.from(manifestBinary).toString()); - if (typeof manifest2 !== "object") - throw new Error("manifest format is invalid"); - if (manifest2.version !== "1.0.0") - throw new Error("unsupported manifest version"); - if (!Array.isArray(manifest2.chunks)) - throw new Error("missing required field: chunks"); - if (manifestChecker) { - const proceed = await manifestChecker?.(manifest2); - if (!proceed) - return false; - } - const cipherHandler = await cipherHandlers[manifest2.cipher]?.download?.(this, downloadParams, manifest2); - if (!cipherHandler) - throw new Error("Unsupported cipher"); - return cipherHandler.payloadHandler(); - }, - "chelonia/fileDelete": async function(manifestCid, credentials = {}) { - if (!manifestCid) { - throw new TypeError("A manifest CID must be provided"); - } - if (!Array.isArray(manifestCid)) - manifestCid = [manifestCid]; - return await Promise.allSettled(manifestCid.map(async (cid) => { - const hasCredential = has(credentials, cid); - const hasToken = has(credentials[cid], "token") && credentials[cid].token; - const hasBillableContractID = has(credentials[cid], "billableContractID") && credentials[cid].billableContractID; - if (!hasCredential || hasToken === hasBillableContractID) { - throw new TypeError(`Either a token or a billable contract ID must be provided for ${cid}`); - } - const response = await this.config.fetch(`${this.config.connectionURL}/deleteFile/${cid}`, { - method: "POST", - signal: this.abortController.signal, - headers: new Headers([ - [ - "authorization", - hasToken ? `bearer ${credentials[cid].token.valueOf()}` : buildShelterAuthorizationHeader.call(this, credentials[cid].billableContractID) - ] - ]) - }); - if (!response.ok) { - throw new Error(`Unable to delete file ${cid}`); - } - })); - } - }); - } -}); -var headPrefix; -var getContractIdFromLogHead; -var getLogHead; -var checkKey; -var parsePrefixableKey; -var prefixHandlers; -var dbPrimitiveSelectors; -var db_default; -var init_db = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/db.mjs"() { - init_esm3(); - init_esm2(); - init_esm(); - init_SPMessage(); - init_errors3(); - headPrefix = "head="; - getContractIdFromLogHead = (key) => { - if (!key.startsWith(headPrefix)) - return; - return key.slice(headPrefix.length); - }; - getLogHead = (contractID) => `${headPrefix}${contractID}`; - checkKey = (key) => { - if (/[\x00-\x1f\x7f\t\\/<>:"|?*]/.test(key)) { - throw new Error(`bad key: ${JSON.stringify(key)}`); - } - }; - parsePrefixableKey = (key) => { - const i2 = key.indexOf(":"); - if (i2 === -1) { - return ["", key]; - } - const prefix = key.slice(0, i2 + 1); - if (prefix in prefixHandlers) { - return [prefix, key.slice(prefix.length)]; - } - throw new ChelErrorDBConnection(`Unknown prefix in '${key}'.`); - }; - prefixHandlers = { - // Decode buffers, but don't transform other values. - "": (value) => Buffer5.isBuffer(value) ? value.toString("utf8") : value, - "any:": (value) => value - /* - // 2025-03-24: Commented out because it's not used; currently, only `any:` - // is used in the `/file` route. - // Throw if the value if not a buffer. - 'blob:': value => { - if (Buffer.isBuffer(value)) { - return value - } - throw new ChelErrorDBConnection('Unexpected value: expected a buffer.') - } - */ - }; - esm_default("sbp/selectors/unsafe", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys", "chelonia.db/keyCount"]); - dbPrimitiveSelectors = process.env.LIGHTWEIGHT_CLIENT === "true" ? { - "chelonia.db/get": function(key) { - const id = getContractIdFromLogHead(key); - if (!id) - return Promise.resolve(); - const state = esm_default("chelonia/rootState").contracts[id]; - const value = state?.HEAD ? JSON.stringify({ - HEAD: state.HEAD, - height: state.height, - previousKeyOp: state.previousKeyOp - }) : void 0; - return Promise.resolve(value); - }, - "chelonia.db/set": function() { - return Promise.resolve(); - }, - "chelonia.db/delete": function() { - return Promise.resolve(true); - }, - "chelonia.db/iterKeys": async function* () { - }, - "chelonia.db/keyCount": function() { - return Promise.resolve(0); + get prune() { + deprecatedMethod("prune", "purgeStale"); + return this.purgeStale; } - } : { - // eslint-disable-next-line require-await - "chelonia.db/get": async function(prefixableKey) { - const [prefix, key] = parsePrefixableKey(prefixableKey); - const value = esm_default("okTurtles.data/get", key); - if (value === void 0) { - return; + purgeStale() { + let deleted = false; + for (const i2 of this.rindexes({ allowStale: true })) { + if (this.isStale(i2)) { + this.delete(this.keyList[i2]); + deleted = true; + } } - return prefixHandlers[prefix](value); - }, - // eslint-disable-next-line require-await - "chelonia.db/set": async function(key, value) { - checkKey(key); - return esm_default("okTurtles.data/set", key, value); - }, - // eslint-disable-next-line require-await - "chelonia.db/delete": async function(key) { - return esm_default("okTurtles.data/delete", key); - }, - "chelonia.db/iterKeys": async function* () { - yield* esm_default("okTurtles.data/iterKeys"); - }, - "chelonia.db/keyCount": function() { - return Promise.resolve(esm_default("okTurtles.data/keyCount")); + return deleted; } - }; - db_default = esm_default("sbp/selectors/register", { - ...dbPrimitiveSelectors, - "chelonia/db/getEntryMeta": async (contractID, height) => { - const entryMetaJson = await esm_default("chelonia.db/get", `_private_hidx=${contractID}#${height}`); - if (!entryMetaJson) - return; - return JSON.parse(entryMetaJson); - }, - "chelonia/db/setEntryMeta": async (contractID, height, entryMeta) => { - const entryMetaJson = JSON.stringify(entryMeta); - await esm_default("chelonia.db/set", `_private_hidx=${contractID}#${height}`, entryMetaJson); - }, - "chelonia/db/latestHEADinfo": async (contractID) => { - const r = await esm_default("chelonia.db/get", getLogHead(contractID)); - return r && JSON.parse(r); - }, - "chelonia/db/deleteLatestHEADinfo": (contractID) => { - return esm_default("chelonia.db/set", getLogHead(contractID), ""); - }, - "chelonia/db/getEntry": async function(hash3) { - try { - const value = await esm_default("chelonia.db/get", hash3); - if (!value) - throw new Error(`no entry for ${hash3}!`); - return SPMessage.deserialize(value, this.transientSecretKeys, void 0, this.config.unwrapMaybeEncryptedData); - } catch (e2) { - throw new ChelErrorDBConnection(`${e2.name} during getEntry: ${e2.message}`); - } - }, - "chelonia/db/addEntry": function(entry) { - return esm_default("okTurtles.eventQueue/queueEvent", `chelonia/db/${entry.contractID()}`, ["chelonia/private/db/addEntry", entry]); - }, - // NEVER call this directly yourself! _always_ call 'chelonia/db/addEntry' instead - "chelonia/private/db/addEntry": async function(entry) { - try { - const { previousHEAD: entryPreviousHEAD, previousKeyOp: entryPreviousKeyOp, height: entryHeight } = entry.head(); - const contractID = entry.contractID(); - if (await esm_default("chelonia.db/get", entry.hash())) { - console.warn(`[chelonia.db] entry exists: ${entry.hash()}`); - return entry.hash(); - } - const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); - if (!entry.isFirstMessage()) { - if (!HEADinfo) { - throw new Error(`No latest HEAD for ${contractID} when attempting to process entry with previous HEAD ${entryPreviousHEAD} at height ${entryHeight}`); - } - const { HEAD: contractHEAD, previousKeyOp: contractPreviousKeyOp, height: contractHeight } = HEADinfo; - if (entryPreviousHEAD !== contractHEAD) { - console.warn(`[chelonia.db] bad previousHEAD: ${entryPreviousHEAD}! Expected: ${contractHEAD} for contractID: ${contractID}`); - throw new ChelErrorDBBadPreviousHEAD(`bad previousHEAD: ${entryPreviousHEAD}. Expected ${contractHEAD} for contractID: ${contractID}`); - } else if (entryPreviousKeyOp !== contractPreviousKeyOp) { - console.error(`[chelonia.db] bad previousKeyOp: ${entryPreviousKeyOp}! Expected: ${contractPreviousKeyOp} for contractID: ${contractID}`); - throw new ChelErrorDBBadPreviousHEAD(`bad previousKeyOp: ${entryPreviousKeyOp}. Expected ${contractPreviousKeyOp} for contractID: ${contractID}`); - } else if (!Number.isSafeInteger(entryHeight) || entryHeight !== contractHeight + 1) { - console.error(`[chelonia.db] bad height: ${entryHeight}! Expected: ${contractHeight + 1} for contractID: ${contractID}`); - throw new ChelErrorDBBadPreviousHEAD(`[chelonia.db] bad height: ${entryHeight}! Expected: ${contractHeight + 1} for contractID: ${contractID}`); - } - } else { - if (HEADinfo) { - console.error(`[chelonia.db] bad previousHEAD: ${entryPreviousHEAD}! Expected: for contractID: ${contractID}`); - throw new ChelErrorDBBadPreviousHEAD(`bad previousHEAD: ${entryPreviousHEAD}. Expected for contractID: ${contractID}`); - } else if (entryHeight !== 0) { - console.error(`[chelonia.db] bad height: ${entryHeight}! Expected: 0 for contractID: ${contractID}`); - throw new ChelErrorDBBadPreviousHEAD(`[chelonia.db] bad height: ${entryHeight}! Expected: 0 for contractID: ${contractID}`); - } + dump() { + const arr = []; + for (const i2 of this.indexes({ allowStale: true })) { + const key = this.keyList[i2]; + const v2 = this.valList[i2]; + const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; + const entry = { value }; + if (this.ttls) { + entry.ttl = this.ttls[i2]; + const age = perf.now() - this.starts[i2]; + entry.start = Math.floor(Date.now() - age); } - await esm_default("chelonia.db/set", entry.hash(), entry.serialize()); - await esm_default("chelonia.db/set", getLogHead(contractID), JSON.stringify({ - HEAD: entry.hash(), - previousKeyOp: entry.isKeyOp() ? entry.hash() : entry.previousKeyOp(), - height: entry.height() - })); - console.debug(`[chelonia.db] HEAD for ${contractID} updated to:`, entry.hash()); - await esm_default("chelonia/db/setEntryMeta", contractID, entryHeight, { - // The hash is used for reverse lookups (height to CID) - hash: entry.hash(), - // The date isn't currently used, but will be used for filtering messages - date: (/* @__PURE__ */ new Date()).toISOString(), - // isKeyOp is used for filtering messages (the actual filtering is - // done more efficiently a separate index key, but `isKeyOp` allows - // us to bootstrap this process without having to load the full message) - // The separate index key bears the prefix `_private_keyop_idx_`. - ...entry.isKeyOp() && { isKeyOp: true } - }); - return entry.hash(); - } catch (e2) { - if (e2.name.includes("ErrorDB")) { - throw e2; + if (this.sizes) { + entry.size = this.sizes[i2]; } - throw new ChelErrorDBConnection(`${e2.name} during addEntry: ${e2.message}`); + arr.unshift([key, entry]); } - }, - "chelonia/db/lastEntry": async function(contractID) { - try { - const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); - if (!latestHEADinfo) - throw new Error(`contract ${contractID} has no latest hash!`); - return esm_default("chelonia/db/getEntry", latestHEADinfo.HEAD); - } catch (e2) { - throw new ChelErrorDBConnection(`${e2.name} during lastEntry: ${e2.message}`); + return arr; + } + load(arr) { + this.clear(); + for (const [key, entry] of arr) { + if (entry.start) { + const age = Date.now() - entry.start; + entry.start = perf.now() - age; + } + this.set(key, entry.value, entry); } } - }); - } -}); -var missingDecryptionKeyIdsMap; -var getMsgMeta; -var keysToMap; -var keyRotationHelper; -var internals_default; -var eventsToReingest; -var reprocessDebounced; -var handleEvent; -var notImplemented; -var init_internals = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/internals.mjs"() { - init_esm(); - init_functions(); - init_esm5(); - init_SPMessage(); - init_Secret(); - init_constants(); - init_esm7(); - init_db(); - init_encryptedData(); - init_errors3(); - init_events(); - init_utils(); - init_signedData(); - missingDecryptionKeyIdsMap = /* @__PURE__ */ new WeakMap(); - getMsgMeta = function(message, contractID, state, index) { - const signingKeyId = message.signingKeyId(); - let innerSigningKeyId = null; - const config2 = this.config; - const result = { - signingKeyId, - get signingContractID() { - return getContractIDfromKeyId(contractID, signingKeyId, state); - }, - get innerSigningKeyId() { - if (innerSigningKeyId === null) { - const value = message.message(); - const data = config2.unwrapMaybeEncryptedData(value); - if (data?.data && isSignedData(data.data)) { - innerSigningKeyId = data.data.signingKeyId; + dispose(v2, k, reason) { + } + set(k, v2, { + ttl = this.ttl, + start, + noDisposeOnSet = this.noDisposeOnSet, + size = 0, + sizeCalculation = this.sizeCalculation, + noUpdateTTL = this.noUpdateTTL + } = {}) { + size = this.requireSize(k, v2, size, sizeCalculation); + if (this.maxEntrySize && size > this.maxEntrySize) { + return this; + } + let index = this.size === 0 ? void 0 : this.keyMap.get(k); + if (index === void 0) { + index = this.newIndex(); + this.keyList[index] = k; + this.valList[index] = v2; + this.keyMap.set(k, index); + this.next[this.tail] = index; + this.prev[index] = this.tail; + this.tail = index; + this.size++; + this.addItemSize(index, size); + noUpdateTTL = false; + } else { + const oldVal = this.valList[index]; + if (v2 !== oldVal) { + if (this.isBackgroundFetch(oldVal)) { + oldVal.__abortController.abort(); } else { - innerSigningKeyId = void 0; + if (!noDisposeOnSet) { + this.dispose(oldVal, k, "set"); + if (this.disposeAfter) { + this.disposed.push([oldVal, k, "set"]); + } + } } - return innerSigningKeyId; + this.removeItemSize(index); + this.valList[index] = v2; + this.addItemSize(index, size); } - }, - get innerSigningContractID() { - return getContractIDfromKeyId(contractID, result.innerSigningKeyId, state); - }, - index - }; - return result; - }; - keysToMap = function(keys_, height, authorizedKeys) { - const keys = keys_.map((key) => { - const data = this.config.unwrapMaybeEncryptedData(key); - if (!data) - return void 0; - if (data.encryptionKeyId) { - data.data._private = data.encryptionKeyId; - } - return data.data; - }).filter(Boolean); - const keysCopy = cloneDeep(keys); - return Object.fromEntries(keysCopy.map((key) => { - key._notBeforeHeight = height; - if (authorizedKeys?.[key.id]) { - if (authorizedKeys[key.id]._notAfterHeight == null) { - throw new ChelErrorKeyAlreadyExists(`Cannot set existing unrevoked key: ${key.id}`); - } - key._notBeforeHeight = Math.min(height, authorizedKeys[key.id]._notBeforeHeight ?? 0); - } else { - key._notBeforeHeight = height; + this.moveToTail(index); } - delete key._notAfterHeight; - return [key.id, key]; - })); - }; - keyRotationHelper = (contractID, state, config2, updatedKeysMap, requiredPermissions, outputSelector, outputMapper, internalSideEffectStack) => { - if (!internalSideEffectStack || !Array.isArray(state._volatile?.watch)) - return; - const rootState = esm_default(config2.stateSelector); - const watchMap = /* @__PURE__ */ Object.create(null); - state._volatile.watch.forEach(([name, cID]) => { - if (!updatedKeysMap[name] || watchMap[cID] === null) { - return; + if (ttl !== 0 && this.ttl === 0 && !this.ttls) { + this.initializeTTLTracking(); } - if (!watchMap[cID]) { - if (!rootState.contracts[cID]?.type || !findSuitableSecretKeyId(rootState[cID], [SPMessage.OP_KEY_UPDATE], ["sig"])) { - watchMap[cID] = null; - return; - } - watchMap[cID] = []; + if (!noUpdateTTL) { + this.setItemTTL(index, ttl, start); } - watchMap[cID].push(name); - }); - Object.entries(watchMap).forEach(([cID, names]) => { - if (!Array.isArray(names) || !names.length) - return; - const [keyNamesToUpdate, signingKeyId] = names.map((name) => { - const foreignContractKey = rootState[cID]?._vm?.authorizedKeys?.[updatedKeysMap[name].oldKeyId]; - if (!foreignContractKey) - return void 0; - const signingKeyId2 = findSuitableSecretKeyId(rootState[cID], requiredPermissions, ["sig"], foreignContractKey.ringLevel); - if (signingKeyId2) { - return [ - [name, foreignContractKey.name], - signingKeyId2, - rootState[cID]._vm.authorizedKeys[signingKeyId2].ringLevel - ]; + if (this.disposeAfter) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()); } - return void 0; - }).filter(Boolean).reduce((acc, [name, signingKeyId2, ringLevel]) => { - acc[0].push(name); - return ringLevel < acc[2] ? [acc[0], signingKeyId2, ringLevel] : acc; - }, [[], void 0, Number.POSITIVE_INFINITY]); - if (!signingKeyId) - return; - const contractName = rootState.contracts[cID]?.type; - internalSideEffectStack?.push(() => { - esm_default(outputSelector, { - contractID: cID, - contractName, - data: keyNamesToUpdate.map(outputMapper).map((v2) => { - return v2; - }), - signingKeyId - }).catch((e2) => { - console.warn(`Error mirroring key operation (${outputSelector}) from ${contractID} to ${cID}: ${e2?.message || e2}`); - }); - }); - }); - }; - internals_default = esm_default("sbp/selectors/register", { - // DO NOT CALL ANY OF THESE YOURSELF! - "chelonia/private/state": function() { - return this.state; - }, - "chelonia/private/invoke": function(instance, invocation) { - if (this._instance !== instance) { - console.info("['chelonia/private/invoke] Not proceeding with invocation as Chelonia was restarted", { invocation }); - return; } - if (Array.isArray(invocation)) { - return esm_default(...invocation); - } else if (typeof invocation === "function") { - return invocation(); - } else { - throw new TypeError(`[chelonia/private/invoke] Expected invocation to be an array or a function. Saw ${typeof invocation} instead.`); - } - }, - "chelonia/private/queueEvent": function(queueName, invocation) { - return esm_default("okTurtles.eventQueue/queueEvent", queueName, [ - "chelonia/private/invoke", - this._instance, - invocation - ]); - }, - "chelonia/private/verifyManifestSignature": function(contractName, manifestHash, manifest2) { - if (!has(manifest2, "signature") || typeof manifest2.signature.keyId !== "string" || typeof manifest2.signature.value !== "string") { - throw new Error(`Invalid or missing signature field for manifest ${manifestHash} (named ${contractName})`); + return this; + } + newIndex() { + if (this.size === 0) { + return this.tail; } - const rootState = esm_default(this.config.stateSelector); - if (!has(rootState, "contractSigningKeys")) { - this.config.reactiveSet(rootState, "contractSigningKeys", /* @__PURE__ */ Object.create(null)); - } - const contractNameLookupKey = `name:${contractName}`; - let signatureValidated = false; - if (process.env.UNSAFE_TRUST_ALL_MANIFEST_SIGNING_KEYS !== "true" && has(rootState.contractSigningKeys, contractNameLookupKey)) { - console.info(`[chelonia] verifying signature for ${manifestHash} with an existing key`); - if (!has(rootState.contractSigningKeys[contractNameLookupKey], manifest2.signature.keyId)) { - console.error(`The manifest with ${manifestHash} (named ${contractName}) claims to be signed with a key with ID ${manifest2.signature.keyId}, which is not trusted. The trusted key IDs for this name are:`, Object.keys(rootState.contractSigningKeys[contractNameLookupKey])); - throw new Error(`Invalid or missing signature in manifest ${manifestHash} (named ${contractName}). It claims to be signed with a key with ID ${manifest2.signature.keyId}, which has not been authorized for this contract before.`); - } - const signingKey = rootState.contractSigningKeys[contractNameLookupKey][manifest2.signature.keyId]; - verifySignature(signingKey, manifest2.body + manifest2.head, manifest2.signature.value); - console.info(`[chelonia] successful signature verification for ${manifestHash} (named ${contractName}) using the already-trusted key ${manifest2.signature.keyId}.`); - signatureValidated = true; - } - const body = JSON.parse(manifest2.body); - if (!signatureValidated) { - console.info(`[chelonia] verifying signature for ${manifestHash} (named ${contractName}) for the first time`); - if (!has(body, "signingKeys") || !Array.isArray(body.signingKeys)) { - throw new Error(`Invalid manifest file ${manifestHash} (named ${contractName}). Its body doesn't contain a 'signingKeys' list'`); - } - let contractSigningKeys; - try { - contractSigningKeys = Object.fromEntries(body.signingKeys.map((serializedKey) => { - return [keyId(serializedKey), serializedKey]; - })); - } catch (e2) { - console.error(`[chelonia] Error parsing the public keys list for ${manifestHash} (named ${contractName})`, e2); - throw e2; - } - if (!has(contractSigningKeys, manifest2.signature.keyId)) { - throw new Error(`Invalid or missing signature in manifest ${manifestHash} (named ${contractName}). It claims to be signed with a key with ID ${manifest2.signature.keyId}, which is not listed in its 'signingKeys' field.`); - } - verifySignature(contractSigningKeys[manifest2.signature.keyId], manifest2.body + manifest2.head, manifest2.signature.value); - console.info(`[chelonia] successful signature verification for ${manifestHash} (named ${contractName}) using ${manifest2.signature.keyId}. The following key IDs will now be trusted for this contract name`, Object.keys(contractSigningKeys)); - signatureValidated = true; - rootState.contractSigningKeys[contractNameLookupKey] = contractSigningKeys; + if (this.size === this.max && this.max !== 0) { + return this.evict(false); } - return body; - }, - "chelonia/private/loadManifest": async function(contractName, manifestHash) { - if (!contractName || typeof contractName !== "string") { - throw new Error("Invalid or missing contract name"); + if (this.free.length !== 0) { + return this.free.pop(); } - if (this.manifestToContract[manifestHash]) { - console.warn("[chelonia]: already loaded manifest", manifestHash); - return; + return this.initialFill++; + } + pop() { + if (this.size) { + const val = this.valList[this.head]; + this.evict(true); + return val; } - const manifestSource = await esm_default("chelonia/out/fetchResource", manifestHash, { - code: multicodes.SHELTER_CONTRACT_MANIFEST - }); - const manifest2 = JSON.parse(manifestSource); - const body = esm_default("chelonia/private/verifyManifestSignature", contractName, manifestHash, manifest2); - if (body.name !== contractName) { - throw new Error(`Mismatched contract name. Expected ${contractName} but got ${body.name}`); - } - const contractInfo = this.config.contracts.defaults.preferSlim && body.contractSlim || body.contract; - console.info(`[chelonia] loading contract '${contractInfo.file}'@'${body.version}' from manifest: ${manifestHash}`); - const source = await esm_default("chelonia/out/fetchResource", contractInfo.hash, { - code: multicodes.SHELTER_CONTRACT_TEXT - }); - const reduceAllow = (acc, v2) => { - acc[v2] = true; - return acc; - }; - const allowedSels = [ - "okTurtles.events/on", - "chelonia/defineContract", - "chelonia/out/keyRequest" - ].concat(this.config.contracts.defaults.allowedSelectors).reduce(reduceAllow, {}); - const allowedDoms = this.config.contracts.defaults.allowedDomains.reduce(reduceAllow, {}); - const contractSBP = (selector, ...args) => { - const domain = domainFromSelector(selector); - if (selector.startsWith(contractName + "/")) { - selector = `${manifestHash}/${selector}`; - } - if (allowedSels[selector] || allowedDoms[domain]) { - return esm_default(selector, ...args); - } else { - console.error("[chelonia] selector not on allowlist", { - selector, - allowedSels, - allowedDoms - }); - throw new Error(`[chelonia] selector not on allowlist: '${selector}'`); + } + evict(free) { + const head = this.head; + const k = this.keyList[head]; + const v2 = this.valList[head]; + if (this.isBackgroundFetch(v2)) { + v2.__abortController.abort(); + } else { + this.dispose(v2, k, "evict"); + if (this.disposeAfter) { + this.disposed.push([v2, k, "evict"]); } - }; - const saferEval = new Function(` - return function (globals) { - // almost a real sandbox - // stops (() => this)().fetch - // needs additional step of locking down Function constructor to stop: - // new (()=>{}).constructor("console.log(typeof this.fetch)")() - globals.self = globals - globals.globalThis = globals - with (new Proxy(globals, { - get (o, p) { return o[p] }, - has (o, p) { /* console.log('has', p); */ return true } - })) { - (function () { - 'use strict' - ${source} - })() } + this.removeItemSize(head); + if (free) { + this.keyList[head] = null; + this.valList[head] = null; + this.free.push(head); + } + this.head = this.next[head]; + this.keyMap.delete(k); + this.size--; + return head; } - `)(); - this.defContractSBP = contractSBP; - this.defContractManifest = manifestHash; - saferEval({ - // pass in globals that we want access to by default in the sandbox - // note: you can undefine these by setting them to undefined in exposedGlobals - crypto: { - getRandomValues: (v2) => globalThis.crypto.getRandomValues(v2) - }, - ...typeof window === "object" && window && { - alert: window.alert.bind(window), - confirm: window.confirm.bind(window), - prompt: window.prompt.bind(window) - }, - isNaN, - console, - Object, - Error, - TypeError, - RangeError, - Math, - Symbol, - Date, - Array, - BigInt, - Boolean, - String, - Number, - Int8Array, - Int16Array, - Int32Array, - Uint8Array, - Uint16Array, - Uint32Array, - Float32Array, - Float64Array, - ArrayBuffer, - JSON, - RegExp, - parseFloat, - parseInt, - Promise, - Function, - Map, - WeakMap, - ...this.config.contracts.defaults.exposedGlobals, - require: (dep) => { - return dep === "@sbp/sbp" ? contractSBP : this.config.contracts.defaults.modules[dep]; - }, - sbp: contractSBP, - fetchServerTime: async (fallback = true) => { - try { - const response = await this.config.fetch(`${this.config.connectionURL}/time`, { - signal: this.abortController.signal - }); - return handleFetchResult("text")(response); - } catch (e2) { - console.warn("[fetchServerTime] Error", e2); - if (fallback) { - return new Date(esm_default("chelonia/time")).toISOString(); - } - throw new ChelErrorFetchServerTimeFailed("Can not fetch server time. Please check your internet connection."); + has(k, { updateAgeOnHas = this.updateAgeOnHas } = {}) { + const index = this.keyMap.get(k); + if (index !== void 0) { + if (!this.isStale(index)) { + if (updateAgeOnHas) { + this.updateItemAge(index); } + return true; } - }); - if (contractName !== this.defContract.name) { - throw new Error(`Invalid contract name for manifest ${manifestHash}. Expected ${contractName} but got ${this.defContract.name}`); } - this.defContractSelectors.forEach((s) => { - allowedSels[s] = true; - }); - this.manifestToContract[manifestHash] = { - slim: contractInfo === body.contractSlim, - info: contractInfo, - contract: this.defContract - }; - }, - // Warning: avoid using this unless you know what you're doing. Prefer using /remove. - "chelonia/private/removeImmediately": function(contractID, params) { - const state = esm_default(this.config.stateSelector); - const contractName = state.contracts[contractID]?.type; - if (!contractName) { - console.error("[chelonia/private/removeImmediately] Missing contract name for contract", { - contractID - }); - return; + return false; + } + // like get(), but without any LRU updating or TTL expiration + peek(k, { allowStale = this.allowStale } = {}) { + const index = this.keyMap.get(k); + if (index !== void 0 && (allowStale || !this.isStale(index))) { + const v2 = this.valList[index]; + return this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; } - const manifestHash = this.config.contracts.manifests[contractName]; - if (manifestHash) { - const destructor = `${manifestHash}/${contractName}/_cleanup`; - if (esm_default("sbp/selectors/fn", destructor)) { - try { - esm_default(destructor, { contractID, resync: !!params?.resync, state: state[contractID] }); - } catch (e2) { - console.error(`[chelonia/private/removeImmediately] Error at destructor for ${contractID}`, e2); + } + backgroundFetch(k, index, options2, context) { + const v2 = index === void 0 ? void 0 : this.valList[index]; + if (this.isBackgroundFetch(v2)) { + return v2; + } + const ac = new AC(); + const fetchOpts = { + signal: ac.signal, + options: options2, + context + }; + const cb = (v3) => { + if (!ac.signal.aborted) { + this.set(k, v3, fetchOpts.options); + } + return v3; + }; + const eb = (er) => { + if (this.valList[index] === p) { + const del = !options2.noDeleteOnFetchRejection || p.__staleWhileFetching === void 0; + if (del) { + this.delete(k); + } else { + this.valList[index] = p.__staleWhileFetching; } } - } - if (params?.resync) { - Object.keys(state.contracts[contractID]).filter((k) => k !== "references").forEach((k) => this.config.reactiveDel(state.contracts[contractID], k)); - Object.keys(state[contractID]).filter((k) => k !== "_volatile").forEach((k) => this.config.reactiveDel(state[contractID], k)); - if (state[contractID]._volatile) { - Object.keys(state[contractID]._volatile).filter((k) => k !== "watch").forEach((k) => this.config.reactiveDel(state[contractID]._volatile, k)); + if (p.__returned === p) { + throw er; } + }; + const pcall = (res) => res(this.fetchMethod(k, v2, fetchOpts)); + const p = new Promise(pcall).then(cb, eb); + p.__abortController = ac; + p.__staleWhileFetching = v2; + p.__returned = null; + if (index === void 0) { + this.set(k, p, fetchOpts.options); + index = this.keyMap.get(k); } else { - delete this.ephemeralReferenceCount[contractID]; - if (params?.permanent) { - this.config.reactiveSet(state.contracts, contractID, null); - } else { - this.config.reactiveDel(state.contracts, contractID); - } - this.config.reactiveDel(state, contractID); + this.valList[index] = p; } - this.subscriptionSet.delete(contractID); - esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { - added: [], - removed: [contractID], - permanent: params?.permanent, - resync: params?.resync - }); - }, - // used by, e.g. 'chelonia/contract/wait' - "chelonia/private/noop": function() { - }, - "chelonia/private/out/sync": function(contractIDs, params) { - const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; - const forcedSync = !!params?.force; - return Promise.all(listOfIds.map((contractID) => { - if (!forcedSync && this.subscriptionSet.has(contractID)) { - const rootState = esm_default(this.config.stateSelector); - if (!rootState[contractID]?._volatile?.dirty) { - return esm_default("chelonia/private/queueEvent", contractID, ["chelonia/private/noop"]); - } - } - return esm_default("chelonia/private/queueEvent", contractID, [ - "chelonia/private/in/syncContract", - contractID, - params - ]).catch((err) => { - console.error(`[chelonia] failed to sync ${contractID}:`, err); - throw err; - }); - })); - }, - "chelonia/private/out/publishEvent": function(entry, { maxAttempts = 5, headers, billableContractID, bearer, disableAutoDedup } = {}, hooks) { - const contractID = entry.contractID(); - const originalEntry = entry; - return esm_default("chelonia/private/queueEvent", `publish:${contractID}`, async () => { - let attempt = 1; - let lastAttemptedHeight; - await hooks?.prepublish?.(entry); - const onreceivedHandler = (_contractID, message) => { - if (entry.hash() === message.hash()) { - esm_default("okTurtles.events/off", EVENT_HANDLED, onreceivedHandler); - hooks.onprocessed(entry); - } - }; - if (typeof hooks?.onprocessed === "function") { - esm_default("okTurtles.events/on", EVENT_HANDLED, onreceivedHandler); - } - while (true) { - lastAttemptedHeight = entry.height(); - const newEntry = await esm_default("chelonia/private/queueEvent", contractID, async () => { - const rootState = esm_default(this.config.stateSelector); - const state = rootState[contractID]; - const isFirstMessage = entry.isFirstMessage(); - if (!state && !isFirstMessage) { - console.info(`[chelonia] Not sending message as contract state has been removed: ${entry.description()}`); - return; - } - if (hooks?.preSendCheck) { - if (!await hooks.preSendCheck(entry, state)) { - console.info(`[chelonia] Not sending message as preSendCheck hook returned non-truish value: ${entry.description()}`); - return; - } - } - await esm_default("chelonia/private/in/processMessage", entry, cloneDeep(state || {})); - if (!isFirstMessage) { - return recreateEvent(entry, state, rootState.contracts[contractID], disableAutoDedup); - } - return entry; - }); - if (!newEntry) - return; - await hooks?.beforeRequest?.(newEntry, entry); - entry = newEntry; - const r = await this.config.fetch(`${this.config.connectionURL}/event`, { - method: "POST", - body: entry.serialize(), - headers: { - ...headers, - ...bearer && { - Authorization: `Bearer ${bearer}` - }, - ...billableContractID && { - Authorization: buildShelterAuthorizationHeader.call(this, billableContractID) - }, - "Content-Type": "text/plain" - }, - signal: this.abortController.signal - }); - if (r.ok) { - await hooks?.postpublish?.(entry); - return entry; - } - try { - if (r.status === 409) { - if (attempt + 1 > maxAttempts) { - console.error(`[chelonia] failed to publish ${entry.description()} after ${attempt} attempts`, entry); - throw new Error(`publishEvent: ${r.status} - ${r.statusText}. attempt ${attempt}`); - } - const randDelay = randomIntFromRange(0, 1500); - console.warn(`[chelonia] publish attempt ${attempt} of ${maxAttempts} failed. Waiting ${randDelay} msec before resending ${entry.description()}`); - attempt += 1; - await delay(randDelay); - if (!entry.isFirstMessage() && entry.height() === lastAttemptedHeight) { - await esm_default("chelonia/private/out/sync", contractID, { force: true }); - } - } else { - const message = (await r.json())?.message; - console.error(`[chelonia] ERROR: failed to publish ${entry.description()}: ${r.status} - ${r.statusText}: ${message}`, entry); - throw new Error(`publishEvent: ${r.status} - ${r.statusText}: ${message}`); - } - } catch (e2) { - esm_default("okTurtles.events/off", EVENT_HANDLED, onreceivedHandler); - throw e2; - } - } - }).then((entry2) => { - esm_default("okTurtles.events/emit", EVENT_PUBLISHED, { - contractID, - message: entry2, - originalMessage: originalEntry - }); - return entry2; - }).catch((e2) => { - esm_default("okTurtles.events/emit", EVENT_PUBLISHING_ERROR, { - contractID, - message: entry, - originalMessage: originalEntry, - error: e2 + return p; + } + isBackgroundFetch(p) { + return p && typeof p === "object" && typeof p.then === "function" && Object.prototype.hasOwnProperty.call( + p, + "__staleWhileFetching" + ) && Object.prototype.hasOwnProperty.call(p, "__returned") && (p.__returned === p || p.__returned === null); + } + // this takes the union of get() and set() opts, because it does both + async fetch(k, { + // get options + allowStale = this.allowStale, + updateAgeOnGet = this.updateAgeOnGet, + noDeleteOnStaleGet = this.noDeleteOnStaleGet, + // set options + ttl = this.ttl, + noDisposeOnSet = this.noDisposeOnSet, + size = 0, + sizeCalculation = this.sizeCalculation, + noUpdateTTL = this.noUpdateTTL, + // fetch exclusive options + noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, + fetchContext = this.fetchContext, + forceRefresh = false + } = {}) { + if (!this.fetchMethod) { + return this.get(k, { + allowStale, + updateAgeOnGet, + noDeleteOnStaleGet }); - throw e2; - }); - }, - "chelonia/private/out/latestHEADinfo": function(contractID) { - return this.config.fetch(`${this.config.connectionURL}/latestHEADinfo/${contractID}`, { - cache: "no-store", - signal: this.abortController.signal - }).then(handleFetchResult("json")); - }, - "chelonia/private/postKeyShare": function(contractID, previousVolatileState, signingKey) { - const cheloniaState = esm_default(this.config.stateSelector); - const targetState = cheloniaState[contractID]; - if (!targetState) - return; - if (previousVolatileState && has(previousVolatileState, "watch")) { - if (!targetState._volatile) { - this.config.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); - } - if (!targetState._volatile.watch) { - this.config.reactiveSet(targetState._volatile, "watch", previousVolatileState.watch); - } else if (targetState._volatile.watch !== previousVolatileState.watch) { - previousVolatileState.watch.forEach((pWatch) => { - if (!targetState._volatile.watch.some((tWatch) => { - return tWatch[0] === pWatch[0] && tWatch[1] === pWatch[1]; - })) { - targetState._volatile.watch.push(pWatch); - } - }); - } - } - if (!Array.isArray(targetState._volatile?.pendingKeyRequests)) - return; - this.config.reactiveSet(targetState._volatile, "pendingKeyRequests", targetState._volatile.pendingKeyRequests.filter((pkr) => pkr?.name !== signingKey.name)); - }, - "chelonia/private/in/processMessage": async function(message, state, internalSideEffectStack, contractName) { - const [opT, opV] = message.op(); - const hash3 = message.hash(); - const height = message.height(); - const contractID = message.contractID(); - const manifestHash = message.manifest(); - const signingKeyId = message.signingKeyId(); - const direction = message.direction(); - const config2 = this.config; - const self2 = this; - const opName = Object.entries(SPMessage).find(([, y]) => y === opT)?.[0]; - console.debug("PROCESSING OPCODE:", opName, "to", contractID); - if (state?._volatile?.dirty) { - console.debug("IGNORING OPCODE BECAUSE CONTRACT STATE IS MARKED AS DIRTY.", "OPCODE:", opName, "CONTRACT:", contractID); - return; } - if (!state._vm) - state._vm = /* @__PURE__ */ Object.create(null); - const opFns = { - /* - There are two types of "errors" that we need to consider: - 1. "Ignoring" errors - 2. "Failure" errors - Example: OP_KEY_ADD - 1. IGNORING: an error is thrown because we wanted to add a key but the - key we wanted to add is already there. This is not a hard error, it's an - ignoring error. We don't care that the operation failed in this case because the intent was accomplished. - 2. FAILURE: an error is thrown while attempting to add a key that doesn't exist. - Example: OP_ACTION_ENCRYPTED - 1. IGNORING: An error is thrown because we don't have the key to decrypt the action. We ignore it. - 2. FAILURE: An error is thrown by the process function during processing. - Handling these in OP_ATOMIC - • ALL errors of class "IGNORING" should be ignored. They should not - impact our ability to process the rest of the operations in the OP_ATOMIC. - No matter how many of these are thrown, it doesn't affect the rest of the operations. - • ANY error of class "FAILURE" will call the rest of the operations to - fail and the state to be reverted to prior to the OP_ATOMIC. No side-effects should be run. Because an intention failed. - */ - async [SPMessage.OP_ATOMIC](v2) { - for (let i2 = 0; i2 < v2.length; i2++) { - const u2 = v2[i2]; - try { - if (u2[0] === SPMessage.OP_ATOMIC) - throw new Error("Cannot nest OP_ATOMIC"); - if (!validateKeyPermissions(message, config2, state, signingKeyId, u2[0], u2[1])) { - throw new Error("Inside OP_ATOMIC: no matching signing key was defined"); - } - await opFns[u2[0]](u2[1]); - } catch (e_) { - const e2 = e_; - if (e2 && typeof e2 === "object") { - if (e2.name === "ChelErrorDecryptionKeyNotFound") { - console.warn(`[chelonia] [OP_ATOMIC] WARN '${e2.name}' in processMessage for ${message.description()}: ${e2.message}`, e2, message.serialize()); - if (e2.cause) { - const missingDecryptionKeyIds = missingDecryptionKeyIdsMap.get(message); - if (missingDecryptionKeyIds) { - missingDecryptionKeyIds.add(e2.cause); - } else { - missingDecryptionKeyIdsMap.set(message, /* @__PURE__ */ new Set([e2.cause])); - } - } - continue; - } else { - logEvtError(message, `[chelonia] [OP_ATOMIC] ERROR '${e2.name}' in processMessage for ${message.description()}: ${e2.message || e2}`, e2, message.serialize()); - } - console.warn(`[chelonia] [OP_ATOMIC] Error processing ${message.description()}: ${message.serialize()}. Any side effects will be skipped!`); - if (config2.strictProcessing) { - throw e2; - } - config2.hooks.processError?.(e2, message, getMsgMeta.call(self2, message, contractID, state)); - if (e2.name === "ChelErrorWarning") - continue; - } else { - logEvtError(message, "Inside OP_ATOMIC: Non-object or null error thrown", contractID, message, i2, e2); - } - throw e2; - } - } - }, - [SPMessage.OP_CONTRACT](v2) { - state._vm.type = v2.type; - const keys = keysToMap.call(self2, v2.keys, height); - state._vm.authorizedKeys = keys; - keyAdditionProcessor.call(self2, message, hash3, v2.keys, state, contractID, signingKey, internalSideEffectStack); - }, - [SPMessage.OP_ACTION_ENCRYPTED](v2) { - if (config2.skipActionProcessing) { - if (!config2.skipDecryptionAttempts) { - console.log("OP_ACTION_ENCRYPTED: skipped action processing"); - } - return; - } - return opFns[SPMessage.OP_ACTION_UNENCRYPTED](v2.valueOf()); - }, - async [SPMessage.OP_ACTION_UNENCRYPTED](v2) { - if (!config2.skipActionProcessing) { - let innerSigningKeyId; - if (isSignedData(v2)) { - innerSigningKeyId = v2.signingKeyId; - v2 = v2.valueOf(); - } - const { data, meta, action } = v2; - if (!config2.whitelisted(action)) { - throw new Error(`chelonia: action not whitelisted: '${action}'`); - } - await esm_default(`${manifestHash}/${action}/process`, { - data, - meta, - hash: hash3, - height, - contractID, - direction: message.direction(), - signingKeyId, - get signingContractID() { - return getContractIDfromKeyId(contractID, signingKeyId, state); - }, - innerSigningKeyId, - get innerSigningContractID() { - return getContractIDfromKeyId(contractID, innerSigningKeyId, state); - } - }, state); - } - }, - [SPMessage.OP_KEY_SHARE](wv) { - const data = config2.unwrapMaybeEncryptedData(wv); - if (!data) - return; - const v2 = data.data; - for (const key of v2.keys) { - if (key.id && key.meta?.private?.content) { - if (!has(state._vm, "sharedKeyIds")) - state._vm.sharedKeyIds = []; - if (!state._vm.sharedKeyIds.some((sK) => sK.id === key.id)) { - state._vm.sharedKeyIds.push({ - id: key.id, - contractID: v2.contractID, - height, - keyRequestHash: v2.keyRequestHash, - keyRequestHeight: v2.keyRequestHeight - }); - } - } - } - if (has(v2, "keyRequestHash") && state._vm.authorizedKeys[signingKeyId].meta?.keyRequest) { - state._vm.authorizedKeys[signingKeyId].meta.keyRequest.responded = hash3; - } - internalSideEffectStack?.push(async () => { - delete self2.postSyncOperations[contractID]?.["pending-keys-for-" + v2.contractID]; - const cheloniaState = esm_default(self2.config.stateSelector); - const targetState = cheloniaState[v2.contractID]; - const missingDecryptionKeyIds = cheloniaState.contracts[v2.contractID]?.missingDecryptionKeyIds; - let newestEncryptionKeyHeight = Number.POSITIVE_INFINITY; - for (const key of v2.keys) { - if (key.id && key.meta?.private?.content) { - const transient = direction === "outgoing" || key.meta.private.transient; - if (!esm_default("chelonia/haveSecretKey", key.id, !transient)) { - try { - const decrypted = key.meta.private.content.valueOf(); - esm_default("chelonia/storeSecretKeys", new Secret([ - { - key: deserializeKey(decrypted), - transient - } - ])); - if (missingDecryptionKeyIds?.includes(key.id)) { - newestEncryptionKeyHeight = Number.NEGATIVE_INFINITY; - } else if ( - // Otherwise, we make an educated guess on whether a re-sync - // is needed based on the height. - targetState?._vm?.authorizedKeys?.[key.id]?._notBeforeHeight != null && Array.isArray(targetState._vm.authorizedKeys[key.id].purpose) && targetState._vm.authorizedKeys[key.id].purpose.includes("enc") - ) { - newestEncryptionKeyHeight = Math.min(newestEncryptionKeyHeight, targetState._vm.authorizedKeys[key.id]._notBeforeHeight); - } - } catch (e_) { - const e2 = e_; - if (e2?.name === "ChelErrorDecryptionKeyNotFound") { - console.warn(`OP_KEY_SHARE (${hash3} of ${contractID}) missing secret key: ${e2.message}`, e2); - } else { - console.error(`OP_KEY_SHARE (${hash3} of ${contractID}) error '${e2.message || e2}':`, e2); - } - } - } - } - } - const mustResync = !!(newestEncryptionKeyHeight < cheloniaState.contracts[v2.contractID]?.height); - if (mustResync) { - if (!has(targetState, "_volatile")) { - config2.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); - } - config2.reactiveSet(targetState._volatile, "dirty", true); - if (!Object.keys(targetState).some((k) => k !== "_volatile")) { - return; - } - const keyDict = /* @__PURE__ */ Object.create(null); - targetState._volatile?.watch?.forEach(([keyName, contractID2]) => { - if (!keyDict[keyName]) { - keyDict[keyName] = [contractID2]; - return; - } - keyDict[keyName].push(contractID2); - }); - const contractIdsToUpdate = Array.from(new Set(Object.entries(keyDict).flatMap(([keyName, contractIDs]) => { - const keyId2 = findKeyIdByName(targetState, keyName); - if ( - // Does the key exist? (i.e., is it a current key) - keyId2 && // Is it an encryption key? (signing keys don't build up a - // potentially invalid state because the private key isn't - // required for validation; however, missing encryption keys - // prevent message processing) - targetState._vm.authorizedKeys[keyId2].purpose.includes("enc") && // Is this a newly set key? (avoid re-syncing contracts that - // haven't been affected by the `OP_KEY_SHARE`) - targetState._vm.authorizedKeys[keyId2]._notBeforeHeight >= newestEncryptionKeyHeight - ) { - return contractIDs; - } - return []; - }))); - contractIdsToUpdate.forEach((contractID2) => { - const targetState2 = cheloniaState[contractID2]; - if (!targetState2) - return; - if (!has(targetState2, "_volatile")) { - config2.reactiveSet(targetState2, "_volatile", /* @__PURE__ */ Object.create(null)); - } - config2.reactiveSet(targetState2._volatile, "dirty", true); - }); - if (self2.subscriptionSet.has(v2.contractID)) { - const resync = esm_default("chelonia/private/queueEvent", v2.contractID, [ - "chelonia/private/in/syncContract", - v2.contractID - ]).then(() => { - esm_default("chelonia/private/out/sync", contractIdsToUpdate.filter((contractID2) => { - return self2.subscriptionSet.has(contractID2); - }), { force: true, resync: true }).catch((e2) => { - console.error("[chelonia] Error resyncing contracts with foreign key references after key rotation", e2); - }); - }).catch((e2) => { - console.error(`[chelonia] Error during sync for ${v2.contractID} during OP_KEY_SHARE for ${contractID}`); - if (v2.contractID === contractID) { - throw e2; - } - }); - if (v2.contractID !== contractID) { - await resync; - } - } - } - const previousVolatileState = targetState?._volatile; - esm_default("chelonia/private/queueEvent", v2.contractID, [ - "chelonia/private/postKeyShare", - v2.contractID, - mustResync ? previousVolatileState : null, - signingKey - ]).then(() => { - esm_default("chelonia/private/queueEvent", contractID, () => { - esm_default("okTurtles.events/emit", CONTRACT_HAS_RECEIVED_KEYS, { - contractID: v2.contractID, - sharedWithContractID: contractID, - signingKeyId, - get signingKeyName() { - return state._vm?.authorizedKeys?.[signingKeyId]?.name; - } - }); - }).catch((e2) => { - console.error(`[chelonia] Error while emitting the CONTRACT_HAS_RECEIVED_KEYS event for ${contractID}`, e2); - }); - }); - }); - }, - [SPMessage.OP_KEY_REQUEST](wv) { - const data = config2.unwrapMaybeEncryptedData(wv); - const v2 = data?.data || { - contractID: "(private)", - replyWith: { context: void 0 }, - request: "*" - }; - const originatingContractID = v2.contractID; - if (state._vm?.invites?.[signingKeyId]?.quantity != null) { - if (state._vm.invites[signingKeyId].quantity > 0) { - if (--state._vm.invites[signingKeyId].quantity <= 0) { - state._vm.invites[signingKeyId].status = INVITE_STATUS.USED; - } - } else { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it exceeds allowed quantity: " + originatingContractID); - return; - } - } - if (state._vm?.invites?.[signingKeyId]?.expires != null) { - if (state._vm.invites[signingKeyId].expires < Date.now()) { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it expired at " + state._vm.invites[signingKeyId].expires + ": " + originatingContractID); - return; - } - } - if (config2.skipActionProcessing || direction === "outgoing") { - return; - } - if (!has(v2.replyWith, "context")) { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it is missing the context attribute"); - return; - } - const context = v2.replyWith.context; - if (data && (!Array.isArray(context) || context[0] !== originatingContractID)) { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it is signed by the wrong contract"); - return; - } - if (v2.request !== "*") { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it has an unsupported request attribute", v2.request); - return; - } - if (!state._vm.pendingKeyshares) - state._vm.pendingKeyshares = /* @__PURE__ */ Object.create(null); - state._vm.pendingKeyshares[message.hash()] = context ? [ - // Full-encryption (i.e., KRS encryption) requires that this request - // was encrypted and that the invite is marked as private - !!data?.encryptionKeyId, - message.height(), - signingKeyId, - context - ] : [!!data?.encryptionKeyId, message.height(), signingKeyId]; - if (data) { - internalSideEffectStack?.push(() => { - self2.setPostSyncOp(contractID, "respondToAllKeyRequests-" + message.contractID(), [ - "chelonia/private/respondToAllKeyRequests", - contractID - ]); - }); - } - }, - [SPMessage.OP_KEY_REQUEST_SEEN](wv) { - if (config2.skipActionProcessing) { - return; - } - const data = config2.unwrapMaybeEncryptedData(wv); - if (!data) - return; - const v2 = data.data; - if (state._vm.pendingKeyshares && v2.keyRequestHash in state._vm.pendingKeyshares) { - const hash4 = v2.keyRequestHash; - const pending = state._vm.pendingKeyshares[hash4]; - delete state._vm.pendingKeyshares[hash4]; - if (pending.length !== 4) - return; - const keyId2 = pending[2]; - const originatingContractID = pending[3][0]; - if (Array.isArray(state._vm?.invites?.[keyId2]?.responses)) { - state._vm?.invites?.[keyId2]?.responses.push(originatingContractID); - } - if (!has(state._vm, "keyshares")) - state._vm.keyshares = /* @__PURE__ */ Object.create(null); - const success = v2.success; - state._vm.keyshares[hash4] = { - contractID: originatingContractID, - height, - success, - ...success && { - hash: v2.keyShareHash - } - }; - } - }, - [SPMessage.OP_PROP_DEL]: notImplemented, - [SPMessage.OP_PROP_SET](v2) { - if (!state._vm.props) - state._vm.props = {}; - state._vm.props[v2.key] = v2.value; - }, - [SPMessage.OP_KEY_ADD](v2) { - const keys = keysToMap.call(self2, v2, height, state._vm.authorizedKeys); - const keysArray = Object.values(v2); - keysArray.forEach((k) => { - if (has(state._vm.authorizedKeys, k.id) && state._vm.authorizedKeys[k.id]._notAfterHeight == null) { - throw new ChelErrorWarning("Cannot use OP_KEY_ADD on existing keys. Key ID: " + k.id); - } - }); - validateKeyAddPermissions.call(self2, contractID, signingKey, state, v2); - state._vm.authorizedKeys = { ...state._vm.authorizedKeys, ...keys }; - keyAdditionProcessor.call(self2, message, hash3, v2, state, contractID, signingKey, internalSideEffectStack); - }, - [SPMessage.OP_KEY_DEL](v2) { - if (!state._vm.authorizedKeys) - state._vm.authorizedKeys = /* @__PURE__ */ Object.create(null); - if (!state._volatile) - state._volatile = /* @__PURE__ */ Object.create(null); - if (!state._volatile.pendingKeyRevocations) { - state._volatile.pendingKeyRevocations = /* @__PURE__ */ Object.create(null); - } - validateKeyDelPermissions.call(self2, contractID, signingKey, state, v2); - const keyIds = v2.map((k) => { - const data = config2.unwrapMaybeEncryptedData(k); - if (!data) - return void 0; - return data.data; - }).filter((keyId2) => { - if (!keyId2 || typeof keyId2 !== "string") - return false; - if (!has(state._vm.authorizedKeys, keyId2) || state._vm.authorizedKeys[keyId2]._notAfterHeight != null) { - console.warn("Attempted to delete non-existent key from contract", { - contractID, - keyId: keyId2 - }); - return false; - } - return true; - }); - keyIds.forEach((keyId2) => { - const key = state._vm.authorizedKeys[keyId2]; - state._vm.authorizedKeys[keyId2]._notAfterHeight = height; - if (has(state._volatile.pendingKeyRevocations, keyId2)) { - delete state._volatile.pendingKeyRevocations[keyId2]; - } - if (key.foreignKey) { - const fkUrl = new URL(key.foreignKey); - const foreignContract = fkUrl.pathname; - const foreignKeyName = fkUrl.searchParams.get("keyName"); - if (!foreignContract || !foreignKeyName) { - throw new Error("Invalid foreign key: missing contract or key name"); - } - internalSideEffectStack?.push(() => { - esm_default("chelonia/private/queueEvent", foreignContract, () => { - const rootState = esm_default(config2.stateSelector); - if (Array.isArray(rootState[foreignContract]?._volatile?.watch)) { - const oldWatch = rootState[foreignContract]._volatile.watch; - rootState[foreignContract]._volatile.watch = oldWatch.filter(([name, cID]) => name !== foreignKeyName || cID !== contractID); - if (oldWatch.length !== rootState[foreignContract]._volatile.watch.length) { - esm_default("chelonia/contract/release", foreignContract, { try: true }).catch((e2) => { - console.error(`[chelonia] Error at OP_KEY_DEL internalSideEffectStack while attempting to release foreign contract ${foreignContract}`, e2); - }); - } - } - }).catch((e2) => { - console.error("Error stopping watching events after removing key", { contractID, foreignContract, foreignKeyName, fkUrl }, e2); - }); - }); - const pendingWatch = state._vm.pendingWatch?.[foreignContract]; - if (pendingWatch) { - state._vm.pendingWatch[foreignContract] = pendingWatch.filter(([, kId]) => kId !== keyId2); - } - } - if (key.name.startsWith("#inviteKey-") && state._vm.invites[key.id]) { - state._vm.invites[key.id].status = INVITE_STATUS.REVOKED; - } - }); - if (Array.isArray(state._volatile?.watch)) { - const updatedKeysMap = /* @__PURE__ */ Object.create(null); - keyIds.forEach((keyId2) => { - updatedKeysMap[state._vm.authorizedKeys[keyId2].name] = { - name: state._vm.authorizedKeys[keyId2].name, - oldKeyId: keyId2 - }; - }); - keyRotationHelper(contractID, state, config2, updatedKeysMap, [SPMessage.OP_KEY_DEL], "chelonia/out/keyDel", (name) => updatedKeysMap[name[0]].oldKeyId, internalSideEffectStack); - } - }, - [SPMessage.OP_KEY_UPDATE](v2) { - if (!state._volatile) - state._volatile = /* @__PURE__ */ Object.create(null); - if (!state._volatile.pendingKeyRevocations) { - state._volatile.pendingKeyRevocations = /* @__PURE__ */ Object.create(null); - } - const [updatedKeys, updatedMap] = validateKeyUpdatePermissions.call(self2, contractID, signingKey, state, v2); - const keysToDelete = Object.values(updatedMap); - for (const keyId2 of keysToDelete) { - if (has(state._volatile.pendingKeyRevocations, keyId2)) { - delete state._volatile.pendingKeyRevocations[keyId2]; - } - state._vm.authorizedKeys[keyId2]._notAfterHeight = height; - } - for (const key of updatedKeys) { - if (!has(state._vm.authorizedKeys, key.id)) { - key._notBeforeHeight = height; - state._vm.authorizedKeys[key.id] = cloneDeep(key); - } - } - keyAdditionProcessor.call(self2, message, hash3, updatedKeys, state, contractID, signingKey, internalSideEffectStack); - if (Array.isArray(state._volatile?.watch)) { - const updatedKeysMap = /* @__PURE__ */ Object.create(null); - updatedKeys.forEach((key) => { - if (key.data) { - updatedKeysMap[key.name] = cloneDeep(key); - updatedKeysMap[key.name].oldKeyId = updatedMap[key.id]; - } - }); - keyRotationHelper(contractID, state, config2, updatedKeysMap, [SPMessage.OP_KEY_UPDATE], "chelonia/out/keyUpdate", (name) => ({ - name: name[1], - oldKeyId: updatedKeysMap[name[0]].oldKeyId, - id: updatedKeysMap[name[0]].id, - data: updatedKeysMap[name[0]].data - }), internalSideEffectStack); - } - }, - [SPMessage.OP_PROTOCOL_UPGRADE]: notImplemented + const options2 = { + allowStale, + updateAgeOnGet, + noDeleteOnStaleGet, + ttl, + noDisposeOnSet, + size, + sizeCalculation, + noUpdateTTL, + noDeleteOnFetchRejection }; - if (!this.config.skipActionProcessing && !this.manifestToContract[manifestHash]) { - const rootState = esm_default(this.config.stateSelector); - if (!contractName) { - contractName = has(rootState.contracts, contractID) && rootState.contracts[contractID] && has(rootState.contracts[contractID], "type") ? rootState.contracts[contractID].type : opT === SPMessage.OP_CONTRACT ? opV.type : ""; - } - if (!contractName) { - throw new Error(`Unable to determine the name for a contract and refusing to load it (contract ID was ${contractID} and its manifest hash was ${manifestHash})`); + let index = this.keyMap.get(k); + if (index === void 0) { + const p = this.backgroundFetch(k, index, options2, fetchContext); + return p.__returned = p; + } else { + const v2 = this.valList[index]; + if (this.isBackgroundFetch(v2)) { + return allowStale && v2.__staleWhileFetching !== void 0 ? v2.__staleWhileFetching : v2.__returned = v2; } - await esm_default("chelonia/private/loadManifest", contractName, manifestHash); - } - let processOp = true; - if (config2.preOp) { - processOp = config2.preOp(message, state) !== false && processOp; - } - let signingKey; - { - const stateForValidation = opT === SPMessage.OP_CONTRACT && !state?._vm?.authorizedKeys ? { - _vm: { - authorizedKeys: keysToMap.call(this, opV.keys, height) + if (!forceRefresh && !this.isStale(index)) { + this.moveToTail(index); + if (updateAgeOnGet) { + this.updateItemAge(index); } - } : state; - if (!validateKeyPermissions(message, config2, stateForValidation, signingKeyId, opT, opV)) { - throw new Error("No matching signing key was defined"); + return v2; } - signingKey = stateForValidation._vm.authorizedKeys[signingKeyId]; - } - if (config2[`preOp_${opT}`]) { - processOp = config2[`preOp_${opT}`](message, state) !== false && processOp; - } - if (processOp) { - await opFns[opT](opV); - config2.postOp?.(message, state); - config2[`postOp_${opT}`]?.(message, state); - } - }, - "chelonia/private/in/enqueueHandleEvent": function(contractID, event) { - return esm_default("chelonia/private/queueEvent", contractID, async () => { - await esm_default("chelonia/private/in/handleEvent", contractID, event); - esm_default("chelonia/private/enqueuePostSyncOps", contractID); - }); - }, - "chelonia/private/in/syncContract": async function(contractID, params) { - const state = esm_default(this.config.stateSelector); - if (state.contracts[contractID] === null) { - throw new ChelErrorResourceGone("Cannot sync permanently deleted contract " + contractID); + const p = this.backgroundFetch(k, index, options2, fetchContext); + return allowStale && p.__staleWhileFetching !== void 0 ? p.__staleWhileFetching : p.__returned = p; } - try { - this.currentSyncs[contractID] = { firstSync: !state.contracts[contractID]?.type }; - esm_default("okTurtles.events/emit", CONTRACT_IS_SYNCING, contractID, true); - const currentVolatileState = state[contractID]?._volatile || /* @__PURE__ */ Object.create(null); - if (currentVolatileState?.dirty || params?.resync) { - delete currentVolatileState.dirty; - currentVolatileState.resyncing = true; - esm_default("chelonia/private/removeImmediately", contractID, { resync: true }); - this.config.reactiveSet(state, contractID, /* @__PURE__ */ Object.create(null)); - this.config.reactiveSet(state[contractID], "_volatile", currentVolatileState); - } - const { HEAD: latestHEAD } = await esm_default("chelonia/out/latestHEADInfo", contractID); - console.debug(`[chelonia] syncContract: ${contractID} latestHash is: ${latestHEAD}`); - const { HEAD: recentHEAD, height: recentHeight } = state.contracts[contractID] || {}; - const isSubscribed = this.subscriptionSet.has(contractID); - if (!isSubscribed) { - const entry = this.pending.find((entry2) => entry2?.contractID === contractID); - if (!entry) { - this.pending.push({ contractID }); - } - } - this.postSyncOperations[contractID] = this.postSyncOperations[contractID] ?? /* @__PURE__ */ Object.create(null); - if (latestHEAD !== recentHEAD) { - console.debug(`[chelonia] Synchronizing Contract ${contractID}: our recent was ${recentHEAD || "undefined"} but the latest is ${latestHEAD}`); - const eventsStream = esm_default("chelonia/out/eventsAfter", contractID, { - sinceHeight: recentHeight ?? 0, - sinceHash: recentHEAD ?? contractID - }); - let latestHashFound = false; - const eventReader = eventsStream.getReader(); - for (let skip = has(state.contracts, contractID) && has(state.contracts[contractID], "HEAD"); ; skip = false) { - const { done, value: event } = await eventReader.read(); - if (done) { - if (!latestHashFound) { - throw new ChelErrorForkedChain(`expected hash ${latestHEAD} in list of events for contract ${contractID}`); - } - break; - } - if (!latestHashFound) { - latestHashFound = SPMessage.deserializeHEAD(event).hash === latestHEAD; + } + get(k, { + allowStale = this.allowStale, + updateAgeOnGet = this.updateAgeOnGet, + noDeleteOnStaleGet = this.noDeleteOnStaleGet + } = {}) { + const index = this.keyMap.get(k); + if (index !== void 0) { + const value = this.valList[index]; + const fetching = this.isBackgroundFetch(value); + if (this.isStale(index)) { + if (!fetching) { + if (!noDeleteOnStaleGet) { + this.delete(k); } - if (skip) - continue; - await esm_default("chelonia/private/in/handleEvent", contractID, event); - } - } else if (!isSubscribed) { - this.subscriptionSet.add(contractID); - esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { - added: [contractID], - removed: [] - }); - const entryIndex = this.pending.findIndex((entry) => entry?.contractID === contractID); - if (entryIndex !== -1) { - this.pending.splice(entryIndex, 1); + return allowStale ? value : void 0; + } else { + return allowStale ? value.__staleWhileFetching : void 0; } - console.debug(`[chelonia] added already synchronized ${contractID} to subscription set`); - } else { - console.debug(`[chelonia] contract ${contractID} was already synchronized`); - } - esm_default("chelonia/private/enqueuePostSyncOps", contractID); - } catch (e2) { - console.error(`[chelonia] syncContract error: ${e2.message || e2}`, e2); - this.config.hooks.syncContractError?.(e2, contractID); - throw e2; - } finally { - if (state[contractID]?._volatile?.resyncing) { - this.config.reactiveDel(state[contractID]._volatile, "resyncing"); - } - delete this.currentSyncs[contractID]; - esm_default("okTurtles.events/emit", CONTRACT_IS_SYNCING, contractID, false); - } - }, - "chelonia/private/enqueuePostSyncOps": function(contractID) { - if (!has(this.postSyncOperations, contractID)) - return; - Object.entries(this.postSyncOperations[contractID]).forEach(([key, op]) => { - delete this.postSyncOperations[contractID][key]; - esm_default("chelonia/private/queueEvent", contractID, op).catch((e2) => { - console.error(`Post-sync operation for ${contractID} failed`, { contractID, op, error: e2 }); - }); - }); - }, - "chelonia/private/watchForeignKeys": function(externalContractID) { - const state = esm_default(this.config.stateSelector); - const externalContractState = state[externalContractID]; - const pendingWatch = externalContractState?._vm?.pendingWatch; - if (!pendingWatch || !Object.keys(pendingWatch).length) - return; - const signingKey = findSuitableSecretKeyId(externalContractState, [SPMessage.OP_KEY_DEL], ["sig"]); - const canMirrorOperations = !!signingKey; - if (!canMirrorOperations) { - console.info("[chelonia/private/watchForeignKeys]: Returning as operations cannot be mirrored", { externalContractID }); - return; - } - Object.entries(pendingWatch).forEach(([contractID, keys]) => { - if (!Array.isArray(keys) || // Check that the keys exist and haven't been revoked - !keys.reduce((acc, [, id]) => { - return acc || has(externalContractState._vm.authorizedKeys, id); - }, false)) { - console.info("[chelonia/private/watchForeignKeys]: Skipping as none of the keys to watch exist", { - externalContractID, - contractID - }); - return; - } - esm_default("chelonia/private/queueEvent", contractID, [ - "chelonia/private/in/syncContractAndWatchKeys", - contractID, - externalContractID - ]).catch((e2) => { - console.error(`Error at syncContractAndWatchKeys for contractID ${contractID} and externalContractID ${externalContractID}`, e2); - }); - }); - }, - "chelonia/private/in/syncContractAndWatchKeys": async function(contractID, externalContractID) { - const rootState = esm_default(this.config.stateSelector); - const externalContractState = rootState[externalContractID]; - const pendingWatch = externalContractState?._vm?.pendingWatch?.[contractID]?.splice(0); - if (!Array.isArray(pendingWatch) || // Check that the keys exist and haven't been revoked - !pendingWatch.reduce((acc, [, id]) => { - return acc || has(externalContractState._vm.authorizedKeys, id) && findKeyIdByName(externalContractState, externalContractState._vm.authorizedKeys[id].name) != null; - }, false)) { - console.info("[chelonia/private/syncContractAndWatchKeys]: Skipping as none of the keys to watch exist", { - externalContractID, - contractID - }); - return; - } - if (!this.subscriptionSet.has(contractID)) { - await esm_default("chelonia/private/in/syncContract", contractID); - } - const contractState = rootState[contractID]; - const keysToDelete = []; - const keysToUpdate = []; - pendingWatch.forEach(([keyName, externalId]) => { - const keyId2 = findKeyIdByName(contractState, keyName); - if (!keyId2) { - keysToDelete.push(externalId); - return; - } else if (keyId2 !== externalId) { - keysToUpdate.push(externalId); - } - if (!contractState._volatile) { - this.config.reactiveSet(contractState, "_volatile", Object.create(null, { - watch: { - value: [[keyName, externalContractID]], - configurable: true, - enumerable: true, - writable: true - } - })); } else { - if (!contractState._volatile.watch) { - this.config.reactiveSet(contractState._volatile, "watch", [ - [keyName, externalContractID] - ]); - } - if (Array.isArray(contractState._volatile.watch) && !contractState._volatile.watch.find((v2) => v2[0] === keyName && v2[1] === externalContractID)) { - contractState._volatile.watch.push([keyName, externalContractID]); - } - } - }); - if (keysToDelete.length || keysToUpdate.length) { - if (!externalContractState._volatile) { - this.config.reactiveSet(externalContractState, "_volatile", /* @__PURE__ */ Object.create(null)); - } - if (!externalContractState._volatile.pendingKeyRevocations) { - this.config.reactiveSet(externalContractState._volatile, "pendingKeyRevocations", /* @__PURE__ */ Object.create(null)); - } - keysToDelete.forEach((id) => this.config.reactiveSet(externalContractState._volatile.pendingKeyRevocations, id, "del")); - keysToUpdate.forEach((id) => this.config.reactiveSet(externalContractState._volatile.pendingKeyRevocations, id, true)); - esm_default("chelonia/private/queueEvent", externalContractID, [ - "chelonia/private/deleteOrRotateRevokedKeys", - externalContractID - ]).catch((e2) => { - console.error(`Error at deleteOrRotateRevokedKeys for contractID ${contractID} and externalContractID ${externalContractID}`, e2); - }); - } - }, - // The following function gets called when we start watching a contract for - // foreign keys for the first time, and it ensures that, at the point the - // watching starts, keys are in sync between the two contracts (later on, - // this will be handled automatically for incoming OP_KEY_DEL and - // OP_KEY_UPDATE). - // For any given foreign key, there are three possible states: - // 1. The key is in sync with the foreign contract. In this case, there's - // nothing left to do. - // 2. The key has been rotated in the foreign contract (replaced by another - // key of the same name). We need to mirror this operation manually - // since watching only affects new messages we receive. - // 3. The key has been removed in the foreign contract. We also need to - // mirror the operation. - "chelonia/private/deleteOrRotateRevokedKeys": function(contractID) { - const rootState = esm_default(this.config.stateSelector); - const contractState = rootState[contractID]; - const pendingKeyRevocations = contractState?._volatile?.pendingKeyRevocations; - if (!pendingKeyRevocations || Object.keys(pendingKeyRevocations).length === 0) - return; - const keysToUpdate = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === true).map(([id]) => id); - const [, keyUpdateSigningKeyId, keyUpdateArgs] = keysToUpdate.reduce((acc, keyId2) => { - const key = contractState._vm?.authorizedKeys?.[keyId2]; - if (!key || !key.foreignKey) - return acc; - const foreignKey = String(key.foreignKey); - const fkUrl = new URL(foreignKey); - const foreignContractID = fkUrl.pathname; - const foreignKeyName = fkUrl.searchParams.get("keyName"); - if (!foreignKeyName) - throw new Error("Missing foreign key name"); - const foreignState = rootState[foreignContractID]; - if (!foreignState) - return acc; - const fKeyId = findKeyIdByName(foreignState, foreignKeyName); - if (!fKeyId) { - if (pendingKeyRevocations[keyId2] === true) { - this.config.reactiveSet(pendingKeyRevocations, keyId2, "del"); - } - return acc; - } - const [currentRingLevel, currentSigningKeyId, currentKeyArgs] = acc; - const ringLevel = Math.min(currentRingLevel, key.ringLevel ?? Number.POSITIVE_INFINITY); - if (ringLevel >= currentRingLevel) { - currentKeyArgs.push({ - name: key.name, - oldKeyId: keyId2, - id: fKeyId, - data: foreignState._vm.authorizedKeys[fKeyId].data - }); - return [currentRingLevel, currentSigningKeyId, currentKeyArgs]; - } else if (Number.isFinite(ringLevel)) { - const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_UPDATE], ["sig"], ringLevel); - if (signingKeyId) { - currentKeyArgs.push({ - name: key.name, - oldKeyId: keyId2, - id: fKeyId, - data: foreignState._vm.authorizedKeys[fKeyId].data - }); - return [ringLevel, signingKeyId, currentKeyArgs]; + if (fetching) { + return void 0; } - } - return acc; - }, [ - Number.POSITIVE_INFINITY, - "", - [] - ]); - if (keyUpdateArgs.length !== 0) { - const contractName = contractState._vm.type; - esm_default("chelonia/out/keyUpdate", { - contractID, - contractName, - data: keyUpdateArgs, - signingKeyId: keyUpdateSigningKeyId - }).catch((e2) => { - console.error(`[chelonia/private/deleteOrRotateRevokedKeys] Error sending OP_KEY_UPDATE for ${contractID}`, e2.message); - }); - } - const keysToDelete = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === "del").map(([id]) => id); - const [, keyDelSigningKeyId, keyIdsToDelete] = keysToDelete.reduce((acc, keyId2) => { - const [currentRingLevel, currentSigningKeyId, currentKeyIds] = acc; - const ringLevel = Math.min(currentRingLevel, contractState._vm?.authorizedKeys?.[keyId2]?.ringLevel ?? Number.POSITIVE_INFINITY); - if (ringLevel >= currentRingLevel) { - currentKeyIds.push(keyId2); - return [currentRingLevel, currentSigningKeyId, currentKeyIds]; - } else if (Number.isFinite(ringLevel)) { - const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_DEL], ["sig"], ringLevel); - if (signingKeyId) { - currentKeyIds.push(keyId2); - return [ringLevel, signingKeyId, currentKeyIds]; + this.moveToTail(index); + if (updateAgeOnGet) { + this.updateItemAge(index); } + return value; } - return acc; - }, [Number.POSITIVE_INFINITY, "", []]); - if (keyIdsToDelete.length !== 0) { - const contractName = contractState._vm.type; - esm_default("chelonia/out/keyDel", { - contractID, - contractName, - data: keyIdsToDelete, - signingKeyId: keyDelSigningKeyId - }).catch((e2) => { - console.error(`[chelonia/private/deleteRevokedKeys] Error sending OP_KEY_DEL for ${contractID}`, e2.message); - }); } - }, - "chelonia/private/respondToAllKeyRequests": function(contractID) { - const state = esm_default(this.config.stateSelector); - const contractState = state[contractID] ?? {}; - const pending = contractState?._vm?.pendingKeyshares; - if (!pending) - return; - const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_ATOMIC, SPMessage.OP_KEY_REQUEST_SEEN, SPMessage.OP_KEY_SHARE], ["sig"]); - if (!signingKeyId) { - console.log("Unable to respond to key request because there is no suitable secret key with OP_KEY_REQUEST_SEEN permission"); - return; - } - Object.entries(pending).map(([hash3, entry]) => { - if (!Array.isArray(entry) || entry.length !== 4) { - return void 0; + } + connect(p, n) { + this.prev[n] = p; + this.next[p] = n; + } + moveToTail(index) { + if (index !== this.tail) { + if (index === this.head) { + this.head = this.next[index]; + } else { + this.connect(this.prev[index], this.next[index]); } - const [, , , [originatingContractID]] = entry; - return esm_default("chelonia/private/queueEvent", originatingContractID, [ - "chelonia/private/respondToKeyRequest", - contractID, - signingKeyId, - hash3 - ]).catch((e2) => { - console.error(`respondToAllKeyRequests: Error responding to key request ${hash3} from ${originatingContractID} to ${contractID}`, e2); - }); - }); - }, - "chelonia/private/respondToKeyRequest": async function(contractID, signingKeyId, hash3) { - const state = esm_default(this.config.stateSelector); - const contractState = state[contractID]; - const entry = contractState?._vm?.pendingKeyshares?.[hash3]; - const instance = this._instance; - if (!Array.isArray(entry) || entry.length !== 4) { - return; + this.connect(this.tail, index); + this.tail = index; } - const [keyShareEncryption, height, , [originatingContractID, rv, originatingContractHeight, headJSON]] = entry; - entry.pop(); - const krsEncryption = !!contractState._vm.authorizedKeys?.[signingKeyId]?._private; - await esm_default("chelonia/private/in/syncContract", originatingContractID); - if (instance !== this._instance) - return; - const originatingState = state[originatingContractID]; - const contractName = state.contracts[contractID].type; - const originatingContractName = originatingState._vm.type; - const v2 = signedIncomingData(originatingContractID, originatingState, rv, originatingContractHeight, headJSON).valueOf(); - const { encryptionKeyId } = v2; - const responseKey = encryptedIncomingData(contractID, contractState, v2.responseKey, height, this.transientSecretKeys, headJSON).valueOf(); - const deserializedResponseKey = deserializeKey(responseKey); - const responseKeyId = keyId(deserializedResponseKey); - Promise.resolve().then(() => { - if (instance !== this._instance) - return; - if (!has(originatingState._vm.authorizedKeys, responseKeyId) || originatingState._vm.authorizedKeys[responseKeyId]._notAfterHeight != null) { - throw new Error(`Unable to respond to key request for ${originatingContractID}. Key ${responseKeyId} is not valid.`); - } - esm_default("chelonia/storeSecretKeys", new Secret([{ key: deserializedResponseKey }])); - const keys = pick2(state.secretKeys, Object.entries(contractState._vm.authorizedKeys).filter(([, key]) => !!key.meta?.private?.shareable).map(([kId]) => kId)); - if (!keys || Object.keys(keys).length === 0) { - console.info("respondToAllKeyRequests: no keys to share", { - contractID, - originatingContractID - }); - return; - } - const keySharePayload = { - contractID, - keys: Object.entries(keys).map(([keyId2, key]) => ({ - id: keyId2, - meta: { - private: { - content: encryptedOutgoingData(originatingContractID, encryptionKeyId, key), - shareable: true + } + get del() { + deprecatedMethod("del", "delete"); + return this.delete; + } + delete(k) { + let deleted = false; + if (this.size !== 0) { + const index = this.keyMap.get(k); + if (index !== void 0) { + deleted = true; + if (this.size === 1) { + this.clear(); + } else { + this.removeItemSize(index); + const v2 = this.valList[index]; + if (this.isBackgroundFetch(v2)) { + v2.__abortController.abort(); + } else { + this.dispose(v2, k, "delete"); + if (this.disposeAfter) { + this.disposed.push([v2, k, "delete"]); } } - })), - keyRequestHash: hash3, - keyRequestHeight: height - }; - if (!contractState?._vm?.pendingKeyshares?.[hash3]) { - return; - } - return keySharePayload; - }).then((keySharePayload) => { - if (instance !== this._instance || !keySharePayload) - return; - return esm_default("chelonia/out/keyShare", { - contractID: originatingContractID, - contractName: originatingContractName, - data: keyShareEncryption ? encryptedOutgoingData(originatingContractID, findSuitablePublicKeyIds(originatingState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", keySharePayload) : keySharePayload, - signingKeyId: responseKeyId - }).then((msg) => { - if (instance !== this._instance) - return; - const payload = { keyRequestHash: hash3, keyShareHash: msg.hash(), success: true }; - const connectionKeyPayload = { - contractID: originatingContractID, - keys: [ - { - id: responseKeyId, - meta: { - private: { - content: encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", responseKey), - shareable: true - } - } - } - ] - }; - esm_default("chelonia/out/atomic", { - contractID, - contractName, - signingKeyId, - data: [ - [ - "chelonia/out/keyRequestResponse", - { - data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload - } - ], - [ - // Upon successful key share, we want to share deserializedResponseKey - // with ourselves - "chelonia/out/keyShare", - { - data: keyShareEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", connectionKeyPayload) : connectionKeyPayload - } - ] - ] - }).catch((e2) => { - console.error("Error at respondToKeyRequest while sending keyRequestResponse", e2); - }); - }); - }).catch((e2) => { - console.error("Error at respondToKeyRequest", e2); - const payload = { keyRequestHash: hash3, success: false }; - if (!contractState?._vm?.pendingKeyshares?.[hash3]) { - return; - } - esm_default("chelonia/out/keyRequestResponse", { - contractID, - contractName, - signingKeyId, - data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload - }).catch((e3) => { - console.error("Error at respondToKeyRequest while sending keyRequestResponse in error handler", e3); - }); - }); - }, - "chelonia/private/in/handleEvent": async function(contractID, rawMessage) { - const state = esm_default(this.config.stateSelector); - const { preHandleEvent, postHandleEvent, handleEventError } = this.config.hooks; - let processingErrored = false; - let message; - try { - if (!this.config.acceptAllMessages && !this.pending.some((entry) => entry?.contractID === contractID) && !this.subscriptionSet.has(contractID)) { - console.warn(`[chelonia] WARN: ignoring unexpected event for ${contractID}:`, rawMessage); - return; - } - const contractStateCopy = state[contractID] ? cloneDeep(state[contractID]) : /* @__PURE__ */ Object.create(null); - message = SPMessage.deserialize(rawMessage, this.transientSecretKeys, contractStateCopy, this.config.unwrapMaybeEncryptedData); - if (message.contractID() !== contractID) { - throw new Error(`[chelonia] Wrong contract ID. Expected ${contractID} but got ${message.contractID()}`); - } - if (!message.isFirstMessage() && (!has(state.contracts, contractID) || !has(state, contractID))) { - throw new ChelErrorUnrecoverable("The event is not for a first message but the contract state is missing"); - } - preHandleEvent?.(message); - const proceed = handleEvent.checkMessageOrdering.call(this, message); - if (proceed === false) - return; - if (state[contractID]?._volatile?.dirty) { - console.info(`[chelonia] Ignoring message ${message.description()} as the contract is marked as dirty`); - return; - } - const internalSideEffectStack = !this.config.skipSideEffects ? [] : void 0; - missingDecryptionKeyIdsMap.delete(message); - try { - await handleEvent.processMutation.call(this, message, contractStateCopy, internalSideEffectStack); - } catch (e_) { - const e2 = e_; - if (e2?.name === "ChelErrorDecryptionKeyNotFound") { - console.warn(`[chelonia] WARN '${e2.name}' in processMutation for ${message.description()}: ${e2.message}`, e2, message.serialize()); - if (e2.cause) { - const missingDecryptionKeyIds = missingDecryptionKeyIdsMap.get(message); - if (missingDecryptionKeyIds) { - missingDecryptionKeyIds.add(e2.cause); - } else { - missingDecryptionKeyIdsMap.set(message, /* @__PURE__ */ new Set([e2.cause])); - } + this.keyMap.delete(k); + this.keyList[index] = null; + this.valList[index] = null; + if (index === this.tail) { + this.tail = this.prev[index]; + } else if (index === this.head) { + this.head = this.next[index]; + } else { + this.next[this.prev[index]] = this.next[index]; + this.prev[this.next[index]] = this.prev[index]; } - } else { - console.error(`[chelonia] ERROR '${e2.name}' in processMutation for ${message.description()}: ${e2.message || e2}`, e2, message.serialize()); - } - console.warn(`[chelonia] Error processing ${message.description()}: ${message.serialize()}. Any side effects will be skipped!`); - if (this.config.strictProcessing) { - throw e2; - } - processingErrored = e2?.name !== "ChelErrorWarning"; - this.config.hooks.processError?.(e2, message, getMsgMeta.call(this, message, contractID, contractStateCopy)); - if (e2.name === "ChelErrorUnrecoverable" || e2.name === "ChelErrorForkedChain" || message.isFirstMessage()) { - throw e2; - } - } - if (!processingErrored) { - if (Array.isArray(internalSideEffectStack) && internalSideEffectStack.length > 0) { - await Promise.all(internalSideEffectStack.map((fn) => Promise.resolve(fn({ state: contractStateCopy, message })).catch((e_) => { - const e2 = e_; - console.error(`[chelonia] ERROR '${e2.name}' in internal side effect for ${message.description()}: ${e2.message}`, e2, { message: message.serialize() }); - }))); - } - if (!this.config.skipActionProcessing && !this.config.skipSideEffects) { - await handleEvent.processSideEffects.call(this, message, contractStateCopy)?.catch((e_) => { - const e2 = e_; - console.error(`[chelonia] ERROR '${e2.name}' in sideEffect for ${message.description()}: ${e2.message}`, e2, { message: message.serialize() }); - this.config.hooks.sideEffectError?.(e2, message); - }); + this.size--; + this.free.push(index); } } - try { - const state2 = esm_default(this.config.stateSelector); - await handleEvent.applyProcessResult.call(this, { - message, - state: state2, - contractState: contractStateCopy, - processingErrored, - postHandleEvent - }); - } catch (e_) { - const e2 = e_; - console.error(`[chelonia] ERROR '${e2.name}' for ${message.description()} marking the event as processed: ${e2.message}`, e2, { message: message.serialize() }); - } - } catch (e_) { - const e2 = e_; - console.error(`[chelonia] ERROR in handleEvent: ${e2.message || e2}`, e2); - try { - handleEventError?.(e2, message); - } catch (e22) { - console.error("[chelonia] Ignoring user error in handleEventError hook:", e22); - } - throw e2; - } finally { - if (message) { - missingDecryptionKeyIdsMap.delete(message); - } } - } - }); - eventsToReingest = []; - reprocessDebounced = debounce((contractID) => esm_default("chelonia/private/out/sync", contractID, { force: true }).catch((e2) => { - console.error(`[chelonia] Error at reprocessDebounced for ${contractID}`, e2); - }), 1e3); - handleEvent = { - checkMessageOrdering(message) { - const contractID = message.contractID(); - const hash3 = message.hash(); - const height = message.height(); - const state = esm_default(this.config.stateSelector); - const latestProcessedHeight = state.contracts[contractID]?.height; - if (!Number.isSafeInteger(height)) { - throw new ChelErrorDBBadPreviousHEAD(`Message ${hash3} in contract ${contractID} has an invalid height.`); - } - if (message.isFirstMessage() ? latestProcessedHeight != null : !(latestProcessedHeight < height)) { - if (!this.config.strictOrdering) { - return false; + if (this.disposed) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()); } - throw new ChelErrorAlreadyProcessed(`Message ${hash3} with height ${height} in contract ${contractID} has already been processed. Current height: ${latestProcessedHeight}.`); } - if (latestProcessedHeight + 1 < height) { - if (this.config.strictOrdering) { - throw new ChelErrorDBBadPreviousHEAD(`Unexpected message ${hash3} with height ${height} in contract ${contractID}: height is too high. Current height: ${latestProcessedHeight}.`); - } - if (eventsToReingest.length > 100) { - throw new ChelErrorUnrecoverable("more than 100 different bad previousHEAD errors"); - } - if (!eventsToReingest.includes(hash3)) { - console.warn(`[chelonia] WARN bad previousHEAD for ${message.description()}, will attempt to re-sync contract to reingest message`); - eventsToReingest.push(hash3); - reprocessDebounced(contractID); - return false; + return deleted; + } + clear() { + for (const index of this.rindexes({ allowStale: true })) { + const v2 = this.valList[index]; + if (this.isBackgroundFetch(v2)) { + v2.__abortController.abort(); } else { - console.error(`[chelonia] ERROR already attempted to reingest ${message.description()}, will not attempt again!`); - throw new ChelErrorDBBadPreviousHEAD(`Already attempted to reingest ${hash3}`); + const k = this.keyList[index]; + this.dispose(v2, k, "delete"); + if (this.disposeAfter) { + this.disposed.push([v2, k, "delete"]); + } } } - const reprocessIdx = eventsToReingest.indexOf(hash3); - if (reprocessIdx !== -1) { - console.warn(`[chelonia] WARN: successfully reingested ${message.description()}`); - eventsToReingest.splice(reprocessIdx, 1); - } - }, - async processMutation(message, state, internalSideEffectStack) { - const contractID = message.contractID(); - if (message.isFirstMessage()) { - if (Object.keys(state).some((k) => k !== "_volatile")) { - throw new ChelErrorUnrecoverable(`state for ${contractID} is already set`); - } + this.keyMap.clear(); + this.valList.fill(null); + this.keyList.fill(null); + if (this.ttls) { + this.ttls.fill(0); + this.starts.fill(0); } - await esm_default("chelonia/private/in/processMessage", message, state, internalSideEffectStack); - }, - processSideEffects(message, state) { - const opT = message.opType(); - if (![ - SPMessage.OP_ATOMIC, - SPMessage.OP_ACTION_ENCRYPTED, - SPMessage.OP_ACTION_UNENCRYPTED - ].includes(opT)) { - return; + if (this.sizes) { + this.sizes.fill(0); } - const contractID = message.contractID(); - const manifestHash = message.manifest(); - const hash3 = message.hash(); - const height = message.height(); - const signingKeyId = message.signingKeyId(); - const callSideEffect = async (field) => { - const wv = this.config.unwrapMaybeEncryptedData(field); - if (!wv) - return; - let v2 = wv.data; - let innerSigningKeyId; - if (isSignedData(v2)) { - innerSigningKeyId = v2.signingKeyId; - v2 = v2.valueOf(); + this.head = 0; + this.tail = 0; + this.initialFill = 1; + this.free.length = 0; + this.calculatedSize = 0; + this.size = 0; + if (this.disposed) { + while (this.disposed.length) { + this.disposeAfter(...this.disposed.shift()); } - const { action, data, meta } = v2; - const mutation = { - data, - meta, - hash: hash3, - height, - contractID, - description: message.description(), - direction: message.direction(), - signingKeyId, - get signingContractID() { - return getContractIDfromKeyId(contractID, signingKeyId, state); - }, - innerSigningKeyId, - get innerSigningContractID() { - return getContractIDfromKeyId(contractID, innerSigningKeyId, state); - } - }; - return await esm_default(`${manifestHash}/${action}/sideEffect`, mutation, state); - }; - const msg = Object(message.message()); - if (opT !== SPMessage.OP_ATOMIC) { - return callSideEffect(msg); - } - const reducer = (acc, [opT2, opV]) => { - if ([SPMessage.OP_ACTION_ENCRYPTED, SPMessage.OP_ACTION_UNENCRYPTED].includes(opT2)) { - acc.push(Object(opV)); - } - return acc; - }; - const actionsOpV = msg.reduce(reducer, []); - return Promise.allSettled(actionsOpV.map((action) => callSideEffect(action))).then((results) => { - const errors2 = results.filter((r) => r.status === "rejected").map((r) => r.reason); - if (errors2.length > 0) { - console.error("Side-effect errors", contractID, errors2); - throw new AggregateError(errors2, `Error at side effects for ${contractID}`); - } - }); - }, - async applyProcessResult({ message, state, contractState, processingErrored, postHandleEvent }) { - const contractID = message.contractID(); - const hash3 = message.hash(); - const height = message.height(); - await esm_default("chelonia/db/addEntry", message); - if (!processingErrored) { - this.config.reactiveSet(state, contractID, contractState); - try { - postHandleEvent?.(message); - } catch (e2) { - console.error(`[chelonia] ERROR '${e2.name}' for ${message.description()} in event post-handling: ${e2.message}`, e2, { message: message.serialize() }); - } - } - if (message.isFirstMessage()) { - const { type } = message.opValue(); - if (!has(state.contracts, contractID)) { - this.config.reactiveSet(state.contracts, contractID, /* @__PURE__ */ Object.create(null)); - } - this.config.reactiveSet(state.contracts[contractID], "type", type); - console.debug(`contract ${type} registered for ${contractID}`); - } - if (message.isKeyOp()) { - this.config.reactiveSet(state.contracts[contractID], "previousKeyOp", hash3); - } - this.config.reactiveSet(state.contracts[contractID], "HEAD", hash3); - this.config.reactiveSet(state.contracts[contractID], "height", height); - const missingDecryptionKeyIdsForMessage = missingDecryptionKeyIdsMap.get(message); - if (missingDecryptionKeyIdsForMessage) { - let missingDecryptionKeyIds = state.contracts[contractID].missingDecryptionKeyIds; - if (!missingDecryptionKeyIds) { - missingDecryptionKeyIds = []; - this.config.reactiveSet(state.contracts[contractID], "missingDecryptionKeyIds", missingDecryptionKeyIds); - } - missingDecryptionKeyIdsForMessage.forEach((keyId2) => { - if (missingDecryptionKeyIds.includes(keyId2)) - return; - missingDecryptionKeyIds.push(keyId2); - }); - } - if (!this.subscriptionSet.has(contractID)) { - const entry = this.pending.find((entry2) => entry2?.contractID === contractID); - if (entry) { - const index = this.pending.indexOf(entry); - if (index !== -1) { - this.pending.splice(index, 1); - } - } - this.subscriptionSet.add(contractID); - esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { - added: [contractID], - removed: [] - }); - } - if (!processingErrored) { - esm_default("okTurtles.events/emit", hash3, contractID, message); - esm_default("okTurtles.events/emit", EVENT_HANDLED, contractID, message); } } + get reset() { + deprecatedMethod("reset", "clear"); + return this.clear; + } + get length() { + deprecatedProperty("length", "size"); + return this.size; + } + static get AbortController() { + return AC; + } + static get AbortSignal() { + return AS; + } }; - notImplemented = (v2) => { - throw new Error(`chelonia: action not implemented to handle: ${JSON.stringify(v2)}.`); - }; + module14.exports = LRUCache; } }); -var wallBase; -var monotonicBase; -var resyncTimeout; -var watchdog; -var syncServerTime; -var time_sync_default; -var init_time_sync = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/time-sync.mjs"() { - init_esm(); - wallBase = Date.now(); - monotonicBase = performance.now(); - syncServerTime = async function() { - const startTime = performance.now(); - const time3 = await this.config.fetch(`${this.config.connectionURL}/time`, { - signal: this.abortController.signal - }); - const requestTimeElapsed = performance.now(); - if (requestTimeElapsed - startTime > 8e3) { - throw new Error("Error fetching server time: request took too long"); - } - if (!time3.ok) - throw new Error("Error fetching server time"); - const serverTime = new Date(await time3.text()).valueOf(); - if (Number.isNaN(serverTime)) - throw new Error("Unable to parse server time"); - const newMonotonicBase = performance.now(); - wallBase = serverTime + (requestTimeElapsed - startTime) / 2 + // Also take into account the time elapsed between `requestTimeElapsed` - // and this line (which should be very little) - (newMonotonicBase - requestTimeElapsed); - monotonicBase = newMonotonicBase; - }; - time_sync_default = esm_default("sbp/selectors/register", { - "chelonia/private/startClockSync": function() { - if (resyncTimeout !== void 0) { - throw new Error("chelonia/private/startClockSync has already been called"); - } - const resync = (delay2 = 3e5) => { - if (resyncTimeout !== null) - return; - const timeout = setTimeout(() => { - syncServerTime.call(this).then(() => { - if (resyncTimeout === timeout) - resyncTimeout = null; - resync(); - }).catch((e2) => { - if (resyncTimeout === timeout) { - resyncTimeout = null; - console.error("Error re-syncing server time; will re-attempt in 5s", e2); - setTimeout(() => resync(0), 5e3); - } else { - console.error("Error re-syncing server time; another attempt is in progress", e2); - } - }); - }, delay2); - resyncTimeout = timeout; +var requiredMethodNames; +var DatabaseBackend; +var init_DatabaseBackend = __esm({ + "src/serve/DatabaseBackend.ts"() { + "use strict"; + requiredMethodNames = ["init", "clear", "readData", "writeData", "deleteData", "close", "iterKeys", "keyCount"]; + DatabaseBackend = class _DatabaseBackend { + constructor() { + if (new.target === _DatabaseBackend) { + throw new Error("Class DatabaseBackend cannot be instantiated directly."); + } + const bindMethod = (name) => { + this[name] = this[name].bind(this); }; - let wallLast = Date.now(); - let monotonicLast = performance.now(); - watchdog = setInterval(() => { - const wallNow = Date.now(); - const monotonicNow = performance.now(); - const difference2 = Math.abs(Math.abs(wallNow - wallLast) - Math.abs(monotonicNow - monotonicLast)); - if (difference2 > 10) { - if (resyncTimeout != null) - clearTimeout(resyncTimeout); - resyncTimeout = null; - resync(0); - } - wallLast = wallNow; - monotonicLast = monotonicNow; - }, 1e4); - resyncTimeout = null; - resync(0); - }, - "chelonia/private/stopClockSync": () => { - if (resyncTimeout !== void 0) { - if (watchdog != null) - clearInterval(watchdog); - if (resyncTimeout != null) - clearTimeout(resyncTimeout); - watchdog = void 0; - resyncTimeout = void 0; - } - }, - // Get an estimate of the server's current time based on the time elapsed as - // measured locally (using a monotonic clock), which is used as an offset, and - // a previously retrieved server time. The time value is returned as a UNIX - // _millisecond_ timestamp (milliseconds since 1 Jan 1970 00:00:00 UTC) - "chelonia/time": function() { - const monotonicNow = performance.now(); - const wallNow = wallBase - monotonicBase + monotonicNow; - return Math.round(wallNow); + for (const name of requiredMethodNames) { + bindMethod(name); + } } - }); + }; } }); -function contractNameFromAction(action) { - const regexResult = ACTION_REGEX.exec(action); - const contractName = regexResult?.[2]; - if (!contractName) - throw new Error(`Poorly named action '${action}': missing contract name.`); - return contractName; -} -function outputEncryptedOrUnencryptedMessage({ contractID, innerSigningKeyId, encryptionKeyId, signingKeyId, data, meta }) { - const state = esm_default(this.config.stateSelector)[contractID]; - const signedMessage = innerSigningKeyId ? state._vm.authorizedKeys[innerSigningKeyId] && state._vm.authorizedKeys[innerSigningKeyId]?._notAfterHeight == null ? signedOutgoingData(contractID, innerSigningKeyId, data, this.transientSecretKeys) : signedOutgoingDataWithRawKey(this.transientSecretKeys[innerSigningKeyId], data) : data; - const payload = !encryptionKeyId ? signedMessage : encryptedOutgoingData(contractID, encryptionKeyId, signedMessage); - const message = signedOutgoingData(contractID, signingKeyId, payload, this.transientSecretKeys); - const rootState = esm_default(this.config.stateSelector); - const height = String(rootState.contracts[contractID].height); - const serializedData = { ...message.serialize((meta ?? "") + height), height }; - return serializedData; -} -function parseEncryptedOrUnencryptedMessage(ctx, { contractID, serializedData, meta }) { - if (!serializedData) { - throw new TypeError("[chelonia] parseEncryptedOrUnencryptedMessage: serializedData is required"); - } - const state = esm_default(ctx.config.stateSelector)[contractID]; - const numericHeight = parseInt(serializedData.height); - const rootState = esm_default(ctx.config.stateSelector); - const currentHeight = rootState.contracts[contractID].height; - if (!(numericHeight >= 0) || !(numericHeight <= currentHeight)) { - throw new Error(`[chelonia] parseEncryptedOrUnencryptedMessage: Invalid height ${serializedData.height}; it must be between 0 and ${currentHeight}`); +var database_fs_exports = {}; +__export(database_fs_exports, { + default: () => FsBackend +}); +async function testCaseSensitivity(backend) { + const { readData, writeData, deleteData } = backend; + const date3 = /* @__PURE__ */ new Date(); + const dateString = date3.toISOString(); + const originalKey = `_private_testCaseSensitivity_${date3.getTime()}_${(0, Math.random)().toFixed(8).slice(2)}`; + const differentlyCasedKey = "_P" + originalKey.slice(2); + await writeData(originalKey, dateString); + try { + const valueOriginalCase = await readData(originalKey); + const valueDifferentCase = await readData(differentlyCasedKey); + if (valueOriginalCase?.toString() !== dateString) { + console.error(`Unexpected value on case-sensitivity test; expected ${dateString}`); + throw new Error("Unexpected value: original key does not have the correct value"); + } + if (valueDifferentCase?.toString() === dateString) { + const errStr = "Filesystem database backend only works on case-sensitive filesystems. This appears to be a case insensitive file system. Set `skipFsCaseSensitivityCheck: true` on the FS backend configuration to skip."; + console.error(errStr); + throw new Error(errStr); + } + } finally { + await deleteData(originalKey); } - const aad = (meta ?? "") + serializedData.height; - const v2 = signedIncomingData(contractID, state, serializedData, numericHeight, aad, (message) => { - return maybeEncryptedIncomingData(contractID, state, message, numericHeight, ctx.transientSecretKeys, aad, void 0); - }); - let encryptionKeyId; - let innerSigningKeyId; - const unwrap2 = /* @__PURE__ */ (() => { - let result2; - return () => { - if (!result2) { - try { - let unwrapped; - unwrapped = v2.valueOf(); - if (isEncryptedData(unwrapped)) { - encryptionKeyId = unwrapped.encryptionKeyId; - unwrapped = unwrapped.valueOf(); - if (isSignedData(unwrapped)) { - innerSigningKeyId = unwrapped.signingKeyId; - unwrapped = unwrapped.valueOf(); - } else { - innerSigningKeyId = null; - } - } else { - encryptionKeyId = null; - innerSigningKeyId = null; - } - result2 = [unwrapped]; - } catch (e2) { - result2 = [void 0, e2]; - } +} +var ConfigSchema; +var splitAndGroup; +var FsBackend; +var init_database_fs = __esm({ + "src/serve/database-fs.ts"() { + "use strict"; + init_db(); + init_zod(); + init_DatabaseBackend(); + ConfigSchema = strictObject({ + dirname: optional(string2()), + depth: optional(number2()), + keyChunkLength: optional(number2()), + skipFsCaseSensitivityCheck: optional(boolean2()) + }); + splitAndGroup = (input, chunkLength, depth) => input.slice(0, chunkLength * depth).split("").reduce((acc, cv, i2) => { + acc[i2 / chunkLength | 0] = (acc[i2 / chunkLength | 0] || "") + cv; + return acc; + }, []); + FsBackend = class extends DatabaseBackend { + dataFolder = "data"; + depth = 0; + keyChunkLength = 2; + skipFsCaseSensitivityCheck = false; + constructor(options2 = {}) { + super(); + ConfigSchema.parse(options2); + if (options2.dirname) this.dataFolder = resolve9(options2.dirname); + if (options2.depth) this.depth = options2.depth; + if (options2.keyChunkLength) this.keyChunkLength = options2.keyChunkLength; + if (options2.skipFsCaseSensitivityCheck) this.skipFsCaseSensitivityCheck = true; } - if (result2.length === 2) { - throw result2[1]; + // Maps a given key to a real path on the filesystem. + mapKey(key) { + if (basename9(normalize8(key)) !== key) throw new TypeError("Invalid key"); + if (!this.depth) return join9(this.dataFolder, key); + const keyChunks = splitAndGroup(key, this.keyChunkLength, this.depth); + return join9(this.dataFolder, ...keyChunks, key); } - return result2[0]; - }; - })(); - const result = { - get contractID() { - return contractID; - }, - get innerSigningKeyId() { - if (innerSigningKeyId === void 0) { - try { - unwrap2(); - } catch { + async init() { + await mkdir(this.dataFolder, { mode: 488, recursive: true }); + if (!this.skipFsCaseSensitivityCheck) { + await testCaseSensitivity(this); } } - return innerSigningKeyId; - }, - get encryptionKeyId() { - if (encryptionKeyId === void 0) { - try { - unwrap2(); - } catch { - } + async clear() { + const names = await readdir(this.dataFolder); + const paths = names.map((name) => join9(this.dataFolder, name)); + await Promise.all( + paths.map((p) => rm(p, { recursive: true })) + ); } - return encryptionKeyId; - }, - get signingKeyId() { - return v2.signingKeyId; - }, - get data() { - return unwrap2(); - }, - get signingContractID() { - return getContractIDfromKeyId(contractID, result.signingKeyId, state); - }, - get innerSigningContractID() { - return getContractIDfromKeyId(contractID, result.innerSigningKeyId, state); - } - }; - return result; -} -async function outEncryptedOrUnencryptedAction(opType, params) { - const { atomic, action, contractID, data, hooks, publishOptions } = params; - const contractName = contractNameFromAction(action); - const manifestHash = this.config.contracts.manifests[contractName]; - const { contract } = this.manifestToContract[manifestHash]; - const state = contract.state(contractID); - const meta = await contract.metadata.create(); - const unencMessage = { action, data, meta }; - const signedMessage = params.innerSigningKeyId ? state._vm.authorizedKeys[params.innerSigningKeyId] && state._vm.authorizedKeys[params.innerSigningKeyId]?._notAfterHeight == null ? signedOutgoingData(contractID, params.innerSigningKeyId, unencMessage, this.transientSecretKeys) : signedOutgoingDataWithRawKey(this.transientSecretKeys[params.innerSigningKeyId], unencMessage) : unencMessage; - if (opType === SPMessage.OP_ACTION_ENCRYPTED && !params.encryptionKeyId) { - throw new Error("OP_ACTION_ENCRYPTED requires an encryption key ID be given"); - } - if (params.encryptionKey) { - if (params.encryptionKeyId !== keyId(params.encryptionKey)) { - throw new Error("OP_ACTION_ENCRYPTED raw encryption key does not match encryptionKeyId"); - } - } - const payload = opType === SPMessage.OP_ACTION_UNENCRYPTED ? signedMessage : params.encryptionKey ? encryptedOutgoingDataWithRawKey(params.encryptionKey, signedMessage) : encryptedOutgoingData(contractID, params.encryptionKeyId, signedMessage); - let message = SPMessage.createV1_0({ - contractID, - op: [ - opType, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - if (!atomic) { - message = await esm_default("chelonia/private/out/publishEvent", message, publishOptions, hooks); - } - return message; -} -function gettersProxy(state, getters) { - const proxyGetters = new Proxy({}, { - get(_target, prop) { - return getters[prop](state, proxyGetters); - } - }); - return { getters: proxyGetters }; -} -var ACTION_REGEX; -var chelonia_default; -var init_chelonia = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/chelonia.mjs"() { - init_esm2(); - init_esm4(); - init_esm(); - init_esm5(); - init_functions(); - init_pubsub(); - init_esm7(); - init_errors3(); - init_events(); - init_SPMessage(); - init_chelonia_utils(); - init_encryptedData(); - init_files(); - init_internals(); - init_signedData(); - init_time_sync(); - init_utils(); - ACTION_REGEX = /^((([\w.]+)\/([^/]+))(?:\/(?:([^/]+)\/)?)?)\w*/; - chelonia_default = esm_default("sbp/selectors/register", { - // https://www.wordnik.com/words/chelonia - // https://gitlab.okturtles.org/okturtles/group-income/-/wikis/E2E-Protocol/Framework.md#alt-names - "chelonia/_init": function() { - this.config = { - // TODO: handle connecting to multiple servers for federation - get connectionURL() { - throw new Error("Invalid use of connectionURL before initialization"); - }, - // override! - set connectionURL(value) { - Object.defineProperty(this, "connectionURL", { value, writable: true }); - }, - stateSelector: "chelonia/private/state", - // override to integrate with, for example, vuex - contracts: { - defaults: { - modules: {}, - // '' => resolved module import - exposedGlobals: {}, - allowedDomains: [], - allowedSelectors: [], - preferSlim: false - }, - overrides: {}, - // override default values per-contract - manifests: {} - // override! contract names => manifest hashes - }, - whitelisted: (action) => !!this.whitelistedActions[action], - reactiveSet: (obj, key, value) => { - obj[key] = value; - return value; - }, - // example: set to Vue.set - fetch: (...args) => fetch(...args), - reactiveDel: (obj, key) => { - delete obj[key]; - }, - // acceptAllMessages disables checking whether we are expecting a message - // or not for processing - acceptAllMessages: false, - skipActionProcessing: false, - skipDecryptionAttempts: false, - skipSideEffects: false, - // Strict processing will treat all processing errors as unrecoverable - // This is useful, e.g., in the server, to prevent invalid messages from - // being added to the database - strictProcessing: false, - // Strict ordering will throw on past events with ChelErrorAlreadyProcessed - // Similarly, future events will not be reingested and will throw - // with ChelErrorDBBadPreviousHEAD - strictOrdering: false, - connectionOptions: { - maxRetries: Infinity, - // See https://github.com/okTurtles/group-income/issues/1183 - reconnectOnTimeout: true - // can be enabled since we are not doing auth via web sockets - }, - hooks: { - preHandleEvent: null, - // async (message: SPMessage) => {} - postHandleEvent: null, - // async (message: SPMessage) => {} - processError: null, - // (e: Error, message: SPMessage) => {} - sideEffectError: null, - // (e: Error, message: SPMessage) => {} - handleEventError: null, - // (e: Error, message: SPMessage) => {} - syncContractError: null, - // (e: Error, contractID: string) => {} - pubsubError: null - // (e:Error, socket: Socket) - }, - unwrapMaybeEncryptedData - }; - this._instance = /* @__PURE__ */ Object.create(null); - this.abortController = new AbortController(); - this.state = { - contracts: {}, - // contractIDs => { type, HEAD } (contracts we've subscribed to) - pending: [] - // prevents processing unexpected data from a malicious server - }; - this.manifestToContract = {}; - this.whitelistedActions = {}; - this.currentSyncs = /* @__PURE__ */ Object.create(null); - this.postSyncOperations = /* @__PURE__ */ Object.create(null); - this.sideEffectStacks = /* @__PURE__ */ Object.create(null); - this.sideEffectStack = (contractID) => { - let stack = this.sideEffectStacks[contractID]; - if (!stack) { - this.sideEffectStacks[contractID] = stack = []; - } - return stack; - }; - this.setPostSyncOp = (contractID, key, op) => { - this.postSyncOperations[contractID] = this.postSyncOperations[contractID] || /* @__PURE__ */ Object.create(null); - this.postSyncOperations[contractID][key] = op; - }; - const secretKeyGetter = (o2, p) => { - if (has(o2, p)) - return o2[p]; - const rootState = esm_default(this.config.stateSelector); - if (rootState?.secretKeys && has(rootState.secretKeys, p)) { - const key = deserializeKey(rootState.secretKeys[p]); - o2[p] = key; - return key; - } - }; - const secretKeyList = (o2) => { - const rootState = esm_default(this.config.stateSelector); - const stateKeys = Object.keys(rootState?.secretKeys || {}); - return Array.from(/* @__PURE__ */ new Set([...Object.keys(o2), ...stateKeys])); - }; - this.transientSecretKeys = new Proxy(/* @__PURE__ */ Object.create(null), { - get: secretKeyGetter, - ownKeys: secretKeyList - }); - this.ephemeralReferenceCount = /* @__PURE__ */ Object.create(null); - this.subscriptionSet = /* @__PURE__ */ new Set(); - this.pending = []; - }, - "chelonia/config": function() { - return { - ...cloneDeep(this.config), - fetch: this.config.fetch, - reactiveSet: this.config.reactiveSet, - reactiveDel: this.config.reactiveDel - }; - }, - "chelonia/configure": async function(config2) { - merge2(this.config, config2); - Object.assign(this.config.hooks, config2.hooks || {}); - if (config2.contracts) { - Object.assign(this.config.contracts.defaults, config2.contracts.defaults || {}); - const manifests = this.config.contracts.manifests; - console.debug("[chelonia] preloading manifests:", Object.keys(manifests)); - for (const contractName in manifests) { - await esm_default("chelonia/private/loadManifest", contractName, manifests[contractName]); - } - } - if (has(config2, "skipDecryptionAttempts")) { - if (config2.skipDecryptionAttempts) { - this.config.unwrapMaybeEncryptedData = (data) => { - if (data == null) - return; - if (!isEncryptedData(data)) { - return { - encryptionKeyId: null, - data - }; - } - }; - } else { - this.config.unwrapMaybeEncryptedData = unwrapMaybeEncryptedData; - } - } - }, - "chelonia/reset": async function(newState, postCleanupFn) { - if (typeof newState === "function" && typeof postCleanupFn === "undefined") { - postCleanupFn = newState; - newState = void 0; - } - if (this.pubsub) { - esm_default("chelonia/private/stopClockSync"); - } - Object.keys(this.postSyncOperations).forEach((cID) => { - esm_default("chelonia/private/enqueuePostSyncOps", cID); - }); - await esm_default("chelonia/contract/waitPublish"); - await esm_default("chelonia/contract/wait"); - Object.keys(this.postSyncOperations).forEach((cID) => { - esm_default("chelonia/private/enqueuePostSyncOps", cID); - }); - await esm_default("chelonia/contract/waitPublish"); - await esm_default("chelonia/contract/wait"); - const result = await postCleanupFn?.(); - const rootState = esm_default(this.config.stateSelector); - this._instance = /* @__PURE__ */ Object.create(null); - this.abortController.abort(); - this.abortController = new AbortController(); - reactiveClearObject(rootState, this.config.reactiveDel); - this.config.reactiveSet(rootState, "contracts", /* @__PURE__ */ Object.create(null)); - clearObject(this.ephemeralReferenceCount); - this.pending.splice(0); - clearObject(this.currentSyncs); - clearObject(this.postSyncOperations); - clearObject(this.sideEffectStacks); - const removedContractIDs = Array.from(this.subscriptionSet); - this.subscriptionSet.clear(); - esm_default("chelonia/clearTransientSecretKeys"); - esm_default("okTurtles.events/emit", CHELONIA_RESET); - esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { - added: [], - removed: removedContractIDs - }); - if (this.pubsub) { - esm_default("chelonia/private/startClockSync"); - } - if (newState) { - Object.entries(newState).forEach(([key, value]) => { - this.config.reactiveSet(rootState, key, value); - }); - } - return result; - }, - "chelonia/storeSecretKeys": function(wkeys) { - const rootState = esm_default(this.config.stateSelector); - if (!rootState.secretKeys) { - this.config.reactiveSet(rootState, "secretKeys", /* @__PURE__ */ Object.create(null)); - } - let keys = wkeys.valueOf(); - if (!keys) - return; - if (!Array.isArray(keys)) - keys = [keys]; - keys.forEach(({ key, transient }) => { - if (!key) - return; - if (typeof key === "string") { - key = deserializeKey(key); - } - const id = keyId(key); - if (!has(this.transientSecretKeys, id)) { - this.transientSecretKeys[id] = key; - } - if (transient) - return; - if (!has(rootState.secretKeys, id)) { - this.config.reactiveSet(rootState.secretKeys, id, serializeKey(key, true)); - } - }); - }, - "chelonia/clearTransientSecretKeys": function(ids) { - if (Array.isArray(ids)) { - ids.forEach((id) => { - delete this.transientSecretKeys[id]; - }); - } else { - Object.keys(this.transientSecretKeys).forEach((id) => { - delete this.transientSecretKeys[id]; - }); - } - }, - "chelonia/haveSecretKey": function(keyId2, persistent) { - if (!persistent && has(this.transientSecretKeys, keyId2)) - return true; - const rootState = esm_default(this.config.stateSelector); - return !!rootState?.secretKeys && has(rootState.secretKeys, keyId2); - }, - "chelonia/contract/isResyncing": function(contractIDOrState) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - return !!contractIDOrState?._volatile?.dirty || !!contractIDOrState?._volatile?.resyncing; - }, - "chelonia/contract/hasKeyShareBeenRespondedBy": function(contractIDOrState, requestedToContractID, reference) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const result = Object.values(contractIDOrState?._vm.authorizedKeys || {}).some((r) => { - return r?.meta?.keyRequest?.responded && r.meta.keyRequest.contractID === requestedToContractID && (!reference || r.meta.keyRequest.reference === reference); + async readData(key) { + checkKey(key); + return await readFile(this.mapKey(key)).catch((err) => { + if (err.code !== "ENOENT") throw err; }); - return result; - }, - "chelonia/contract/waitingForKeyShareTo": function(contractIDOrState, requestingContractID, reference) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const result = contractIDOrState._volatile?.pendingKeyRequests?.filter((r) => { - return r && (!requestingContractID || r.contractID === requestingContractID) && (!reference || r.reference === reference); - })?.map(({ name }) => name); - if (!result?.length) - return null; - return result; - }, - "chelonia/contract/successfulKeySharesByContractID": function(contractIDOrState, requestingContractID) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const keyShares = Object.values(contractIDOrState._vm.keyshares || {}); - if (!keyShares?.length) - return; - const result = /* @__PURE__ */ Object.create(null); - keyShares.forEach((kS) => { - if (!kS.success) - return; - if (requestingContractID && kS.contractID !== requestingContractID) + } + async writeData(key, value) { + const path8 = this.mapKey(key); + if (this.depth) await mkdir(dirname9(path8), { mode: 488, recursive: true }); + await writeFile(path8, value); + } + async deleteData(key) { + await unlink(this.mapKey(key)).catch((e2) => { + if (e2?.code === "ENOENT") { return; - if (!result[kS.contractID]) - result[kS.contractID] = []; - result[kS.contractID].push({ height: kS.height, hash: kS.hash }); - }); - Object.keys(result).forEach((cID) => { - result[cID].sort((a, b) => { - return b.height - a.height; - }); - }); - return result; - }, - "chelonia/contract/hasKeysToPerformOperation": function(contractIDOrState, operation) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const op = operation !== "*" ? [operation] : operation; - return !!findSuitableSecretKeyId(contractIDOrState, op, ["sig"]); - }, - // Did sourceContractIDOrState receive an OP_KEY_SHARE to perform the given - // operation on contractIDOrState? - "chelonia/contract/receivedKeysToPerformOperation": function(sourceContractIDOrState, contractIDOrState, operation) { - const rootState = esm_default(this.config.stateSelector); - if (typeof sourceContractIDOrState === "string") { - sourceContractIDOrState = rootState[sourceContractIDOrState]; - } - if (typeof contractIDOrState === "string") { - contractIDOrState = rootState[contractIDOrState]; - } - const op = operation !== "*" ? [operation] : operation; - const keyId2 = findSuitableSecretKeyId(contractIDOrState, op, ["sig"]); - return sourceContractIDOrState?._vm?.sharedKeyIds?.some((sK) => sK.id === keyId2); - }, - "chelonia/contract/currentKeyIdByName": function(contractIDOrState, name, requireSecretKey) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const currentKeyId = findKeyIdByName(contractIDOrState, name); - if (requireSecretKey && !esm_default("chelonia/haveSecretKey", currentKeyId)) { - return; - } - return currentKeyId; - }, - "chelonia/contract/foreignKeysByContractID": function(contractIDOrState, foreignContractID) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - return findForeignKeysByContractID(contractIDOrState, foreignContractID); - }, - "chelonia/contract/historicalKeyIdsByName": function(contractIDOrState, name) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const currentKeyId = findKeyIdByName(contractIDOrState, name); - const revokedKeyIds = findRevokedKeyIdsByName(contractIDOrState, name); - return currentKeyId ? [currentKeyId, ...revokedKeyIds] : revokedKeyIds; - }, - "chelonia/contract/suitableSigningKey": function(contractIDOrState, permissions, purposes, ringLevel, allowedActions) { - if (typeof contractIDOrState === "string") { - const rootState = esm_default(this.config.stateSelector); - contractIDOrState = rootState[contractIDOrState]; - } - const keyId2 = findSuitableSecretKeyId(contractIDOrState, permissions, purposes, ringLevel, allowedActions); - return keyId2; - }, - "chelonia/contract/setPendingKeyRevocation": function(contractID, names) { - const rootState = esm_default(this.config.stateSelector); - const state = rootState[contractID]; - if (!state._volatile) - this.config.reactiveSet(state, "_volatile", /* @__PURE__ */ Object.create(null)); - if (!state._volatile.pendingKeyRevocations) { - this.config.reactiveSet(state._volatile, "pendingKeyRevocations", /* @__PURE__ */ Object.create(null)); - } - for (const name of names) { - const keyId2 = findKeyIdByName(state, name); - if (keyId2) { - this.config.reactiveSet(state._volatile.pendingKeyRevocations, keyId2, true); - } else { - console.warn("[setPendingKeyRevocation] Unable to find keyId for name", { - contractID, - name - }); - } - } - }, - "chelonia/shelterAuthorizationHeader"(contractID) { - return buildShelterAuthorizationHeader.call(this, contractID); - }, - // The purpose of the 'chelonia/crypto/*' selectors is so that they can be called - // from contracts without including the crypto code (i.e., importing crypto.js) - // This function takes a function as a parameter that returns a string - // It does not a string directly to prevent accidentally logging the value, - // which is a secret - "chelonia/crypto/keyId": (inKey) => { - return keyId(inKey.valueOf()); - }, - // TODO: allow connecting to multiple servers at once - "chelonia/connect": function(options2 = {}) { - if (!this.config.connectionURL) - throw new Error("config.connectionURL missing"); - if (!this.config.connectionOptions) - throw new Error("config.connectionOptions missing"); - if (this.pubsub) { - this.pubsub.destroy(); - } - let pubsubURL = this.config.connectionURL; - if (true) { - pubsubURL += `?debugID=${randomHexString(6)}`; - } - if (this.pubsub) { - esm_default("chelonia/private/stopClockSync"); - } - esm_default("chelonia/private/startClockSync"); - this.pubsub = createClient(pubsubURL, { - ...this.config.connectionOptions, - handlers: { - ...options2.handlers, - // Every time we get a REQUEST_TYPE.SUB response, which happens for - // 'new' subscriptions as well as every time the connection is reset - "subscription-succeeded": function(event) { - const { channelID } = event.detail; - if (this.subscriptionSet.has(channelID)) { - esm_default("chelonia/private/out/sync", channelID, { force: true }).catch((err) => { - console.warn(`[chelonia] Syncing contract ${channelID} failed: ${err.message}`); - }); - } - options2.handlers?.["subscription-succeeded"]?.call(this, event); - } - }, - // Map message handlers to transparently handle encryption and signatures - messageHandlers: { - ...Object.fromEntries(Object.entries(options2.messageHandlers || {}).map(([k, v2]) => { - switch (k) { - case NOTIFICATION_TYPE.PUB: - return [ - k, - (msg) => { - if (!msg.channelID) { - console.info("[chelonia] Discarding pub event without channelID"); - return; - } - if (!this.subscriptionSet.has(msg.channelID)) { - console.info(`[chelonia] Discarding pub event for ${msg.channelID} because it's not in the current subscriptionSet`); - return; - } - esm_default("chelonia/queueInvocation", msg.channelID, () => { - v2.call(this.pubsub, parseEncryptedOrUnencryptedMessage(this, { - contractID: msg.channelID, - serializedData: msg.data - })); - }).catch((e2) => { - console.error(`[chelonia] Error processing pub event for ${msg.channelID}`, e2); - }); - } - ]; - case NOTIFICATION_TYPE.KV: - return [ - k, - (msg) => { - if (!msg.channelID || !msg.key) { - console.info("[chelonia] Discarding kv event without channelID or key"); - return; - } - if (!this.subscriptionSet.has(msg.channelID)) { - console.info(`[chelonia] Discarding kv event for ${msg.channelID} because it's not in the current subscriptionSet`); - return; - } - esm_default("chelonia/queueInvocation", msg.channelID, () => { - v2.call(this.pubsub, [ - msg.key, - parseEncryptedOrUnencryptedMessage(this, { - contractID: msg.channelID, - meta: msg.key, - serializedData: JSON.parse(Buffer6.from(msg.data).toString()) - }) - ]); - }).catch((e2) => { - console.error(`[chelonia] Error processing kv event for ${msg.channelID} and key ${msg.key}`, msg, e2); - }); - } - ]; - case NOTIFICATION_TYPE.DELETION: - return [ - k, - (msg) => v2.call(this.pubsub, msg.data) - ]; - default: - return [k, v2]; - } - })), - [NOTIFICATION_TYPE.ENTRY](msg) { - const { contractID } = SPMessage.deserializeHEAD(msg.data); - esm_default("chelonia/private/in/enqueueHandleEvent", contractID, msg.data); - } } + throw e2; }); - if (!this.contractsModifiedListener) { - this.contractsModifiedListener = () => esm_default("chelonia/pubsub/update"); - esm_default("okTurtles.events/on", CONTRACTS_MODIFIED, this.contractsModifiedListener); - } - return this.pubsub; - }, - // This selector is defined primarily for ingesting web push notifications, - // although it can be used as a general-purpose API to process events received - // from other external sources that are not managed by Chelonia itself (i.e. sources - // other than the Chelonia-managed websocket connection and RESTful API). - "chelonia/handleEvent": async function(event) { - const { contractID } = SPMessage.deserializeHEAD(event); - return await esm_default("chelonia/private/in/enqueueHandleEvent", contractID, event); - }, - "chelonia/defineContract": function(contract) { - if (!ACTION_REGEX.exec(contract.name)) - throw new Error(`bad contract name: ${contract.name}`); - if (!contract.metadata) - contract.metadata = { validate() { - }, create: () => ({}) }; - if (!contract.getters) - contract.getters = {}; - contract.state = (contractID) => esm_default(this.config.stateSelector)[contractID]; - contract.manifest = this.defContractManifest; - contract.sbp = this.defContractSBP; - this.defContractSelectors = []; - this.defContract = contract; - this.defContractSelectors.push(...esm_default("sbp/selectors/register", { - // expose getters for Vuex integration and other conveniences - [`${contract.manifest}/${contract.name}/getters`]: () => contract.getters, - // 2 ways to cause sideEffects to happen: by defining a sideEffect function in the - // contract, or by calling /pushSideEffect w/async SBP call. Can also do both. - [`${contract.manifest}/${contract.name}/pushSideEffect`]: (contractID, asyncSbpCall) => { - const [sel] = asyncSbpCall; - if (sel.startsWith(contract.name + "/")) { - asyncSbpCall[0] = `${contract.manifest}/${sel}`; - } - this.sideEffectStack(contractID).push(asyncSbpCall); - } - })); - for (const action in contract.actions) { - contractNameFromAction(action); - this.whitelistedActions[action] = true; - this.defContractSelectors.push(...esm_default("sbp/selectors/register", { - [`${contract.manifest}/${action}/process`]: async (message, state) => { - const { meta, data, contractID } = message; - state = state || contract.state(contractID); - const gProxy = gettersProxy(state, contract.getters); - await contract.metadata.validate(meta, { state, ...gProxy, contractID }); - await contract.actions[action].validate(data, { - state, - ...gProxy, - meta, - message, - contractID - }); - this.sideEffectStacks[contractID] = []; - await contract.actions[action].process(message, { state, ...gProxy }); - }, - // 'mutation' is an object that's similar to 'message', but not identical - [`${contract.manifest}/${action}/sideEffect`]: async (mutation, state) => { - if (contract.actions[action].sideEffect) { - state = state || contract.state(mutation.contractID); - if (!state) { - console.warn(`[${contract.manifest}/${action}/sideEffect]: Skipping side-effect since there is no contract state for contract ${mutation.contractID}`); - return; - } - const stateCopy = cloneDeep(state); - const gProxy = gettersProxy(stateCopy, contract.getters); - await contract.actions[action].sideEffect(mutation, { state: stateCopy, ...gProxy }); - } - const sideEffects = this.sideEffectStack(mutation.contractID); - while (sideEffects.length > 0) { - const sideEffect = sideEffects.shift(); - try { - await contract.sbp(...sideEffect); - } catch (e_) { - const e2 = e_; - console.error(`[chelonia] ERROR: '${e2.name}' ${e2.message}, for pushed sideEffect of ${mutation.description}:`, sideEffect); - this.sideEffectStacks[mutation.contractID] = []; - throw e2; - } - } - } - })); - } - for (const method in contract.methods) { - this.defContractSelectors.push(...esm_default("sbp/selectors/register", { - [`${contract.manifest}/${method}`]: contract.methods[method] - })); - } - esm_default("okTurtles.events/emit", CONTRACT_REGISTERED, contract); - }, - "chelonia/queueInvocation": (contractID, sbpInvocation) => { - return esm_default("chelonia/private/queueEvent", contractID, ["chelonia/private/noop"]).then(() => esm_default("chelonia/private/queueEvent", "public:" + contractID, sbpInvocation)); - }, - "chelonia/begin": async (...invocations) => { - for (const invocation of invocations) { - await esm_default(...invocation); - } - }, - // call this manually to resubscribe/unsubscribe from contracts as needed - // if you are using a custom stateSelector and reload the state (e.g. upon login) - "chelonia/pubsub/update": function() { - const client = this.pubsub; - const subscribedIDs = [...client.subscriptionSet]; - const currentIDs = Array.from(this.subscriptionSet); - const leaveSubscribed = intersection2(subscribedIDs, currentIDs); - const toUnsubscribe = difference(subscribedIDs, leaveSubscribed); - const toSubscribe = difference(currentIDs, leaveSubscribed); - try { - for (const contractID of toUnsubscribe) { - client.unsub(contractID); - } - for (const contractID of toSubscribe) { - client.sub(contractID); + } + close() { + } + async *iterKeys() { + const entries = await readdir(this.dataFolder, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isFile()) { + yield entry.name; } - } catch (e2) { - console.error(`[chelonia] pubsub/update: error ${e2.name}: ${e2.message}`, { toUnsubscribe, toSubscribe }, e2); - this.config.hooks.pubsubError?.(e2, client); } - }, - // resolves when all pending actions for these contractID(s) finish - "chelonia/contract/wait": function(contractIDs) { - const listOfIds = contractIDs ? typeof contractIDs === "string" ? [contractIDs] : contractIDs : Object.keys(esm_default(this.config.stateSelector).contracts); - return Promise.all(listOfIds.flatMap((cID) => { - return esm_default("chelonia/queueInvocation", cID, ["chelonia/private/noop"]); - })); - }, - // resolves when all pending *writes* for these contractID(s) finish - "chelonia/contract/waitPublish": function(contractIDs) { - const listOfIds = contractIDs ? typeof contractIDs === "string" ? [contractIDs] : contractIDs : Object.keys(esm_default(this.config.stateSelector).contracts); - return Promise.all(listOfIds.flatMap((cID) => { - return esm_default("chelonia/private/queueEvent", `publish:${cID}`, ["chelonia/private/noop"]); - })); - }, - // 'chelonia/contract' - selectors related to injecting remote data and monitoring contracts - // TODO: add an optional parameter to "retain" the contract (see #828) - // eslint-disable-next-line require-await - "chelonia/contract/sync": async function(contractIDs, params) { - const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; - listOfIds.forEach((id) => { - if (checkCanBeGarbageCollected.call(this, id)) { - if (process.env.CI) { - Promise.reject(new Error("[chelonia] Missing reference count for contract " + id)); - } - console.error("[chelonia] Missing reference count for contract " + id); - throw new Error("Missing reference count for contract"); - } - }); - return esm_default("chelonia/private/out/sync", listOfIds, { ...params, force: true }); - }, - "chelonia/contract/isSyncing": function(contractID, { firstSync = false } = {}) { - const isSyncing = !!this.currentSyncs[contractID]; - return firstSync ? isSyncing && this.currentSyncs[contractID].firstSync : isSyncing; - }, - "chelonia/contract/currentSyncs": function() { - return Object.keys(this.currentSyncs); - }, - // Because `/remove` is done asynchronously and a contract might be removed - // much later than when the call to remove was made, an optional callback - // can be passed to verify whether to proceed with removal. This is used as - // part of the `/release` mechanism to prevent removing contracts that have - // acquired new references since the call to `/remove`. - "chelonia/contract/remove": function(contractIDs, { confirmRemovalCallback, permanent } = {}) { - const rootState = esm_default(this.config.stateSelector); - const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; - return Promise.all(listOfIds.map((contractID) => { - if (!rootState?.contracts?.[contractID]) { - return void 0; - } - return esm_default("chelonia/private/queueEvent", contractID, () => { - if (confirmRemovalCallback && !confirmRemovalCallback(contractID)) { - return; - } - const rootState2 = esm_default(this.config.stateSelector); - const fkContractIDs = Array.from(new Set(Object.values(rootState2[contractID]?._vm?.authorizedKeys ?? {}).filter((k) => { - return !!k.foreignKey; - }).map((k) => { - try { - const fkUrl = new URL(k.foreignKey); - return fkUrl.pathname; - } catch { - return void 0; - } - }).filter(Boolean))); - esm_default("chelonia/private/removeImmediately", contractID, { permanent }); - if (fkContractIDs.length) { - esm_default("chelonia/contract/release", fkContractIDs, { try: true }).catch((e2) => { - console.error("[chelonia] Error attempting to release foreign key contracts", e2); - }); - } - }); - })); - }, - "chelonia/contract/retain": async function(contractIDs, params) { - const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; - const rootState = esm_default(this.config.stateSelector); - if (listOfIds.length === 0) - return Promise.resolve(); - const checkIfDeleted = (id) => { - if (rootState.contracts[id] === null) { - console.error("[chelonia/contract/retain] Called /retain on permanently deleted contract.", id); - throw new ChelErrorResourceGone("Unable to retain permanently deleted contract " + id); - } - }; - if (!params?.ephemeral) { - listOfIds.forEach((id) => { - checkIfDeleted(id); - if (!has(rootState.contracts, id)) { - this.config.reactiveSet(rootState.contracts, id, /* @__PURE__ */ Object.create(null)); - } - this.config.reactiveSet(rootState.contracts[id], "references", (rootState.contracts[id].references ?? 0) + 1); - }); - } else { - listOfIds.forEach((id) => { - checkIfDeleted(id); - if (!has(this.ephemeralReferenceCount, id)) { - this.ephemeralReferenceCount[id] = 1; - } else { - this.ephemeralReferenceCount[id] = this.ephemeralReferenceCount[id] + 1; - } - }); - } - return await esm_default("chelonia/private/out/sync", listOfIds); - }, - // the `try` parameter does not affect (ephemeral or persistent) reference - // counts, but rather removes a contract if the reference count is zero - // and the contract isn't being monitored for foreign keys. This parameter - // is meant mostly for internal chelonia use, so that removing or releasing - // a contract can also remove other contracts that this first contract - // was monitoring. - "chelonia/contract/release": async function(contractIDs, params) { - const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; - const rootState = esm_default(this.config.stateSelector); - if (!params?.try) { - if (!params?.ephemeral) { - listOfIds.forEach((id) => { - if (rootState.contracts[id] === null) { - console.warn("[chelonia/contract/release] Called /release on permanently deleted contract. This has no effect.", id); - return; - } - if (has(rootState.contracts, id) && has(rootState.contracts[id], "references")) { - const current = rootState.contracts[id].references; - if (current === 0) { - console.error("[chelonia/contract/release] Invalid negative reference count for", id); - if (process.env.CI) { - Promise.reject(new Error("Invalid negative reference count: " + id)); - } - throw new Error("Invalid negative reference count"); - } - if (current <= 1) { - this.config.reactiveDel(rootState.contracts[id], "references"); - } else { - this.config.reactiveSet(rootState.contracts[id], "references", current - 1); - } - } else { - console.error("[chelonia/contract/release] Invalid negative reference count for", id); - if (process.env.CI) { - Promise.reject(new Error("Invalid negative reference count: " + id)); - } - throw new Error("Invalid negative reference count"); - } - }); - } else { - listOfIds.forEach((id) => { - if (rootState.contracts[id] === null) { - console.warn("[chelonia/contract/release] Called /release on permanently deleted contract. This has no effect.", id); - return; - } - if (has(this.ephemeralReferenceCount, id)) { - const current = this.ephemeralReferenceCount[id] ?? 0; - if (current <= 1) { - delete this.ephemeralReferenceCount[id]; - } else { - this.ephemeralReferenceCount[id] = current - 1; - } - } else { - console.error("[chelonia/contract/release] Invalid negative ephemeral reference count for", id); - if (process.env.CI) { - Promise.reject(new Error("Invalid negative ephemeral reference count: " + id)); - } - throw new Error("Invalid negative ephemeral reference count"); - } - }); - } - } - const boundCheckCanBeGarbageCollected = checkCanBeGarbageCollected.bind(this); - const idsToRemove = listOfIds.filter(boundCheckCanBeGarbageCollected); - return idsToRemove.length ? await esm_default("chelonia/contract/remove", idsToRemove, { - confirmRemovalCallback: boundCheckCanBeGarbageCollected - }) : void 0; - }, - "chelonia/contract/disconnect": async function(contractID, contractIDToDisconnect) { - const state = esm_default(this.config.stateSelector); - const contractState = state[contractID]; - const keyIds = Object.values(contractState._vm.authorizedKeys).filter((k) => { - return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractIDToDisconnect; - }).map((k) => k.id); - if (!keyIds.length) - return; - return await esm_default("chelonia/out/keyDel", { - contractID, - contractName: contractState._vm.type, - data: keyIds, - signingKeyId: findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_DEL], ["sig"]) - }); - }, - "chelonia/in/processMessage": function(messageOrRawMessage, state) { - const stateCopy = cloneDeep(state); - const message = typeof messageOrRawMessage === "string" ? SPMessage.deserialize(messageOrRawMessage, this.transientSecretKeys, stateCopy, this.config.unwrapMaybeEncryptedData) : messageOrRawMessage; - return esm_default("chelonia/private/in/processMessage", message, stateCopy).then(() => stateCopy).catch((e2) => { - console.warn(`chelonia/in/processMessage: reverting mutation ${message.description()}: ${message.serialize()}`, e2); - return state; - }); - }, - "chelonia/out/fetchResource": async function(cid, { code: code2 } = {}) { - const parsedCID = parseCID(cid); - if (code2 != null) { - if (parsedCID.code !== code2) { - throw new Error(`Invalid CID content type. Expected ${code2}, got ${parsedCID.code}`); - } - } - const local = await esm_default("chelonia.db/get", cid); - if (local != null) - return local; - const url2 = `${this.config.connectionURL}/file/${cid}`; - const data = await this.config.fetch(url2, { signal: this.abortController.signal }).then(handleFetchResult("text")); - const ourHash = createCID(data, parsedCID.code); - if (ourHash !== cid) { - throw new Error(`expected hash ${cid}. Got: ${ourHash}`); - } - await esm_default("chelonia.db/set", cid, data); - return data; - }, - "chelonia/out/latestHEADInfo": function(contractID) { - return this.config.fetch(`${this.config.connectionURL}/latestHEADinfo/${contractID}`, { - cache: "no-store", - signal: this.abortController.signal - }).then(handleFetchResult("json")); - }, - "chelonia/out/deserializedHEAD": async function(hash3, { contractID } = {}) { - const message = await esm_default("chelonia/out/fetchResource", hash3, { - code: multicodes.SHELTER_CONTRACT_DATA - }); - const deserializedHEAD = SPMessage.deserializeHEAD(message); - if (contractID && deserializedHEAD.contractID !== contractID) { - throw new Error("chelonia/out/deserializedHEAD: Mismatched contract ID"); - } - return deserializedHEAD; - }, - "chelonia/out/eventsAfter": eventsAfter, - "chelonia/out/eventsBefore": function(contractID, { beforeHeight, limit, stream }) { - if (limit <= 0) { - console.error('[chelonia] invalid params error: "limit" needs to be positive integer'); - } - const offset = Math.max(0, beforeHeight - limit + 1); - const eventsAfterLimit = Math.min(beforeHeight + 1, limit); - return esm_default("chelonia/out/eventsAfter", contractID, { - sinceHeight: offset, - limit: eventsAfterLimit, - stream - }); - }, - "chelonia/out/eventsBetween": function(contractID, { startHash, endHeight = Number.POSITIVE_INFINITY, offset = 0, limit = 0, stream = true }) { - if (offset < 0) { - console.error('[chelonia] invalid params error: "offset" needs to be positive integer or zero'); - return; - } - let reader; - const s = new ReadableStream({ - start: async (controller) => { - const deserializedHEAD = await esm_default("chelonia/out/deserializedHEAD", startHash, { contractID }); - const startOffset = Math.max(0, deserializedHEAD.head.height - offset); - const ourLimit = limit ? Math.min(endHeight - startOffset + 1, limit) : endHeight - startOffset + 1; - if (ourLimit < 1) { - controller.close(); - return; - } - reader = esm_default("chelonia/out/eventsAfter", contractID, { - sinceHeight: startOffset, - limit: ourLimit - }).getReader(); - }, - async pull(controller) { - const { done, value } = await reader.read(); - if (done) { - controller.close(); - } else { - controller.enqueue(value); - } - } - }); - if (stream) - return s; - return collectEventStream(s); - }, - "chelonia/rootState": function() { - return esm_default(this.config.stateSelector); - }, - "chelonia/latestContractState": async function(contractID, options2 = { forceSync: false }) { - const rootState = esm_default(this.config.stateSelector); - if (rootState.contracts[contractID] === null) { - throw new ChelErrorResourceGone("Permanently deleted contract " + contractID); - } - if (!options2.forceSync && rootState[contractID] && Object.keys(rootState[contractID]).some((x3) => x3 !== "_volatile")) { - return cloneDeep(rootState[contractID]); - } - let state = /* @__PURE__ */ Object.create(null); - let contractName = rootState.contracts[contractID]?.type; - const eventsStream = esm_default("chelonia/out/eventsAfter", contractID, { - sinceHeight: 0, - sinceHash: contractID - }); - const eventsStreamReader = eventsStream.getReader(); - if (rootState[contractID]) - state._volatile = rootState[contractID]._volatile; - for (; ; ) { - const { value: event, done } = await eventsStreamReader.read(); - if (done) - return state; - const stateCopy = cloneDeep(state); - try { - await esm_default("chelonia/private/in/processMessage", SPMessage.deserialize(event, this.transientSecretKeys, state, this.config.unwrapMaybeEncryptedData), state, void 0, contractName); - if (!contractName && state._vm) { - contractName = state._vm.type; - } - } catch (e2) { - console.warn(`[chelonia] latestContractState: '${e2.name}': ${e2.message} processing:`, event, e2.stack); - if (e2 instanceof ChelErrorUnrecoverable) - throw e2; - state = stateCopy; - } - } - }, - "chelonia/contract/state": function(contractID, height) { - const state = esm_default(this.config.stateSelector)[contractID]; - const stateCopy = state && cloneDeep(state); - if (stateCopy?._vm && height != null) { - Object.keys(stateCopy._vm.authorizedKeys).forEach((keyId2) => { - if (stateCopy._vm.authorizedKeys[keyId2]._notBeforeHeight > height) { - delete stateCopy._vm.authorizedKeys[keyId2]; - } - }); - } - return stateCopy; - }, - "chelonia/contract/fullState": function(contractID) { - const rootState = esm_default(this.config.stateSelector); - if (Array.isArray(contractID)) { - return Object.fromEntries(contractID.map((contractID2) => { - return [ - contractID2, - { - contractState: rootState[contractID2], - cheloniaState: rootState.contracts[contractID2] - } - ]; - })); - } - return { - contractState: rootState[contractID], - cheloniaState: rootState.contracts[contractID] - }; - }, - // 'chelonia/out' - selectors that send data out to the server - "chelonia/out/registerContract": async function(params) { - const { contractName, keys, hooks, publishOptions, signingKeyId, actionSigningKeyId, actionEncryptionKeyId } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contractInfo = this.manifestToContract[manifestHash]; - if (!contractInfo) - throw new Error(`contract not defined: ${contractName}`); - const signingKey = this.transientSecretKeys[signingKeyId]; - if (!signingKey) - throw new Error(`Signing key ${signingKeyId} is not defined`); - const payload = { - type: contractName, - keys - }; - const contractMsg = SPMessage.createV1_0({ - contractID: null, - height: 0, - op: [ - SPMessage.OP_CONTRACT, - signedOutgoingDataWithRawKey(signingKey, payload) - ], - manifest: manifestHash - }); - const contractID = contractMsg.hash(); - await esm_default("chelonia/private/out/publishEvent", contractMsg, params.namespaceRegistration ? { - ...publishOptions, - headers: { - ...publishOptions?.headers, - "shelter-namespace-registration": params.namespaceRegistration - } - } : publishOptions, hooks && { - prepublish: hooks.prepublishContract, - postpublish: hooks.postpublishContract - }); - await esm_default("chelonia/private/out/sync", contractID); - const msg = await esm_default(actionEncryptionKeyId ? "chelonia/out/actionEncrypted" : "chelonia/out/actionUnencrypted", { - action: contractName, - contractID, - data: params.data, - signingKeyId: actionSigningKeyId ?? signingKeyId, - encryptionKeyId: actionEncryptionKeyId, - hooks, - publishOptions - }); - return msg; - }, - "chelonia/out/ownResources": async function(contractID) { - if (!contractID) { - throw new TypeError("A contract ID must be provided"); - } - const response = await this.config.fetch(`${this.config.connectionURL}/ownResources`, { - method: "GET", - signal: this.abortController.signal, - headers: new Headers([ - ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] - ]) - }); - if (!response.ok) { - console.error("Unable to fetch own resources", contractID, response.status); - throw new Error(`Unable to fetch own resources for ${contractID}: ${response.status}`); - } - return response.json(); - }, - "chelonia/out/deleteContract": async function(contractID, credentials = {}) { - if (!contractID) { - throw new TypeError("A contract ID must be provided"); - } - if (!Array.isArray(contractID)) - contractID = [contractID]; - return await Promise.allSettled(contractID.map(async (cid) => { - const hasCredential = has(credentials, cid); - const hasToken = has(credentials[cid], "token") && credentials[cid].token; - const hasBillableContractID = has(credentials[cid], "billableContractID") && credentials[cid].billableContractID; - if (!hasCredential || hasToken === hasBillableContractID) { - throw new TypeError(`Either a token or a billable contract ID must be provided for ${cid}`); - } - const response = await this.config.fetch(`${this.config.connectionURL}/deleteContract/${cid}`, { - method: "POST", - signal: this.abortController.signal, - headers: new Headers([ - [ - "authorization", - hasToken ? `bearer ${credentials[cid].token.valueOf()}` : buildShelterAuthorizationHeader.call(this, credentials[cid].billableContractID) - ] - ]) - }); - if (!response.ok) { - if (response.status === 404 || response.status === 410) { - console.warn("Contract appears to have been deleted already", cid, response.status); - return; - } - console.error("Unable to delete contract", cid, response.status); - throw new Error(`Unable to delete contract ${cid}: ${response.status}`); - } - })); - }, - // all of these functions will do both the creation of the SPMessage - // and the sending of it via 'chelonia/private/out/publishEvent' - "chelonia/out/actionEncrypted": function(params) { - return outEncryptedOrUnencryptedAction.call(this, SPMessage.OP_ACTION_ENCRYPTED, params); - }, - "chelonia/out/actionUnencrypted": function(params) { - return outEncryptedOrUnencryptedAction.call(this, SPMessage.OP_ACTION_UNENCRYPTED, params); - }, - "chelonia/out/keyShare": async function(params) { - const { atomic, originatingContractName, originatingContractID, contractName, contractID, data, hooks, publishOptions } = params; - const originatingManifestHash = this.config.contracts.manifests[originatingContractName]; - const destinationManifestHash = this.config.contracts.manifests[contractName]; - const originatingContract = originatingContractID ? this.manifestToContract[originatingManifestHash]?.contract : void 0; - const destinationContract = this.manifestToContract[destinationManifestHash]?.contract; - if (originatingContractID && !originatingContract || !destinationContract) { - throw new Error("Contract name not found"); - } - const payload = data; - if (!params.signingKeyId && !params.signingKey) { - throw new TypeError("Either signingKeyId or signingKey must be specified"); - } - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_SHARE, - params.signingKeyId ? signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) : signedOutgoingDataWithRawKey(params.signingKey, payload) - ], - manifest: destinationManifestHash - }); - if (!atomic) { - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); - } - return msg; - }, - "chelonia/out/keyAdd": async function(params) { - const { atomic, contractID, contractName, data, hooks, publishOptions } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const state = contract.state(contractID); - const payload = params.skipExistingKeyCheck ? data : data.filter((wk) => { - const k = isEncryptedData(wk) ? wk.valueOf() : wk; - if (has(state._vm.authorizedKeys, k.id)) { - if (state._vm.authorizedKeys[k.id]._notAfterHeight == null) { - return false; - } - } - return true; - }); - if (payload.length === 0) - return; - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_ADD, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - if (!atomic) { - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); - } - return msg; - }, - "chelonia/out/keyDel": async function(params) { - const { atomic, contractID, contractName, data, hooks, publishOptions } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const state = contract.state(contractID); - const payload = data.map((keyId2) => { - if (isEncryptedData(keyId2)) - return keyId2; - if (!has(state._vm.authorizedKeys, keyId2) || state._vm.authorizedKeys[keyId2]._notAfterHeight != null) { - return void 0; - } - if (state._vm.authorizedKeys[keyId2]._private) { - return encryptedOutgoingData(contractID, state._vm.authorizedKeys[keyId2]._private, keyId2); - } else { - return keyId2; - } - }).filter(Boolean); - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_DEL, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - if (!atomic) { - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); - } - return msg; - }, - "chelonia/out/keyUpdate": async function(params) { - const { atomic, contractID, contractName, data, hooks, publishOptions } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const state = contract.state(contractID); - const payload = data.map((key) => { - if (isEncryptedData(key)) - return key; - const { oldKeyId } = key; - if (state._vm.authorizedKeys[oldKeyId]._private) { - return encryptedOutgoingData(contractID, state._vm.authorizedKeys[oldKeyId]._private, key); - } else { - return key; - } - }); - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_UPDATE, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - if (!atomic) { - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); - } - return msg; - }, - "chelonia/out/keyRequest": async function(params) { - const { originatingContractID, originatingContractName, contractID, contractName, hooks, publishOptions, innerSigningKeyId, encryptionKeyId, innerEncryptionKeyId, encryptKeyRequestMetadata, reference } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const originatingManifestHash = this.config.contracts.manifests[originatingContractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - const originatingContract = this.manifestToContract[originatingManifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const rootState = esm_default(this.config.stateSelector); - try { - await esm_default("chelonia/contract/retain", contractID, { ephemeral: true }); - const state = contract.state(contractID); - const originatingState = originatingContract.state(originatingContractID); - const havePendingKeyRequest = Object.values(originatingState._vm.authorizedKeys).findIndex((k) => { - return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractID && state?._volatile?.pendingKeyRequests?.some((pkr) => pkr.name === k.name); - }) !== -1; - if (havePendingKeyRequest) { - return; - } - const keyRequestReplyKey = keygen(EDWARDS25519SHA512BATCH); - const keyRequestReplyKeyId = keyId(keyRequestReplyKey); - const keyRequestReplyKeyP = serializeKey(keyRequestReplyKey, false); - const keyRequestReplyKeyS = serializeKey(keyRequestReplyKey, true); - const signingKeyId = findSuitableSecretKeyId(originatingState, [SPMessage.OP_KEY_ADD], ["sig"]); - if (!signingKeyId) { - throw new ChelErrorUnexpected(`Unable to send key request. Originating contract is missing a key with OP_KEY_ADD permission. contractID=${contractID} originatingContractID=${originatingContractID}`); - } - const keyAddOp = () => esm_default("chelonia/out/keyAdd", { - contractID: originatingContractID, - contractName: originatingContractName, - data: [ - { - id: keyRequestReplyKeyId, - name: "#krrk-" + keyRequestReplyKeyId, - purpose: ["sig"], - ringLevel: Number.MAX_SAFE_INTEGER, - permissions: params.permissions === "*" ? "*" : Array.isArray(params.permissions) ? [...params.permissions, SPMessage.OP_KEY_SHARE] : [SPMessage.OP_KEY_SHARE], - allowedActions: params.allowedActions, - meta: { - private: { - content: encryptedOutgoingData(originatingContractID, encryptionKeyId, keyRequestReplyKeyS), - shareable: false - }, - keyRequest: { - ...reference && { - reference: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, reference) : reference - }, - contractID: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, contractID) : contractID - } - }, - data: keyRequestReplyKeyP - } - ], - signingKeyId - }).catch((e2) => { - console.error(`[chelonia] Error sending OP_KEY_ADD for ${originatingContractID} during key request to ${contractID}`, e2); - throw e2; - }); - const payload = { - contractID: originatingContractID, - height: rootState.contracts[originatingContractID].height, - replyWith: signedOutgoingData(originatingContractID, innerSigningKeyId, { - encryptionKeyId, - responseKey: encryptedOutgoingData(contractID, innerEncryptionKeyId, keyRequestReplyKeyS) - }, this.transientSecretKeys), - request: "*" - }; - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_REQUEST, - signedOutgoingData(contractID, params.signingKeyId, encryptKeyRequestMetadata ? encryptedOutgoingData(contractID, innerEncryptionKeyId, payload) : payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, { - ...hooks, - // We ensure that both messages are placed into the publish queue - prepublish: (...args) => { - return keyAddOp().then(() => hooks?.prepublish?.(...args)); - } - }); - return msg; - } finally { - await esm_default("chelonia/contract/release", contractID, { ephemeral: true }); - } - }, - "chelonia/out/keyRequestResponse": async function(params) { - const { atomic, contractID, contractName, data, hooks, publishOptions } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const payload = data; - let message = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_KEY_REQUEST_SEEN, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - if (!atomic) { - message = await esm_default("chelonia/private/out/publishEvent", message, publishOptions, hooks); - } - return message; - }, - "chelonia/out/atomic": async function(params) { - const { contractID, contractName, data, hooks, publishOptions } = params; - const manifestHash = this.config.contracts.manifests[contractName]; - const contract = this.manifestToContract[manifestHash]?.contract; - if (!contract) { - throw new Error("Contract name not found"); - } - const payload = (await Promise.all(data.map(([selector, opParams]) => { - if (![ - "chelonia/out/actionEncrypted", - "chelonia/out/actionUnencrypted", - "chelonia/out/keyAdd", - "chelonia/out/keyDel", - "chelonia/out/keyUpdate", - "chelonia/out/keyRequestResponse", - "chelonia/out/keyShare" - ].includes(selector)) { - throw new Error("Selector not allowed in OP_ATOMIC: " + selector); - } - return esm_default(selector, { - ...opParams, - ...params, - data: opParams.data, - atomic: true - }); - }))).flat().filter(Boolean).map((msg2) => { - return [msg2.opType(), msg2.opValue()]; - }); - let msg = SPMessage.createV1_0({ - contractID, - op: [ - SPMessage.OP_ATOMIC, - signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) - ], - manifest: manifestHash - }); - msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); - return msg; - }, - "chelonia/out/protocolUpgrade": async function() { - }, - "chelonia/out/propSet": async function() { - }, - "chelonia/out/propDel": async function() { - }, - "chelonia/out/encryptedOrUnencryptedPubMessage": function({ contractID, innerSigningKeyId, encryptionKeyId, signingKeyId, data }) { - const serializedData = outputEncryptedOrUnencryptedMessage.call(this, { - contractID, - innerSigningKeyId, - encryptionKeyId, - signingKeyId, - data - }); - this.pubsub.pub(contractID, serializedData); - }, - // Note: This is a bare-bones function designed for precise control. In many - // situations, the `chelonia/kv/queuedSet` selector (in chelonia-utils.js) - // will be simpler and more appropriate to use. - // In most situations, you want to use some queuing strategy (which this - // selector doesn't provide) alongside writing to the KV store. Therefore, as - // a general rule, you shouldn't be calling this selector directly unless - // you're building a utility library or if you have very specific needs. In - // this case, see if `chelonia/kv/queuedSet` covers your needs. - // `data` is allowed to be falsy, in which case a fetch will occur first and - // the `onconflict` handler will be called. - "chelonia/kv/set": async function(contractID, key, data, { ifMatch, innerSigningKeyId, encryptionKeyId, signingKeyId, maxAttempts, onconflict }) { - maxAttempts = maxAttempts ?? 3; - const url2 = `${this.config.connectionURL}/kv/${encodeURIComponent(contractID)}/${encodeURIComponent(key)}`; - const hasOnconflict = typeof onconflict === "function"; - let response; - const resolveData = async () => { - let currentValue; - if (response.ok || response.status === 409 || response.status === 412) { - const serializedDataText = await response.text(); - currentValue = serializedDataText ? parseEncryptedOrUnencryptedMessage(this, { - contractID, - serializedData: JSON.parse(serializedDataText), - meta: key - }) : void 0; - } else if (response.status !== 404 && response.status !== 410) { - throw new ChelErrorUnexpectedHttpResponseCode("[kv/set] Invalid response code: " + response.status); - } - const result = await onconflict({ - contractID, - key, - failedData: data, - status: response.status, - // If no x-cid or etag header was returned, `ifMatch` would likely be - // returned as undefined, which will then use the `''` fallback value - // when writing. This allows 404 / 410 responses to work even if no - // etag is explicitly given - etag: response.headers.get("x-cid") || response.headers.get("etag"), - get currentData() { - return currentValue?.data; - }, - currentValue - }); - if (!result) - return false; - data = result[0]; - ifMatch = result[1]; - return true; - }; - for (; ; ) { - if (data !== void 0) { - const serializedData = outputEncryptedOrUnencryptedMessage.call(this, { - contractID, - innerSigningKeyId, - encryptionKeyId, - signingKeyId, - data, - meta: key - }); - response = await this.config.fetch(url2, { - headers: new Headers([ - ["authorization", buildShelterAuthorizationHeader.call(this, contractID)], - ["if-match", ifMatch || '""'] - ]), - method: "POST", - body: JSON.stringify(serializedData), - signal: this.abortController.signal - }); - } else { - if (!hasOnconflict) { - throw TypeError("onconflict required with empty data"); - } - response = await this.config.fetch(url2, { - headers: new Headers([ - ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] - ]), - signal: this.abortController.signal - }); - if (await resolveData()) { - continue; - } else { - break; - } - } - if (!response.ok) { - if (response.status === 409 || response.status === 412) { - if (--maxAttempts <= 0) { - throw new Error("kv/set conflict setting KV value"); - } - await delay(randomIntFromRange(0, 1500)); - if (hasOnconflict) { - if (await resolveData()) { - continue; - } else { - break; - } - } else { - throw new Error(`kv/set failed with status ${response.status} and no onconflict handler was provided`); - } - } - throw new ChelErrorUnexpectedHttpResponseCode("kv/set invalid response status: " + response.status); - } - break; - } - }, - "chelonia/kv/get": async function(contractID, key) { - const response = await this.config.fetch(`${this.config.connectionURL}/kv/${encodeURIComponent(contractID)}/${encodeURIComponent(key)}`, { - headers: new Headers([ - ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] - ]), - signal: this.abortController.signal - }); - if (response.status === 404) { - return null; - } - if (!response.ok) { - throw new Error("Invalid response status: " + response.status); - } - const data = await response.json(); - return parseEncryptedOrUnencryptedMessage(this, { - contractID, - serializedData: data, - meta: key - }); - }, - // To set filters for a contract, call with `filter` set to an array of KV - // keys to receive updates for over the WebSocket. An empty array means that - // no KV updates will be sent. - // Calling with a single argument (the contract ID) will remove filters, - // meaning that KV updates will be sent for _any_ KV key. - // The last call takes precedence, so, for example, calling with filter - // set to `['foo', 'bar']` and then with `['baz']` means that KV updates will - // be received for `baz` only, not for `foo`, `bar` or any other keys. - "chelonia/kv/setFilter": function(contractID, filter) { - this.pubsub.setKvFilter(contractID, filter); - }, - "chelonia/parseEncryptedOrUnencryptedDetachedMessage": function({ contractID, serializedData, meta }) { - return parseEncryptedOrUnencryptedMessage(this, { - contractID, - serializedData, - meta - }); } - }); - esm_default("sbp/domains/lock", ["chelonia"]); + async keyCount() { + const entries = await readdir(this.dataFolder, { withFileTypes: true }); + return entries.filter((e2) => e2.isFile()).length; + } + }; } }); -var require_lru_cache = __commonJS({ - "node_modules/.deno/lru-cache@7.14.0/node_modules/lru-cache/index.js"(exports2, module14) { - var perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date; - var hasAbortController = typeof AbortController === "function"; - var AC = hasAbortController ? AbortController : class AbortController { +var require_verbatim_string = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/RESP/verbatim-string.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.VerbatimString = void 0; + var VerbatimString = class extends String { + format; + constructor(format52, value) { + super(value); + this.format = format52; + } + }; + exports2.VerbatimString = VerbatimString; + } +}); +var require_errors = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/errors.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.MultiErrorReply = exports2.CommandTimeoutDuringMaintenanceError = exports2.SocketTimeoutDuringMaintenanceError = exports2.TimeoutError = exports2.BlobError = exports2.SimpleError = exports2.ErrorReply = exports2.ReconnectStrategyError = exports2.RootNodesUnavailableError = exports2.SocketClosedUnexpectedlyError = exports2.DisconnectsClientError = exports2.ClientOfflineError = exports2.ClientClosedError = exports2.SocketTimeoutError = exports2.ConnectionTimeoutError = exports2.WatchError = exports2.AbortError = void 0; + var AbortError = class extends Error { constructor() { - this.signal = new AS(); + super("The command was aborted"); } - abort() { - this.signal.dispatchEvent("abort"); + }; + exports2.AbortError = AbortError; + var WatchError = class extends Error { + constructor(message = "One (or more) of the watched keys has been changed") { + super(message); } }; - var hasAbortSignal = typeof AbortSignal === "function"; - var hasACAbortSignal = typeof AC.AbortSignal === "function"; - var AS = hasAbortSignal ? AbortSignal : hasACAbortSignal ? AC.AbortController : class AbortSignal { + exports2.WatchError = WatchError; + var ConnectionTimeoutError = class extends Error { constructor() { - this.aborted = false; - this._listeners = []; + super("Connection timeout"); } - dispatchEvent(type) { - if (type === "abort") { - this.aborted = true; - const e2 = { type, target: this }; - this.onabort(e2); - this._listeners.forEach((f) => f(e2), this); - } + }; + exports2.ConnectionTimeoutError = ConnectionTimeoutError; + var SocketTimeoutError = class extends Error { + constructor(timeout) { + super(`Socket timeout timeout. Expecting data, but didn't receive any in ${timeout}ms.`); } - onabort() { + }; + exports2.SocketTimeoutError = SocketTimeoutError; + var ClientClosedError = class extends Error { + constructor() { + super("The client is closed"); } - addEventListener(ev, fn) { - if (ev === "abort") { - this._listeners.push(fn); - } + }; + exports2.ClientClosedError = ClientClosedError; + var ClientOfflineError = class extends Error { + constructor() { + super("The client is offline"); } - removeEventListener(ev, fn) { - if (ev === "abort") { - this._listeners = this._listeners.filter((f) => f !== fn); - } + }; + exports2.ClientOfflineError = ClientOfflineError; + var DisconnectsClientError = class extends Error { + constructor() { + super("Disconnects client"); } }; - var warned = /* @__PURE__ */ new Set(); - var deprecatedOption = (opt, instead) => { - const code2 = `LRU_CACHE_OPTION_${opt}`; - if (shouldWarn(code2)) { - warn(code2, `${opt} option`, `options.${instead}`, LRUCache); + exports2.DisconnectsClientError = DisconnectsClientError; + var SocketClosedUnexpectedlyError = class extends Error { + constructor() { + super("Socket closed unexpectedly"); } }; - var deprecatedMethod = (method, instead) => { - const code2 = `LRU_CACHE_METHOD_${method}`; - if (shouldWarn(code2)) { - const { prototype } = LRUCache; - const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, method); - warn(code2, `${method} method`, `cache.${instead}()`, get2); + exports2.SocketClosedUnexpectedlyError = SocketClosedUnexpectedlyError; + var RootNodesUnavailableError = class extends Error { + constructor() { + super("All the root nodes are unavailable"); } }; - var deprecatedProperty = (field, instead) => { - const code2 = `LRU_CACHE_PROPERTY_${field}`; - if (shouldWarn(code2)) { - const { prototype } = LRUCache; - const { get: get2 } = Object.getOwnPropertyDescriptor(prototype, field); - warn(code2, `${field} property`, `cache.${instead}`, get2); + exports2.RootNodesUnavailableError = RootNodesUnavailableError; + var ReconnectStrategyError = class extends Error { + originalError; + socketError; + constructor(originalError, socketError) { + super(originalError.message); + this.originalError = originalError; + this.socketError = socketError; } }; - var emitWarning = (...a) => { - typeof process === "object" && process && typeof process.emitWarning === "function" ? process.emitWarning(...a) : console.error(...a); + exports2.ReconnectStrategyError = ReconnectStrategyError; + var ErrorReply = class extends Error { }; - var shouldWarn = (code2) => !warned.has(code2); - var warn = (code2, what, instead, fn) => { - warned.add(code2); - const msg = `The ${what} is deprecated. Please use ${instead} instead.`; - emitWarning(msg, "DeprecationWarning", code2, fn); + exports2.ErrorReply = ErrorReply; + var SimpleError = class extends ErrorReply { }; - var isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n); - var getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null; - var ZeroArray = class extends Array { - constructor(size) { - super(size); - this.fill(0); + exports2.SimpleError = SimpleError; + var BlobError = class extends ErrorReply { + }; + exports2.BlobError = BlobError; + var TimeoutError = class extends Error { + }; + exports2.TimeoutError = TimeoutError; + var SocketTimeoutDuringMaintenanceError = class extends TimeoutError { + constructor(timeout) { + super(`Socket timeout during maintenance. Expecting data, but didn't receive any in ${timeout}ms.`); } }; - var Stack = class { - constructor(max) { - if (max === 0) { - return []; - } - const UintArray = getUintArray(max); - this.heap = new UintArray(max); - this.length = 0; + exports2.SocketTimeoutDuringMaintenanceError = SocketTimeoutDuringMaintenanceError; + var CommandTimeoutDuringMaintenanceError = class extends TimeoutError { + constructor(timeout) { + super(`Command timeout during maintenance. Waited to write command for more than ${timeout}ms.`); } - push(n) { - this.heap[this.length++] = n; + }; + exports2.CommandTimeoutDuringMaintenanceError = CommandTimeoutDuringMaintenanceError; + var MultiErrorReply = class extends ErrorReply { + replies; + errorIndexes; + constructor(replies, errorIndexes) { + super(`${errorIndexes.length} commands failed, see .replies and .errorIndexes for more information`); + this.replies = replies; + this.errorIndexes = errorIndexes; } - pop() { - return this.heap[--this.length]; + *errors() { + for (const index of this.errorIndexes) { + yield this.replies[index]; + } } }; - var LRUCache = class _LRUCache { - constructor(options2 = {}) { - const { - max = 0, - ttl, - ttlResolution = 1, - ttlAutopurge, - updateAgeOnGet, - updateAgeOnHas, - allowStale, - dispose, - disposeAfter, - noDisposeOnSet, - noUpdateTTL, - maxSize = 0, - maxEntrySize = 0, - sizeCalculation, - fetchMethod, - fetchContext, - noDeleteOnFetchRejection, - noDeleteOnStaleGet - } = options2; - const { length: length2, maxAge: maxAge2, stale } = options2 instanceof _LRUCache ? {} : options2; - if (max !== 0 && !isPosInt(max)) { - throw new TypeError("max option must be a nonnegative integer"); - } - const UintArray = max ? getUintArray(max) : Array; - if (!UintArray) { - throw new Error("invalid max value: " + max); - } - this.max = max; - this.maxSize = maxSize; - this.maxEntrySize = maxEntrySize || this.maxSize; - this.sizeCalculation = sizeCalculation || length2; - if (this.sizeCalculation) { - if (!this.maxSize && !this.maxEntrySize) { - throw new TypeError( - "cannot set sizeCalculation without setting maxSize or maxEntrySize" - ); - } - if (typeof this.sizeCalculation !== "function") { - throw new TypeError("sizeCalculation set to non-function"); - } - } - this.fetchMethod = fetchMethod || null; - if (this.fetchMethod && typeof this.fetchMethod !== "function") { - throw new TypeError( - "fetchMethod must be a function if specified" - ); - } - this.fetchContext = fetchContext; - if (!this.fetchMethod && fetchContext !== void 0) { - throw new TypeError( - "cannot set fetchContext without fetchMethod" - ); - } - this.keyMap = /* @__PURE__ */ new Map(); - this.keyList = new Array(max).fill(null); - this.valList = new Array(max).fill(null); - this.next = new UintArray(max); - this.prev = new UintArray(max); - this.head = 0; - this.tail = 0; - this.free = new Stack(max); - this.initialFill = 1; - this.size = 0; - if (typeof dispose === "function") { - this.dispose = dispose; - } - if (typeof disposeAfter === "function") { - this.disposeAfter = disposeAfter; - this.disposed = []; - } else { - this.disposeAfter = null; - this.disposed = null; - } - this.noDisposeOnSet = !!noDisposeOnSet; - this.noUpdateTTL = !!noUpdateTTL; - this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection; - if (this.maxEntrySize !== 0) { - if (this.maxSize !== 0) { - if (!isPosInt(this.maxSize)) { - throw new TypeError( - "maxSize must be a positive integer if specified" - ); - } - } - if (!isPosInt(this.maxEntrySize)) { - throw new TypeError( - "maxEntrySize must be a positive integer if specified" - ); - } - this.initializeSizeTracking(); - } - this.allowStale = !!allowStale || !!stale; - this.noDeleteOnStaleGet = !!noDeleteOnStaleGet; - this.updateAgeOnGet = !!updateAgeOnGet; - this.updateAgeOnHas = !!updateAgeOnHas; - this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1; - this.ttlAutopurge = !!ttlAutopurge; - this.ttl = ttl || maxAge2 || 0; - if (this.ttl) { - if (!isPosInt(this.ttl)) { - throw new TypeError( - "ttl must be a positive integer if specified" - ); - } - this.initializeTTLTracking(); - } - if (this.max === 0 && this.ttl === 0 && this.maxSize === 0) { - throw new TypeError( - "At least one of max, maxSize, or ttl is required" - ); - } - if (!this.ttlAutopurge && !this.max && !this.maxSize) { - const code2 = "LRU_CACHE_UNBOUNDED"; - if (shouldWarn(code2)) { - warned.add(code2); - const msg = "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption."; - emitWarning(msg, "UnboundedCacheWarning", code2, _LRUCache); - } - } - if (stale) { - deprecatedOption("stale", "allowStale"); - } - if (maxAge2) { - deprecatedOption("maxAge", "ttl"); - } - if (length2) { - deprecatedOption("length", "sizeCalculation"); - } + exports2.MultiErrorReply = MultiErrorReply; + } +}); +var require_decoder = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/RESP/decoder.js"(exports2) { + "use strict"; + var _a2; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.Decoder = exports2.PUSH_TYPE_MAPPING = exports2.RESP_TYPES = void 0; + var verbatim_string_1 = require_verbatim_string(); + var errors_1 = require_errors(); + exports2.RESP_TYPES = { + NULL: 95, + // _ + BOOLEAN: 35, + // # + NUMBER: 58, + // : + BIG_NUMBER: 40, + // ( + DOUBLE: 44, + // , + SIMPLE_STRING: 43, + // + + BLOB_STRING: 36, + // $ + VERBATIM_STRING: 61, + // = + SIMPLE_ERROR: 45, + // - + BLOB_ERROR: 33, + // ! + ARRAY: 42, + // * + SET: 126, + // ~ + MAP: 37, + // % + PUSH: 62 + // > + }; + var ASCII = { + "\r": 13, + "t": 116, + "+": 43, + "-": 45, + "0": 48, + ".": 46, + "i": 105, + "n": 110, + "E": 69, + "e": 101 + }; + exports2.PUSH_TYPE_MAPPING = { + [exports2.RESP_TYPES.BLOB_STRING]: Buffer + }; + var Decoder2 = class { + onReply; + onErrorReply; + onPush; + getTypeMapping; + #cursor = 0; + #next; + constructor(config2) { + this.onReply = config2.onReply; + this.onErrorReply = config2.onErrorReply; + this.onPush = config2.onPush; + this.getTypeMapping = config2.getTypeMapping; } - getRemainingTTL(key) { - return this.has(key, { updateAgeOnHas: false }) ? Infinity : 0; + reset() { + this.#cursor = 0; + this.#next = void 0; } - initializeTTLTracking() { - this.ttls = new ZeroArray(this.max); - this.starts = new ZeroArray(this.max); - this.setItemTTL = (index, ttl, start = perf.now()) => { - this.starts[index] = ttl !== 0 ? start : 0; - this.ttls[index] = ttl; - if (ttl !== 0 && this.ttlAutopurge) { - const t = setTimeout(() => { - if (this.isStale(index)) { - this.delete(this.keyList[index]); - } - }, ttl + 1); - if (t.unref) { - t.unref(); - } + write(chunk) { + if (this.#cursor >= chunk.length) { + this.#cursor -= chunk.length; + return; + } + if (this.#next) { + if (this.#next(chunk) || this.#cursor >= chunk.length) { + this.#cursor -= chunk.length; + return; } - }; - this.updateItemAge = (index) => { - this.starts[index] = this.ttls[index] !== 0 ? perf.now() : 0; - }; - let cachedNow = 0; - const getNow = () => { - const n = perf.now(); - if (this.ttlResolution > 0) { - cachedNow = n; - const t = setTimeout( - () => cachedNow = 0, - this.ttlResolution - ); - if (t.unref) { - t.unref(); - } + } + do { + const type = chunk[this.#cursor]; + if (++this.#cursor === chunk.length) { + this.#next = this.#continueDecodeTypeValue.bind(this, type); + break; } - return n; - }; - this.getRemainingTTL = (key) => { - const index = this.keyMap.get(key); - if (index === void 0) { - return 0; + if (this.#decodeTypeValue(type, chunk)) { + break; } - return this.ttls[index] === 0 || this.starts[index] === 0 ? Infinity : this.starts[index] + this.ttls[index] - (cachedNow || getNow()); - }; - this.isStale = (index) => { - return this.ttls[index] !== 0 && this.starts[index] !== 0 && (cachedNow || getNow()) - this.starts[index] > this.ttls[index]; - }; + } while (this.#cursor < chunk.length); + this.#cursor -= chunk.length; } - updateItemAge(index) { + #continueDecodeTypeValue(type, chunk) { + this.#next = void 0; + return this.#decodeTypeValue(type, chunk); } - setItemTTL(index, ttl, start) { + #decodeTypeValue(type, chunk) { + switch (type) { + case exports2.RESP_TYPES.NULL: + this.onReply(this.#decodeNull()); + return false; + case exports2.RESP_TYPES.BOOLEAN: + return this.#handleDecodedValue(this.onReply, this.#decodeBoolean(chunk)); + case exports2.RESP_TYPES.NUMBER: + return this.#handleDecodedValue(this.onReply, this.#decodeNumber(this.getTypeMapping()[exports2.RESP_TYPES.NUMBER], chunk)); + case exports2.RESP_TYPES.BIG_NUMBER: + return this.#handleDecodedValue(this.onReply, this.#decodeBigNumber(this.getTypeMapping()[exports2.RESP_TYPES.BIG_NUMBER], chunk)); + case exports2.RESP_TYPES.DOUBLE: + return this.#handleDecodedValue(this.onReply, this.#decodeDouble(this.getTypeMapping()[exports2.RESP_TYPES.DOUBLE], chunk)); + case exports2.RESP_TYPES.SIMPLE_STRING: + return this.#handleDecodedValue(this.onReply, this.#decodeSimpleString(this.getTypeMapping()[exports2.RESP_TYPES.SIMPLE_STRING], chunk)); + case exports2.RESP_TYPES.BLOB_STRING: + return this.#handleDecodedValue(this.onReply, this.#decodeBlobString(this.getTypeMapping()[exports2.RESP_TYPES.BLOB_STRING], chunk)); + case exports2.RESP_TYPES.VERBATIM_STRING: + return this.#handleDecodedValue(this.onReply, this.#decodeVerbatimString(this.getTypeMapping()[exports2.RESP_TYPES.VERBATIM_STRING], chunk)); + case exports2.RESP_TYPES.SIMPLE_ERROR: + return this.#handleDecodedValue(this.onErrorReply, this.#decodeSimpleError(chunk)); + case exports2.RESP_TYPES.BLOB_ERROR: + return this.#handleDecodedValue(this.onErrorReply, this.#decodeBlobError(chunk)); + case exports2.RESP_TYPES.ARRAY: + return this.#handleDecodedValue(this.onReply, this.#decodeArray(this.getTypeMapping(), chunk)); + case exports2.RESP_TYPES.SET: + return this.#handleDecodedValue(this.onReply, this.#decodeSet(this.getTypeMapping(), chunk)); + case exports2.RESP_TYPES.MAP: + return this.#handleDecodedValue(this.onReply, this.#decodeMap(this.getTypeMapping(), chunk)); + case exports2.RESP_TYPES.PUSH: + return this.#handleDecodedValue(this.onPush, this.#decodeArray(exports2.PUSH_TYPE_MAPPING, chunk)); + default: + throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`); + } } - isStale(index) { + #handleDecodedValue(cb, value) { + if (typeof value === "function") { + this.#next = this.#continueDecodeValue.bind(this, cb, value); + return true; + } + cb(value); return false; } - initializeSizeTracking() { - this.calculatedSize = 0; - this.sizes = new ZeroArray(this.max); - this.removeItemSize = (index) => { - this.calculatedSize -= this.sizes[index]; - this.sizes[index] = 0; - }; - this.requireSize = (k, v2, size, sizeCalculation) => { - if (!isPosInt(size)) { - if (sizeCalculation) { - if (typeof sizeCalculation !== "function") { - throw new TypeError("sizeCalculation must be a function"); - } - size = sizeCalculation(v2, k); - if (!isPosInt(size)) { - throw new TypeError( - "sizeCalculation return invalid (expect positive integer)" - ); - } - } else { - throw new TypeError( - "invalid size value (must be positive integer)" - ); - } - } - return size; - }; - this.addItemSize = (index, size) => { - this.sizes[index] = size; - const maxSize = this.maxSize - this.sizes[index]; - while (this.calculatedSize > maxSize) { - this.evict(true); - } - this.calculatedSize += this.sizes[index]; - }; + #continueDecodeValue(cb, next, chunk) { + this.#next = void 0; + return this.#handleDecodedValue(cb, next(chunk)); } - removeItemSize(index) { + #decodeNull() { + this.#cursor += 2; + return null; } - addItemSize(index, size) { + #decodeBoolean(chunk) { + const boolean3 = chunk[this.#cursor] === ASCII.t; + this.#cursor += 3; + return boolean3; } - requireSize(k, v2, size, sizeCalculation) { - if (size || sizeCalculation) { - throw new TypeError( - "cannot set size without setting maxSize or maxEntrySize on cache" - ); + #decodeNumber(type, chunk) { + if (type === String) { + return this.#decodeSimpleString(String, chunk); } - } - *indexes({ allowStale = this.allowStale } = {}) { - if (this.size) { - for (let i2 = this.tail; true; ) { - if (!this.isValidIndex(i2)) { - break; - } - if (allowStale || !this.isStale(i2)) { - yield i2; - } - if (i2 === this.head) { - break; - } else { - i2 = this.prev[i2]; - } - } + switch (chunk[this.#cursor]) { + case ASCII["+"]: + return this.#maybeDecodeNumberValue(false, chunk); + case ASCII["-"]: + return this.#maybeDecodeNumberValue(true, chunk); + default: + return this.#decodeNumberValue(false, this.#decodeUnsingedNumber.bind(this, 0), chunk); } } - *rindexes({ allowStale = this.allowStale } = {}) { - if (this.size) { - for (let i2 = this.head; true; ) { - if (!this.isValidIndex(i2)) { - break; - } - if (allowStale || !this.isStale(i2)) { - yield i2; - } - if (i2 === this.tail) { - break; - } else { - i2 = this.next[i2]; - } + #maybeDecodeNumberValue(isNegative, chunk) { + const cb = this.#decodeUnsingedNumber.bind(this, 0); + return ++this.#cursor === chunk.length ? this.#decodeNumberValue.bind(this, isNegative, cb) : this.#decodeNumberValue(isNegative, cb, chunk); + } + #decodeNumberValue(isNegative, numberCb, chunk) { + const number3 = numberCb(chunk); + return typeof number3 === "function" ? this.#decodeNumberValue.bind(this, isNegative, number3) : isNegative ? -number3 : number3; + } + #decodeUnsingedNumber(number3, chunk) { + let cursor = this.#cursor; + do { + const byte = chunk[cursor]; + if (byte === ASCII["\r"]) { + this.#cursor = cursor + 2; + return number3; } + number3 = number3 * 10 + byte - ASCII["0"]; + } while (++cursor < chunk.length); + this.#cursor = cursor; + return this.#decodeUnsingedNumber.bind(this, number3); + } + #decodeBigNumber(type, chunk) { + if (type === String) { + return this.#decodeSimpleString(String, chunk); + } + switch (chunk[this.#cursor]) { + case ASCII["+"]: + return this.#maybeDecodeBigNumberValue(false, chunk); + case ASCII["-"]: + return this.#maybeDecodeBigNumberValue(true, chunk); + default: + return this.#decodeBigNumberValue(false, this.#decodeUnsingedBigNumber.bind(this, 0n), chunk); } } - isValidIndex(index) { - return this.keyMap.get(this.keyList[index]) === index; + #maybeDecodeBigNumberValue(isNegative, chunk) { + const cb = this.#decodeUnsingedBigNumber.bind(this, 0n); + return ++this.#cursor === chunk.length ? this.#decodeBigNumberValue.bind(this, isNegative, cb) : this.#decodeBigNumberValue(isNegative, cb, chunk); } - *entries() { - for (const i2 of this.indexes()) { - yield [this.keyList[i2], this.valList[i2]]; - } + #decodeBigNumberValue(isNegative, bigNumberCb, chunk) { + const bigNumber = bigNumberCb(chunk); + return typeof bigNumber === "function" ? this.#decodeBigNumberValue.bind(this, isNegative, bigNumber) : isNegative ? -bigNumber : bigNumber; } - *rentries() { - for (const i2 of this.rindexes()) { - yield [this.keyList[i2], this.valList[i2]]; - } + #decodeUnsingedBigNumber(bigNumber, chunk) { + let cursor = this.#cursor; + do { + const byte = chunk[cursor]; + if (byte === ASCII["\r"]) { + this.#cursor = cursor + 2; + return bigNumber; + } + bigNumber = bigNumber * 10n + BigInt(byte - ASCII["0"]); + } while (++cursor < chunk.length); + this.#cursor = cursor; + return this.#decodeUnsingedBigNumber.bind(this, bigNumber); } - *keys() { - for (const i2 of this.indexes()) { - yield this.keyList[i2]; + #decodeDouble(type, chunk) { + if (type === String) { + return this.#decodeSimpleString(String, chunk); } - } - *rkeys() { - for (const i2 of this.rindexes()) { - yield this.keyList[i2]; + switch (chunk[this.#cursor]) { + case ASCII.n: + this.#cursor += 5; + return NaN; + case ASCII["+"]: + return this.#maybeDecodeDoubleInteger(false, chunk); + case ASCII["-"]: + return this.#maybeDecodeDoubleInteger(true, chunk); + default: + return this.#decodeDoubleInteger(false, 0, chunk); } } - *values() { - for (const i2 of this.indexes()) { - yield this.valList[i2]; - } + #maybeDecodeDoubleInteger(isNegative, chunk) { + return ++this.#cursor === chunk.length ? this.#decodeDoubleInteger.bind(this, isNegative, 0) : this.#decodeDoubleInteger(isNegative, 0, chunk); } - *rvalues() { - for (const i2 of this.rindexes()) { - yield this.valList[i2]; + #decodeDoubleInteger(isNegative, integer2, chunk) { + if (chunk[this.#cursor] === ASCII.i) { + this.#cursor += 5; + return isNegative ? -Infinity : Infinity; } + return this.#continueDecodeDoubleInteger(isNegative, integer2, chunk); } - [Symbol.iterator]() { - return this.entries(); + #continueDecodeDoubleInteger(isNegative, integer2, chunk) { + let cursor = this.#cursor; + do { + const byte = chunk[cursor]; + switch (byte) { + case ASCII["."]: + this.#cursor = cursor + 1; + return this.#cursor < chunk.length ? this.#decodeDoubleDecimal(isNegative, 0, integer2, chunk) : this.#decodeDoubleDecimal.bind(this, isNegative, 0, integer2); + case ASCII.E: + case ASCII.e: + this.#cursor = cursor + 1; + const i2 = isNegative ? -integer2 : integer2; + return this.#cursor < chunk.length ? this.#decodeDoubleExponent(i2, chunk) : this.#decodeDoubleExponent.bind(this, i2); + case ASCII["\r"]: + this.#cursor = cursor + 2; + return isNegative ? -integer2 : integer2; + default: + integer2 = integer2 * 10 + byte - ASCII["0"]; + } + } while (++cursor < chunk.length); + this.#cursor = cursor; + return this.#continueDecodeDoubleInteger.bind(this, isNegative, integer2); } - find(fn, getOptions = {}) { - for (const i2 of this.indexes()) { - if (fn(this.valList[i2], this.keyList[i2], this)) { - return this.get(this.keyList[i2], getOptions); + // Precalculated multipliers for decimal points to improve performance + // "... about 15 to 17 decimal places ..." + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#:~:text=about%2015%20to%2017%20decimal%20places + static #DOUBLE_DECIMAL_MULTIPLIERS = [ + 0.1, + 0.01, + 1e-3, + 1e-4, + 1e-5, + 1e-6, + 1e-7, + 1e-8, + 1e-9, + 1e-10, + 1e-11, + 1e-12, + 1e-13, + 1e-14, + 1e-15, + 1e-16, + 1e-17 + ]; + #decodeDoubleDecimal(isNegative, decimalIndex, double, chunk) { + let cursor = this.#cursor; + do { + const byte = chunk[cursor]; + switch (byte) { + case ASCII.E: + case ASCII.e: + this.#cursor = cursor + 1; + const d = isNegative ? -double : double; + return this.#cursor === chunk.length ? this.#decodeDoubleExponent.bind(this, d) : this.#decodeDoubleExponent(d, chunk); + case ASCII["\r"]: + this.#cursor = cursor + 2; + return isNegative ? -double : double; + } + if (decimalIndex < _a2.#DOUBLE_DECIMAL_MULTIPLIERS.length) { + double += (byte - ASCII["0"]) * _a2.#DOUBLE_DECIMAL_MULTIPLIERS[decimalIndex++]; } + } while (++cursor < chunk.length); + this.#cursor = cursor; + return this.#decodeDoubleDecimal.bind(this, isNegative, decimalIndex, double); + } + #decodeDoubleExponent(double, chunk) { + switch (chunk[this.#cursor]) { + case ASCII["+"]: + return ++this.#cursor === chunk.length ? this.#continueDecodeDoubleExponent.bind(this, false, double, 0) : this.#continueDecodeDoubleExponent(false, double, 0, chunk); + case ASCII["-"]: + return ++this.#cursor === chunk.length ? this.#continueDecodeDoubleExponent.bind(this, true, double, 0) : this.#continueDecodeDoubleExponent(true, double, 0, chunk); } + return this.#continueDecodeDoubleExponent(false, double, 0, chunk); } - forEach(fn, thisp = this) { - for (const i2 of this.indexes()) { - fn.call(thisp, this.valList[i2], this.keyList[i2], this); + #continueDecodeDoubleExponent(isNegative, double, exponent, chunk) { + let cursor = this.#cursor; + do { + const byte = chunk[cursor]; + if (byte === ASCII["\r"]) { + this.#cursor = cursor + 2; + return double * 10 ** (isNegative ? -exponent : exponent); + } + exponent = exponent * 10 + byte - ASCII["0"]; + } while (++cursor < chunk.length); + this.#cursor = cursor; + return this.#continueDecodeDoubleExponent.bind(this, isNegative, double, exponent); + } + #findCRLF(chunk, cursor) { + while (chunk[cursor] !== ASCII["\r"]) { + if (++cursor === chunk.length) { + this.#cursor = chunk.length; + return -1; + } } + this.#cursor = cursor + 2; + return cursor; } - rforEach(fn, thisp = this) { - for (const i2 of this.rindexes()) { - fn.call(thisp, this.valList[i2], this.keyList[i2], this); + #decodeSimpleString(type, chunk) { + const start = this.#cursor, crlfIndex = this.#findCRLF(chunk, start); + if (crlfIndex === -1) { + return this.#continueDecodeSimpleString.bind(this, [chunk.subarray(start)], type); } + const slice = chunk.subarray(start, crlfIndex); + return type === Buffer ? slice : slice.toString(); } - get prune() { - deprecatedMethod("prune", "purgeStale"); - return this.purgeStale; - } - purgeStale() { - let deleted = false; - for (const i2 of this.rindexes({ allowStale: true })) { - if (this.isStale(i2)) { - this.delete(this.keyList[i2]); - deleted = true; - } + #continueDecodeSimpleString(chunks, type, chunk) { + const start = this.#cursor, crlfIndex = this.#findCRLF(chunk, start); + if (crlfIndex === -1) { + chunks.push(chunk.subarray(start)); + return this.#continueDecodeSimpleString.bind(this, chunks, type); } - return deleted; + chunks.push(chunk.subarray(start, crlfIndex)); + const buffer = Buffer.concat(chunks); + return type === Buffer ? buffer : buffer.toString(); } - dump() { - const arr = []; - for (const i2 of this.indexes({ allowStale: true })) { - const key = this.keyList[i2]; - const v2 = this.valList[i2]; - const value = this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; - const entry = { value }; - if (this.ttls) { - entry.ttl = this.ttls[i2]; - const age = perf.now() - this.starts[i2]; - entry.start = Math.floor(Date.now() - age); - } - if (this.sizes) { - entry.size = this.sizes[i2]; - } - arr.unshift([key, entry]); + #decodeBlobString(type, chunk) { + if (chunk[this.#cursor] === ASCII["-"]) { + this.#cursor += 4; + return null; } - return arr; + const length2 = this.#decodeUnsingedNumber(0, chunk); + if (typeof length2 === "function") { + return this.#continueDecodeBlobStringLength.bind(this, length2, type); + } else if (this.#cursor >= chunk.length) { + return this.#decodeBlobStringWithLength.bind(this, length2, type); + } + return this.#decodeBlobStringWithLength(length2, type, chunk); } - load(arr) { - this.clear(); - for (const [key, entry] of arr) { - if (entry.start) { - const age = Date.now() - entry.start; - entry.start = perf.now() - age; - } - this.set(key, entry.value, entry); + #continueDecodeBlobStringLength(lengthCb, type, chunk) { + const length2 = lengthCb(chunk); + if (typeof length2 === "function") { + return this.#continueDecodeBlobStringLength.bind(this, length2, type); + } else if (this.#cursor >= chunk.length) { + return this.#decodeBlobStringWithLength.bind(this, length2, type); } + return this.#decodeBlobStringWithLength(length2, type, chunk); } - dispose(v2, k, reason) { + #decodeStringWithLength(length2, skip, type, chunk) { + const end = this.#cursor + length2; + if (end >= chunk.length) { + const slice2 = chunk.subarray(this.#cursor); + this.#cursor = chunk.length; + return this.#continueDecodeStringWithLength.bind(this, length2 - slice2.length, [slice2], skip, type); + } + const slice = chunk.subarray(this.#cursor, end); + this.#cursor = end + skip; + return type === Buffer ? slice : slice.toString(); } - set(k, v2, { - ttl = this.ttl, - start, - noDisposeOnSet = this.noDisposeOnSet, - size = 0, - sizeCalculation = this.sizeCalculation, - noUpdateTTL = this.noUpdateTTL - } = {}) { - size = this.requireSize(k, v2, size, sizeCalculation); - if (this.maxEntrySize && size > this.maxEntrySize) { - return this; + #continueDecodeStringWithLength(length2, chunks, skip, type, chunk) { + const end = this.#cursor + length2; + if (end >= chunk.length) { + const slice = chunk.subarray(this.#cursor); + chunks.push(slice); + this.#cursor = chunk.length; + return this.#continueDecodeStringWithLength.bind(this, length2 - slice.length, chunks, skip, type); } - let index = this.size === 0 ? void 0 : this.keyMap.get(k); - if (index === void 0) { - index = this.newIndex(); - this.keyList[index] = k; - this.valList[index] = v2; - this.keyMap.set(k, index); - this.next[this.tail] = index; - this.prev[index] = this.tail; - this.tail = index; - this.size++; - this.addItemSize(index, size); - noUpdateTTL = false; - } else { - const oldVal = this.valList[index]; - if (v2 !== oldVal) { - if (this.isBackgroundFetch(oldVal)) { - oldVal.__abortController.abort(); - } else { - if (!noDisposeOnSet) { - this.dispose(oldVal, k, "set"); - if (this.disposeAfter) { - this.disposed.push([oldVal, k, "set"]); - } - } - } - this.removeItemSize(index); - this.valList[index] = v2; - this.addItemSize(index, size); - } - this.moveToTail(index); + chunks.push(chunk.subarray(this.#cursor, end)); + this.#cursor = end + skip; + const buffer = Buffer.concat(chunks); + return type === Buffer ? buffer : buffer.toString(); + } + #decodeBlobStringWithLength(length2, type, chunk) { + return this.#decodeStringWithLength(length2, 2, type, chunk); + } + #decodeVerbatimString(type, chunk) { + return this.#continueDecodeVerbatimStringLength(this.#decodeUnsingedNumber.bind(this, 0), type, chunk); + } + #continueDecodeVerbatimStringLength(lengthCb, type, chunk) { + const length2 = lengthCb(chunk); + return typeof length2 === "function" ? this.#continueDecodeVerbatimStringLength.bind(this, length2, type) : this.#decodeVerbatimStringWithLength(length2, type, chunk); + } + #decodeVerbatimStringWithLength(length2, type, chunk) { + const stringLength = length2 - 4; + if (type === verbatim_string_1.VerbatimString) { + return this.#decodeVerbatimStringFormat(stringLength, chunk); } - if (ttl !== 0 && this.ttl === 0 && !this.ttls) { - this.initializeTTLTracking(); + this.#cursor += 4; + return this.#cursor >= chunk.length ? this.#decodeBlobStringWithLength.bind(this, stringLength, type) : this.#decodeBlobStringWithLength(stringLength, type, chunk); + } + #decodeVerbatimStringFormat(stringLength, chunk) { + const formatCb = this.#decodeStringWithLength.bind(this, 3, 1, String); + return this.#cursor >= chunk.length ? this.#continueDecodeVerbatimStringFormat.bind(this, stringLength, formatCb) : this.#continueDecodeVerbatimStringFormat(stringLength, formatCb, chunk); + } + #continueDecodeVerbatimStringFormat(stringLength, formatCb, chunk) { + const format52 = formatCb(chunk); + return typeof format52 === "function" ? this.#continueDecodeVerbatimStringFormat.bind(this, stringLength, format52) : this.#decodeVerbatimStringWithFormat(stringLength, format52, chunk); + } + #decodeVerbatimStringWithFormat(stringLength, format52, chunk) { + return this.#continueDecodeVerbatimStringWithFormat(format52, this.#decodeBlobStringWithLength.bind(this, stringLength, String), chunk); + } + #continueDecodeVerbatimStringWithFormat(format52, stringCb, chunk) { + const string3 = stringCb(chunk); + return typeof string3 === "function" ? this.#continueDecodeVerbatimStringWithFormat.bind(this, format52, string3) : new verbatim_string_1.VerbatimString(format52, string3); + } + #decodeSimpleError(chunk) { + const string3 = this.#decodeSimpleString(String, chunk); + return typeof string3 === "function" ? this.#continueDecodeSimpleError.bind(this, string3) : new errors_1.SimpleError(string3); + } + #continueDecodeSimpleError(stringCb, chunk) { + const string3 = stringCb(chunk); + return typeof string3 === "function" ? this.#continueDecodeSimpleError.bind(this, string3) : new errors_1.SimpleError(string3); + } + #decodeBlobError(chunk) { + const string3 = this.#decodeBlobString(String, chunk); + return typeof string3 === "function" ? this.#continueDecodeBlobError.bind(this, string3) : new errors_1.BlobError(string3); + } + #continueDecodeBlobError(stringCb, chunk) { + const string3 = stringCb(chunk); + return typeof string3 === "function" ? this.#continueDecodeBlobError.bind(this, string3) : new errors_1.BlobError(string3); + } + #decodeNestedType(typeMapping, chunk) { + const type = chunk[this.#cursor]; + return ++this.#cursor === chunk.length ? this.#decodeNestedTypeValue.bind(this, type, typeMapping) : this.#decodeNestedTypeValue(type, typeMapping, chunk); + } + #decodeNestedTypeValue(type, typeMapping, chunk) { + switch (type) { + case exports2.RESP_TYPES.NULL: + return this.#decodeNull(); + case exports2.RESP_TYPES.BOOLEAN: + return this.#decodeBoolean(chunk); + case exports2.RESP_TYPES.NUMBER: + return this.#decodeNumber(typeMapping[exports2.RESP_TYPES.NUMBER], chunk); + case exports2.RESP_TYPES.BIG_NUMBER: + return this.#decodeBigNumber(typeMapping[exports2.RESP_TYPES.BIG_NUMBER], chunk); + case exports2.RESP_TYPES.DOUBLE: + return this.#decodeDouble(typeMapping[exports2.RESP_TYPES.DOUBLE], chunk); + case exports2.RESP_TYPES.SIMPLE_STRING: + return this.#decodeSimpleString(typeMapping[exports2.RESP_TYPES.SIMPLE_STRING], chunk); + case exports2.RESP_TYPES.BLOB_STRING: + return this.#decodeBlobString(typeMapping[exports2.RESP_TYPES.BLOB_STRING], chunk); + case exports2.RESP_TYPES.VERBATIM_STRING: + return this.#decodeVerbatimString(typeMapping[exports2.RESP_TYPES.VERBATIM_STRING], chunk); + case exports2.RESP_TYPES.SIMPLE_ERROR: + return this.#decodeSimpleError(chunk); + case exports2.RESP_TYPES.BLOB_ERROR: + return this.#decodeBlobError(chunk); + case exports2.RESP_TYPES.ARRAY: + return this.#decodeArray(typeMapping, chunk); + case exports2.RESP_TYPES.SET: + return this.#decodeSet(typeMapping, chunk); + case exports2.RESP_TYPES.MAP: + return this.#decodeMap(typeMapping, chunk); + default: + throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`); } - if (!noUpdateTTL) { - this.setItemTTL(index, ttl, start); + } + #decodeArray(typeMapping, chunk) { + if (chunk[this.#cursor] === ASCII["-"]) { + this.#cursor += 4; + return null; } - if (this.disposeAfter) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); + return this.#decodeArrayWithLength(this.#decodeUnsingedNumber(0, chunk), typeMapping, chunk); + } + #decodeArrayWithLength(length2, typeMapping, chunk) { + return typeof length2 === "function" ? this.#continueDecodeArrayLength.bind(this, length2, typeMapping) : this.#decodeArrayItems(new Array(length2), 0, typeMapping, chunk); + } + #continueDecodeArrayLength(lengthCb, typeMapping, chunk) { + return this.#decodeArrayWithLength(lengthCb(chunk), typeMapping, chunk); + } + #decodeArrayItems(array2, filled, typeMapping, chunk) { + for (let i2 = filled; i2 < array2.length; i2++) { + if (this.#cursor >= chunk.length) { + return this.#decodeArrayItems.bind(this, array2, i2, typeMapping); + } + const item = this.#decodeNestedType(typeMapping, chunk); + if (typeof item === "function") { + return this.#continueDecodeArrayItems.bind(this, array2, i2, item, typeMapping); } + array2[i2] = item; } - return this; + return array2; } - newIndex() { - if (this.size === 0) { - return this.tail; - } - if (this.size === this.max && this.max !== 0) { - return this.evict(false); - } - if (this.free.length !== 0) { - return this.free.pop(); + #continueDecodeArrayItems(array2, filled, itemCb, typeMapping, chunk) { + const item = itemCb(chunk); + if (typeof item === "function") { + return this.#continueDecodeArrayItems.bind(this, array2, filled, item, typeMapping); } - return this.initialFill++; + array2[filled++] = item; + return this.#decodeArrayItems(array2, filled, typeMapping, chunk); } - pop() { - if (this.size) { - const val = this.valList[this.head]; - this.evict(true); - return val; + #decodeSet(typeMapping, chunk) { + const length2 = this.#decodeUnsingedNumber(0, chunk); + if (typeof length2 === "function") { + return this.#continueDecodeSetLength.bind(this, length2, typeMapping); } + return this.#decodeSetItems(length2, typeMapping, chunk); } - evict(free) { - const head = this.head; - const k = this.keyList[head]; - const v2 = this.valList[head]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(); - } else { - this.dispose(v2, k, "evict"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "evict"]); + #continueDecodeSetLength(lengthCb, typeMapping, chunk) { + const length2 = lengthCb(chunk); + return typeof length2 === "function" ? this.#continueDecodeSetLength.bind(this, length2, typeMapping) : this.#decodeSetItems(length2, typeMapping, chunk); + } + #decodeSetItems(length2, typeMapping, chunk) { + return typeMapping[exports2.RESP_TYPES.SET] === Set ? this.#decodeSetAsSet(/* @__PURE__ */ new Set(), length2, typeMapping, chunk) : this.#decodeArrayItems(new Array(length2), 0, typeMapping, chunk); + } + #decodeSetAsSet(set, remaining, typeMapping, chunk) { + while (remaining > 0) { + if (this.#cursor >= chunk.length) { + return this.#decodeSetAsSet.bind(this, set, remaining, typeMapping); } + const item = this.#decodeNestedType(typeMapping, chunk); + if (typeof item === "function") { + return this.#continueDecodeSetAsSet.bind(this, set, remaining, item, typeMapping); + } + set.add(item); + --remaining; } - this.removeItemSize(head); - if (free) { - this.keyList[head] = null; - this.valList[head] = null; - this.free.push(head); - } - this.head = this.next[head]; - this.keyMap.delete(k); - this.size--; - return head; + return set; } - has(k, { updateAgeOnHas = this.updateAgeOnHas } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0) { - if (!this.isStale(index)) { - if (updateAgeOnHas) { - this.updateItemAge(index); - } - return true; - } + #continueDecodeSetAsSet(set, remaining, itemCb, typeMapping, chunk) { + const item = itemCb(chunk); + if (typeof item === "function") { + return this.#continueDecodeSetAsSet.bind(this, set, remaining, item, typeMapping); } - return false; + set.add(item); + return this.#decodeSetAsSet(set, remaining - 1, typeMapping, chunk); } - // like get(), but without any LRU updating or TTL expiration - peek(k, { allowStale = this.allowStale } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0 && (allowStale || !this.isStale(index))) { - const v2 = this.valList[index]; - return this.isBackgroundFetch(v2) ? v2.__staleWhileFetching : v2; + #decodeMap(typeMapping, chunk) { + const length2 = this.#decodeUnsingedNumber(0, chunk); + if (typeof length2 === "function") { + return this.#continueDecodeMapLength.bind(this, length2, typeMapping); } + return this.#decodeMapItems(length2, typeMapping, chunk); } - backgroundFetch(k, index, options2, context) { - const v2 = index === void 0 ? void 0 : this.valList[index]; - if (this.isBackgroundFetch(v2)) { - return v2; + #continueDecodeMapLength(lengthCb, typeMapping, chunk) { + const length2 = lengthCb(chunk); + return typeof length2 === "function" ? this.#continueDecodeMapLength.bind(this, length2, typeMapping) : this.#decodeMapItems(length2, typeMapping, chunk); + } + #decodeMapItems(length2, typeMapping, chunk) { + switch (typeMapping[exports2.RESP_TYPES.MAP]) { + case Map: + return this.#decodeMapAsMap(/* @__PURE__ */ new Map(), length2, typeMapping, chunk); + case Array: + return this.#decodeArrayItems(new Array(length2 * 2), 0, typeMapping, chunk); + default: + return this.#decodeMapAsObject(/* @__PURE__ */ Object.create(null), length2, typeMapping, chunk); } - const ac = new AC(); - const fetchOpts = { - signal: ac.signal, - options: options2, - context - }; - const cb = (v3) => { - if (!ac.signal.aborted) { - this.set(k, v3, fetchOpts.options); + } + #decodeMapAsMap(map, remaining, typeMapping, chunk) { + while (remaining > 0) { + if (this.#cursor >= chunk.length) { + return this.#decodeMapAsMap.bind(this, map, remaining, typeMapping); } - return v3; - }; - const eb = (er) => { - if (this.valList[index] === p) { - const del = !options2.noDeleteOnFetchRejection || p.__staleWhileFetching === void 0; - if (del) { - this.delete(k); - } else { - this.valList[index] = p.__staleWhileFetching; - } + const key = this.#decodeMapKey(typeMapping, chunk); + if (typeof key === "function") { + return this.#continueDecodeMapKey.bind(this, map, remaining, key, typeMapping); } - if (p.__returned === p) { - throw er; + if (this.#cursor >= chunk.length) { + return this.#continueDecodeMapValue.bind(this, map, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); } - }; - const pcall = (res) => res(this.fetchMethod(k, v2, fetchOpts)); - const p = new Promise(pcall).then(cb, eb); - p.__abortController = ac; - p.__staleWhileFetching = v2; - p.__returned = null; - if (index === void 0) { - this.set(k, p, fetchOpts.options); - index = this.keyMap.get(k); - } else { - this.valList[index] = p; + const value = this.#decodeNestedType(typeMapping, chunk); + if (typeof value === "function") { + return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); + } + map.set(key, value); + --remaining; } - return p; + return map; } - isBackgroundFetch(p) { - return p && typeof p === "object" && typeof p.then === "function" && Object.prototype.hasOwnProperty.call( - p, - "__staleWhileFetching" - ) && Object.prototype.hasOwnProperty.call(p, "__returned") && (p.__returned === p || p.__returned === null); + #decodeMapKey(typeMapping, chunk) { + const type = chunk[this.#cursor]; + return ++this.#cursor === chunk.length ? this.#decodeMapKeyValue.bind(this, type, typeMapping) : this.#decodeMapKeyValue(type, typeMapping, chunk); } - // this takes the union of get() and set() opts, because it does both - async fetch(k, { - // get options - allowStale = this.allowStale, - updateAgeOnGet = this.updateAgeOnGet, - noDeleteOnStaleGet = this.noDeleteOnStaleGet, - // set options - ttl = this.ttl, - noDisposeOnSet = this.noDisposeOnSet, - size = 0, - sizeCalculation = this.sizeCalculation, - noUpdateTTL = this.noUpdateTTL, - // fetch exclusive options - noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, - fetchContext = this.fetchContext, - forceRefresh = false - } = {}) { - if (!this.fetchMethod) { - return this.get(k, { - allowStale, - updateAgeOnGet, - noDeleteOnStaleGet - }); + #decodeMapKeyValue(type, typeMapping, chunk) { + switch (type) { + // decode simple string map key as string (and not as buffer) + case exports2.RESP_TYPES.SIMPLE_STRING: + return this.#decodeSimpleString(String, chunk); + // decode blob string map key as string (and not as buffer) + case exports2.RESP_TYPES.BLOB_STRING: + return this.#decodeBlobString(String, chunk); + default: + return this.#decodeNestedTypeValue(type, typeMapping, chunk); } - const options2 = { - allowStale, - updateAgeOnGet, - noDeleteOnStaleGet, - ttl, - noDisposeOnSet, - size, - sizeCalculation, - noUpdateTTL, - noDeleteOnFetchRejection - }; - let index = this.keyMap.get(k); - if (index === void 0) { - const p = this.backgroundFetch(k, index, options2, fetchContext); - return p.__returned = p; - } else { - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - return allowStale && v2.__staleWhileFetching !== void 0 ? v2.__staleWhileFetching : v2.__returned = v2; + } + #continueDecodeMapKey(map, remaining, keyCb, typeMapping, chunk) { + const key = keyCb(chunk); + if (typeof key === "function") { + return this.#continueDecodeMapKey.bind(this, map, remaining, key, typeMapping); + } + if (this.#cursor >= chunk.length) { + return this.#continueDecodeMapValue.bind(this, map, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); + } + const value = this.#decodeNestedType(typeMapping, chunk); + if (typeof value === "function") { + return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); + } + map.set(key, value); + return this.#decodeMapAsMap(map, remaining - 1, typeMapping, chunk); + } + #continueDecodeMapValue(map, remaining, key, valueCb, typeMapping, chunk) { + const value = valueCb(chunk); + if (typeof value === "function") { + return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); + } + map.set(key, value); + return this.#decodeMapAsMap(map, remaining - 1, typeMapping, chunk); + } + #decodeMapAsObject(object2, remaining, typeMapping, chunk) { + while (remaining > 0) { + if (this.#cursor >= chunk.length) { + return this.#decodeMapAsObject.bind(this, object2, remaining, typeMapping); } - if (!forceRefresh && !this.isStale(index)) { - this.moveToTail(index); - if (updateAgeOnGet) { - this.updateItemAge(index); - } - return v2; + const key = this.#decodeMapKey(typeMapping, chunk); + if (typeof key === "function") { + return this.#continueDecodeMapAsObjectKey.bind(this, object2, remaining, key, typeMapping); } - const p = this.backgroundFetch(k, index, options2, fetchContext); - return allowStale && p.__staleWhileFetching !== void 0 ? p.__staleWhileFetching : p.__returned = p; + if (this.#cursor >= chunk.length) { + return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); + } + const value = this.#decodeNestedType(typeMapping, chunk); + if (typeof value === "function") { + return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); + } + object2[key] = value; + --remaining; } + return object2; } - get(k, { - allowStale = this.allowStale, - updateAgeOnGet = this.updateAgeOnGet, - noDeleteOnStaleGet = this.noDeleteOnStaleGet - } = {}) { - const index = this.keyMap.get(k); - if (index !== void 0) { - const value = this.valList[index]; - const fetching = this.isBackgroundFetch(value); - if (this.isStale(index)) { - if (!fetching) { - if (!noDeleteOnStaleGet) { - this.delete(k); - } - return allowStale ? value : void 0; - } else { - return allowStale ? value.__staleWhileFetching : void 0; - } - } else { - if (fetching) { - return void 0; - } - this.moveToTail(index); - if (updateAgeOnGet) { - this.updateItemAge(index); - } - return value; - } - } - } - connect(p, n) { - this.prev[n] = p; - this.next[p] = n; - } - moveToTail(index) { - if (index !== this.tail) { - if (index === this.head) { - this.head = this.next[index]; - } else { - this.connect(this.prev[index], this.next[index]); - } - this.connect(this.tail, index); - this.tail = index; + #continueDecodeMapAsObjectKey(object2, remaining, keyCb, typeMapping, chunk) { + const key = keyCb(chunk); + if (typeof key === "function") { + return this.#continueDecodeMapAsObjectKey.bind(this, object2, remaining, key, typeMapping); } - } - get del() { - deprecatedMethod("del", "delete"); - return this.delete; - } - delete(k) { - let deleted = false; - if (this.size !== 0) { - const index = this.keyMap.get(k); - if (index !== void 0) { - deleted = true; - if (this.size === 1) { - this.clear(); - } else { - this.removeItemSize(index); - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(); - } else { - this.dispose(v2, k, "delete"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "delete"]); - } - } - this.keyMap.delete(k); - this.keyList[index] = null; - this.valList[index] = null; - if (index === this.tail) { - this.tail = this.prev[index]; - } else if (index === this.head) { - this.head = this.next[index]; - } else { - this.next[this.prev[index]] = this.next[index]; - this.prev[this.next[index]] = this.prev[index]; - } - this.size--; - this.free.push(index); - } - } + if (this.#cursor >= chunk.length) { + return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); } - if (this.disposed) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); - } + const value = this.#decodeNestedType(typeMapping, chunk); + if (typeof value === "function") { + return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); } - return deleted; + object2[key] = value; + return this.#decodeMapAsObject(object2, remaining - 1, typeMapping, chunk); } - clear() { - for (const index of this.rindexes({ allowStale: true })) { - const v2 = this.valList[index]; - if (this.isBackgroundFetch(v2)) { - v2.__abortController.abort(); - } else { - const k = this.keyList[index]; - this.dispose(v2, k, "delete"); - if (this.disposeAfter) { - this.disposed.push([v2, k, "delete"]); - } - } - } - this.keyMap.clear(); - this.valList.fill(null); - this.keyList.fill(null); - if (this.ttls) { - this.ttls.fill(0); - this.starts.fill(0); - } - if (this.sizes) { - this.sizes.fill(0); - } - this.head = 0; - this.tail = 0; - this.initialFill = 1; - this.free.length = 0; - this.calculatedSize = 0; - this.size = 0; - if (this.disposed) { - while (this.disposed.length) { - this.disposeAfter(...this.disposed.shift()); - } + #continueDecodeMapAsObjectValue(object2, remaining, key, valueCb, typeMapping, chunk) { + const value = valueCb(chunk); + if (typeof value === "function") { + return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); } - } - get reset() { - deprecatedMethod("reset", "clear"); - return this.clear; - } - get length() { - deprecatedProperty("length", "size"); - return this.size; - } - static get AbortController() { - return AC; - } - static get AbortSignal() { - return AS; + object2[key] = value; + return this.#decodeMapAsObject(object2, remaining - 1, typeMapping, chunk); } }; - module14.exports = LRUCache; + exports2.Decoder = Decoder2; + _a2 = Decoder2; } }); -var BackendErrorNotFound; -var BackendErrorGone; -var BackendErrorBadData; -var BackendErrorConflict; -var init_errors4 = __esm({ - "src/serve/errors.ts"() { +var require_lua_script = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/lua-script.js"(exports2) { "use strict"; - init_errors3(); - BackendErrorNotFound = ChelErrorGenerator("BackendErrorNotFound"); - BackendErrorGone = ChelErrorGenerator("BackendErrorGone"); - BackendErrorBadData = ChelErrorGenerator("BackendErrorBadData"); - BackendErrorConflict = ChelErrorGenerator("BackendErrorConflict"); + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.scriptSha1 = exports2.defineScript = void 0; + var node_crypto_1 = __require2("node:crypto"); + function defineScript(script) { + return { + ...script, + SHA1: scriptSha1(script.SCRIPT) + }; + } + exports2.defineScript = defineScript; + function scriptSha1(script) { + return (0, node_crypto_1.createHash)("sha1").update(script).digest("hex"); + } + exports2.scriptSha1 = scriptSha1; } }); -var SERVER_EXITING; -var SERVER_RUNNING; -var init_events2 = __esm({ - "src/serve/events.ts"() { +var require_ACL_CAT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_CAT.js"(exports2) { "use strict"; - SERVER_EXITING = "server-exiting"; - SERVER_RUNNING = "server-running"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Lists ACL categories or commands in a category + * @param parser - The Redis command parser + * @param categoryName - Optional category name to filter commands + */ + parseCommand(parser3, categoryName) { + parser3.push("ACL", "CAT"); + if (categoryName) { + parser3.push(categoryName); + } + }, + transformReply: void 0 + }; } }); -var import_npm_nconf; -var vapidPublicKey; -var vapidPrivateKey; -var vapid; -var initVapid; -var generateJwt; -var getVapidPublicKey; -var vapidAuthorization; -var init_vapid = __esm({ - "src/serve/vapid.ts"() { +var require_ACL_DELUSER = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_DELUSER.js"(exports2) { "use strict"; - init_esm(); - import_npm_nconf = __toESM(require_nconf()); - initVapid = async () => { - const vapidEmail = import_npm_nconf.default.get("server:vapid:email"); - if (!vapidEmail) { - console.warn('Missing VAPID identification. Please set `server:vapid:email` to a value like "some@domain.example".'); - } - vapid = { VAPID_EMAIL: vapidEmail?.replace(/^mailto:/i, "") || "test@example.com" }; - const vapidKeyPair = await esm_default("chelonia.db/get", "_private_immutable_vapid_key").then(async (vapidKeyPair2) => { - if (!vapidKeyPair2) { - console.info("Generating new VAPID keypair..."); - const keyPair = await crypto.subtle.generateKey( - { - name: "ECDSA", - namedCurve: "P-256" - // Use P-256 curve - }, - true, - // Whether the key is extractable - ["sign", "verify"] - // Usages - ); - const serializedKeyPair2 = await Promise.all([ - crypto.subtle.exportKey("jwk", keyPair.privateKey), - crypto.subtle.exportKey("raw", keyPair.publicKey).then( - (key) => Buffer7.from(key).toString("base64url") - ) - ]); - return esm_default("chelonia.db/set", "_private_immutable_vapid_key", JSON.stringify(serializedKeyPair2)).then(() => { - console.info("Successfully saved newly generated VAPID keys"); - return [keyPair.privateKey, serializedKeyPair2[1]]; - }); - } - const serializedKeyPair = JSON.parse(vapidKeyPair2); - return [ - await crypto.subtle.importKey( - "jwk", - serializedKeyPair[0], - { name: "ECDSA", namedCurve: "P-256" }, - false, - ["sign"] - ), - serializedKeyPair[1] - ]; - }); - vapidPrivateKey = vapidKeyPair[0]; - vapidPublicKey = vapidKeyPair[1]; - }; - generateJwt = async (endpoint) => { - const now = Date.now() / 1e3 | 0; - const audience = endpoint.origin; - const header = Buffer7.from(JSON.stringify( - Object.fromEntries([["typ", "JWT"], ["alg", "ES256"]]) - )).toString("base64url"); - const body = Buffer7.from(JSON.stringify( - // We're expecting to use the JWT immediately. We set a 10-minute window - // for using the JWT (5 minutes into the past, 5 minutes into the future) - // to account for potential network delays and clock drift. - Object.fromEntries([ - // token audience - ["aud", audience], - // 'expiry' / 'not after' value for the token - ["exp", now + 300], - // (optional) issuance time for the token - ["iat", now], - // 'not before' value for the JWT - ["nbf", now - 300], - // URI used for identifying ourselves. This can be used by the push - // provider to get in touch in case of issues. - ["sub", `mailto:${vapid.VAPID_EMAIL}`] - ]) - )).toString("base64url"); - const signature = Buffer7.from( - await crypto.subtle.sign( - { name: "ECDSA", hash: "SHA-256" }, - vapidPrivateKey, - Buffer7.from([header, body].join(".")) - ) - ).toString("base64url"); - return [header, body, signature].join("."); - }; - getVapidPublicKey = () => vapidPublicKey; - vapidAuthorization = async (endpoint) => { - const jwt = await generateJwt(endpoint); - return `vapid t=${jwt}, k=${vapidPublicKey}`; - }; - } -}); -var AUTHSALT; -var CONTRACTSALT; -var CS; -var SU; -var SALT_LENGTH_IN_OCTETS; -var init_zkppConstants = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/zkppConstants.mjs"() { - AUTHSALT = "AUTHSALT"; - CONTRACTSALT = "CONTRACTSALT"; - CS = "CS"; - SU = "SU"; - SALT_LENGTH_IN_OCTETS = 24; - } -}); -var import_scrypt_async2; -var import_tweetnacl2; -var base64ToBase64url; -var base64urlToBase64; -var hashStringArray; -var hashRawStringArray; -var randomNonce; -var hash2; -var computeCAndHc; -var encryptContractSalt; -var encryptSaltUpdate; -var decryptSaltUpdate; -var boxKeyPair; -var saltAgreement; -var parseRegisterSalt; -var init_zkpp = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/zkpp.mjs"() { - import_scrypt_async2 = __toESM(require_scrypt_async(), 1); - import_tweetnacl2 = __toESM(require_nacl_fast(), 1); - init_zkppConstants(); - base64ToBase64url = (s) => s.replace(/\//g, "_").replace(/\+/g, "-").replace(/=*$/, ""); - base64urlToBase64 = (s) => s.replace(/_/g, "/").replace(/-/g, "+") + "=".repeat((4 - s.length % 4) % 4); - hashStringArray = (...args) => { - return import_tweetnacl2.default.hash(Buffer8.concat(args.map((s) => import_tweetnacl2.default.hash(Buffer8.from(s))))); - }; - hashRawStringArray = (...args) => { - return import_tweetnacl2.default.hash(Buffer8.concat(args.map((s) => Buffer8.from(s)))); - }; - randomNonce = () => { - return base64ToBase64url(Buffer8.from(import_tweetnacl2.default.randomBytes(12)).toString("base64")); - }; - hash2 = (v2) => { - return base64ToBase64url(Buffer8.from(import_tweetnacl2.default.hash(Buffer8.from(v2))).toString("base64")); - }; - computeCAndHc = (r, s, h2) => { - const \u0127 = hashStringArray(r, s); - const c = hashStringArray(h2, \u0127); - const hc = import_tweetnacl2.default.hash(c); - return [c, hc]; - }; - encryptContractSalt = (c, contractSalt) => { - const encryptionKey = hashRawStringArray(CS, c).slice(0, import_tweetnacl2.default.secretbox.keyLength); - const nonce = import_tweetnacl2.default.randomBytes(import_tweetnacl2.default.secretbox.nonceLength); - const encryptedContractSalt = import_tweetnacl2.default.secretbox(Buffer8.from(contractSalt), nonce, encryptionKey); - return base64ToBase64url(Buffer8.concat([nonce, encryptedContractSalt]).toString("base64")); - }; - encryptSaltUpdate = (secret, recordId, record2) => { - const nonce = import_tweetnacl2.default.randomBytes(import_tweetnacl2.default.secretbox.nonceLength); - const encryptionKey = hashRawStringArray(SU, secret, nonce, recordId).slice(0, import_tweetnacl2.default.secretbox.keyLength); - const encryptedRecord = import_tweetnacl2.default.secretbox(Buffer8.from(record2), nonce, encryptionKey); - return base64ToBase64url(Buffer8.concat([nonce, encryptedRecord]).toString("base64")); - }; - decryptSaltUpdate = (secret, recordId, encryptedRecordBox) => { - const encryptedRecordBoxBuf = Buffer8.from(base64urlToBase64(encryptedRecordBox), "base64"); - const nonce = encryptedRecordBoxBuf.subarray(0, import_tweetnacl2.default.secretbox.nonceLength); - const encryptionKey = hashRawStringArray(SU, secret, nonce, recordId).slice(0, import_tweetnacl2.default.secretbox.keyLength); - const encryptedRecord = encryptedRecordBoxBuf.subarray(import_tweetnacl2.default.secretbox.nonceLength); - const decrypted = import_tweetnacl2.default.secretbox.open(encryptedRecord, nonce, encryptionKey); - if (!decrypted) - throw new Error("Failed to decrypt salt update"); - return Buffer8.from(decrypted).toString(); - }; - boxKeyPair = () => { - return import_tweetnacl2.default.box.keyPair(); - }; - saltAgreement = (publicKey, secretKey) => { - const publicKeyBuf = Buffer8.from(base64urlToBase64(publicKey), "base64"); - const dhKey = import_tweetnacl2.default.box.before(publicKeyBuf, secretKey); - if (!publicKeyBuf || publicKeyBuf.byteLength !== import_tweetnacl2.default.box.publicKeyLength) { - return false; - } - const authSalt = Buffer8.from(hashStringArray(AUTHSALT, dhKey)).subarray(0, SALT_LENGTH_IN_OCTETS).toString("base64"); - const contractSalt = Buffer8.from(hashStringArray(CONTRACTSALT, dhKey)).subarray(0, SALT_LENGTH_IN_OCTETS).toString("base64"); - return [authSalt, contractSalt]; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Deletes one or more users from the ACL + * @param parser - The Redis command parser + * @param username - Username(s) to delete + */ + parseCommand(parser3, username) { + parser3.push("ACL", "DELUSER"); + parser3.pushVariadic(username); + }, + transformReply: void 0 }; - parseRegisterSalt = (publicKey, secretKey, encryptedHashedPassword) => { - const saltAgreementRes = saltAgreement(publicKey, secretKey); - if (!saltAgreementRes) { - return false; - } - const [authSalt, contractSalt] = saltAgreementRes; - const encryptionKey = import_tweetnacl2.default.hash(Buffer8.from(authSalt + contractSalt)).slice(0, import_tweetnacl2.default.secretbox.keyLength); - const encryptedHashedPasswordBuf = Buffer8.from(base64urlToBase64(encryptedHashedPassword), "base64"); - const hashedPasswordBuf = import_tweetnacl2.default.secretbox.open(encryptedHashedPasswordBuf.subarray(import_tweetnacl2.default.box.nonceLength), encryptedHashedPasswordBuf.subarray(0, import_tweetnacl2.default.box.nonceLength), encryptionKey); - if (!hashedPasswordBuf) { - return false; - } - return [authSalt, contractSalt, hashedPasswordBuf, encryptionKey]; + } +}); +var require_ACL_DRYRUN = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_DRYRUN.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Simulates ACL operations without executing them + * @param parser - The Redis command parser + * @param username - Username to simulate ACL operations for + * @param command - Command arguments to simulate + */ + parseCommand(parser3, username, command2) { + parser3.push("ACL", "DRYRUN", username, ...command2); + }, + transformReply: void 0 }; } }); -var import_npm_tweetnacl; -var nacl3; -var recordSecret; -var challengeSecret; -var registrationSecret; -var hashUpdateSecret; -var initZkpp; -var maxAge; -var computeZkppSaltRecordId; -var getZkppSaltRecord; -var setZkppSaltRecord; -var getChallenge; -var verifyChallenge; -var registrationKey; -var register; -var contractSaltVerifyC; -var getContractSalt; -var updateContractSalt; -var redeemSaltRegistrationToken; -var redeemSaltUpdateToken; -var init_zkppSalt = __esm({ - "src/serve/zkppSalt.ts"() { - "use strict"; - init_zkpp(); - init_zkppConstants(); - init_esm(); - import_npm_tweetnacl = __toESM(require_nacl_fast()); - nacl3 = import_npm_tweetnacl.default; - initZkpp = async () => { - const IKM = await esm_default("chelonia.db/get", "_private_immutable_zkpp_ikm").then((IKM2) => { - if (!IKM2) { - const secret = randomBytes2(33).toString("base64"); - return esm_default("chelonia.db/set", "_private_immutable_zkpp_ikm", secret).then(() => { - return secret; - }); - } - return IKM2; - }); - recordSecret = Buffer9.from(hashStringArray("private/recordSecret", IKM)).toString("base64"); - challengeSecret = Buffer9.from(hashStringArray("private/challengeSecret", IKM)).toString("base64"); - registrationSecret = Buffer9.from(hashStringArray("private/registrationSecret", IKM)).toString("base64"); - hashUpdateSecret = Buffer9.from(hashStringArray("private/hashUpdateSecret", IKM)).toString("base64"); - }; - maxAge = 30; - computeZkppSaltRecordId = async (contractID) => { - const recordId = `_private_rid_${contractID}`; - const record2 = await esm_default("chelonia.db/get", recordId); - if (!record2) { - return null; - } - const recordBuf = Buffer9.concat([Buffer9.from(contractID), Buffer9.from(record2)]); - return hash2(recordBuf); - }; - getZkppSaltRecord = async (contractID) => { - const recordId = `_private_rid_${contractID}`; - const record2 = await esm_default("chelonia.db/get", recordId); - if (record2) { - const encryptionKey = hashStringArray("REK", contractID, recordSecret).slice(0, nacl3.secretbox.keyLength); - const recordBuf = Buffer9.from(base64urlToBase64(record2), "base64"); - const nonce = recordBuf.slice(0, nacl3.secretbox.nonceLength); - const recordCiphertext = recordBuf.slice(nacl3.secretbox.nonceLength); - const recordPlaintext = nacl3.secretbox.open(recordCiphertext, nonce, encryptionKey); - if (!recordPlaintext) { - return null; - } - const recordString = Buffer9.from(recordPlaintext).toString("utf-8"); - try { - const recordObj = JSON.parse(recordString); - if (!Array.isArray(recordObj) || recordObj.length !== 3 && recordObj.length !== 4 || recordObj.slice(0, 3).some((r) => !r || typeof r !== "string") || recordObj[3] != null && typeof recordObj[3] !== "string") { - console.error("Error validating encrypted JSON object " + recordId); - return null; - } - const [hashedPassword, authSalt, contractSalt, cid] = recordObj; - return { - hashedPassword, - authSalt, - contractSalt, - cid - }; - } catch { - console.error("Error parsing encrypted JSON object " + recordId); +var require_ACL_GENPASS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_GENPASS.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Generates a secure password for ACL users + * @param parser - The Redis command parser + * @param bits - Optional number of bits for password entropy + */ + parseCommand(parser3, bits) { + parser3.push("ACL", "GENPASS"); + if (bits) { + parser3.push(bits.toString()); } - } - return null; + }, + transformReply: void 0 }; - setZkppSaltRecord = async (contractID, hashedPassword, authSalt, contractSalt, cid) => { - const recordId = `_private_rid_${contractID}`; - const encryptionKey = hashStringArray("REK", contractID, recordSecret).slice(0, nacl3.secretbox.keyLength); - const nonce = nacl3.randomBytes(nacl3.secretbox.nonceLength); - const recordPlaintext = JSON.stringify([hashedPassword, authSalt, contractSalt, cid]); - const recordCiphertext = nacl3.secretbox(Buffer9.from(recordPlaintext), nonce, encryptionKey); - const recordBuf = Buffer9.concat([nonce, recordCiphertext]); - const record2 = base64ToBase64url(recordBuf.toString("base64")); - await esm_default("chelonia.db/set", recordId, record2); - }; - getChallenge = async (contract, b) => { - const record2 = await getZkppSaltRecord(contract); - if (!record2) { - console.debug("getChallenge: Error obtaining ZKPP salt record for contract ID " + contract); - return false; + } +}); +var require_ACL_GETUSER = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_GETUSER.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Returns ACL information about a specific user + * @param parser - The Redis command parser + * @param username - Username to get information for + */ + parseCommand(parser3, username) { + parser3.push("ACL", "GETUSER", username); + }, + transformReply: { + 2: (reply) => ({ + flags: reply[1], + passwords: reply[3], + commands: reply[5], + keys: reply[7], + channels: reply[9], + selectors: reply[11]?.map((selector) => { + const inferred = selector; + return { + commands: inferred[1], + keys: inferred[3], + channels: inferred[5] + }; + }) + }), + 3: void 0 } - const { authSalt } = record2; - const s = randomNonce(); - const now = (Date.now() / 1e3 | 0).toString(16); - const sig = [now, base64ToBase64url(Buffer9.from(hashStringArray(contract, b, s, now, challengeSecret)).toString("base64"))].join(","); - return { - authSalt, - s, - sig - }; }; - verifyChallenge = (contractID, r, s, userSig) => { - if (!/^[a-fA-F0-9]{1,11},[a-zA-Z0-9_-]{86}(?:==)?$/.test(userSig)) { - console.info(`wrong signature format for challenge for contract: ${contractID}`); - return false; - } - const [then, mac] = userSig.split(","); - const now = Date.now() / 1e3 | 0; - const iThen = Number.parseInt(then, 16); - if (!(iThen <= now) || !(iThen >= now - maxAge)) { - return false; - } - const b = hash2(r); - const sig = hashStringArray(contractID, b, s, then, challengeSecret); - const macBuf = Buffer9.from(base64urlToBase64(mac), "base64"); - return sig.byteLength === macBuf.byteLength && timingSafeEqual(sig, macBuf); - }; - registrationKey = (provisionalId, b) => { - const encryptionKey = hashStringArray("REG", provisionalId, registrationSecret).slice(0, nacl3.secretbox.keyLength); - const nonce = nacl3.randomBytes(nacl3.secretbox.nonceLength); - const keyPair = boxKeyPair(); - const s = base64ToBase64url(Buffer9.concat([nonce, nacl3.secretbox(keyPair.secretKey, nonce, encryptionKey)]).toString("base64")); - const now = (Date.now() / 1e3 | 0).toString(16); - const sig = [now, base64ToBase64url(Buffer9.from(hashStringArray(provisionalId, b, s, now, challengeSecret)).toString("base64"))].join(","); - return { - s, - p: base64ToBase64url(Buffer9.from(keyPair.publicKey).toString("base64")), - sig - }; + } +}); +var require_ACL_LIST = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LIST.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Returns all configured ACL users and their permissions + * @param parser - The Redis command parser + */ + parseCommand(parser3) { + parser3.push("ACL", "LIST"); + }, + transformReply: void 0 }; - register = (provisionalId, clientPublicKey, encryptedSecretKey, userSig, encryptedHashedPassword) => { - if (!verifyChallenge(provisionalId, clientPublicKey, encryptedSecretKey, userSig)) { - console.warn("register: Error validating challenge: " + JSON.stringify({ contract: provisionalId, clientPublicKey, userSig })); - throw new Error("register: Invalid challenge"); - } - const encryptedSecretKeyBuf = Buffer9.from(base64urlToBase64(encryptedSecretKey), "base64"); - const encryptionKey = hashStringArray("REG", provisionalId, registrationSecret).slice(0, nacl3.secretbox.keyLength); - const secretKeyBuf = nacl3.secretbox.open(encryptedSecretKeyBuf.slice(nacl3.secretbox.nonceLength), encryptedSecretKeyBuf.slice(0, nacl3.secretbox.nonceLength), encryptionKey); - if (!secretKeyBuf) { - console.warn(`register: Error decrypting arguments for contract ID ${provisionalId} (${JSON.stringify({ clientPublicKey, userSig })})`); - return false; - } - const parseRegisterSaltRes = parseRegisterSalt(clientPublicKey, secretKeyBuf, encryptedHashedPassword); - if (!parseRegisterSaltRes) { - console.warn(`register: Error parsing registration salt for contract ID ${provisionalId} (${JSON.stringify({ clientPublicKey, userSig })})`); - return false; - } - const [authSalt, contractSalt, hashedPasswordBuf, sharedEncryptionKey] = parseRegisterSaltRes; - const token = encryptSaltUpdate( - hashUpdateSecret, - provisionalId, - JSON.stringify([Date.now(), Buffer9.from(hashedPasswordBuf).toString(), authSalt, contractSalt]) - ); - return encryptContractSalt(sharedEncryptionKey, token); + } +}); +var require_ACL_LOAD = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOAD.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Reloads ACL configuration from the ACL file + * @param parser - The Redis command parser + */ + parseCommand(parser3) { + parser3.push("ACL", "LOAD"); + }, + transformReply: void 0 }; - contractSaltVerifyC = (h2, r, s, userHc) => { - const [c, hc] = computeCAndHc(r, s, h2); - const userHcBuf = Buffer9.from(base64urlToBase64(userHc), "base64"); - if (hc.byteLength === userHcBuf.byteLength && timingSafeEqual(hc, userHcBuf)) { - return c; + } +}); +var require_parser = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/client/parser.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.BasicCommandParser = void 0; + var BasicCommandParser = class { + #redisArgs = []; + #keys = []; + preserve; + get redisArgs() { + return this.#redisArgs; } - return false; - }; - getContractSalt = async (contract, r, s, sig, hc) => { - if (!verifyChallenge(contract, r, s, sig)) { - console.debug("getContractSalt: Error validating challenge: " + JSON.stringify({ contract, r, s, sig })); - throw new Error("getContractSalt: Bad challenge"); + get keys() { + return this.#keys; } - const record2 = await getZkppSaltRecord(contract); - if (!record2) { - console.error("getContractSalt: Error obtaining ZKPP salt record for contract ID " + contract); - return false; + get firstKey() { + return this.#keys[0]; } - const { hashedPassword, contractSalt, cid } = record2; - const c = contractSaltVerifyC(hashedPassword, r, s, hc); - if (!c) { - console.error(`getContractSalt: Error verifying challenge for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); - throw new Error("getContractSalt: Bad challenge"); + get cacheKey() { + const tmp = new Array(this.#redisArgs.length * 2); + for (let i2 = 0; i2 < this.#redisArgs.length; i2++) { + tmp[i2] = this.#redisArgs[i2].length; + tmp[i2 + this.#redisArgs.length] = this.#redisArgs[i2]; + } + return tmp.join("_"); } - return encryptContractSalt(c, JSON.stringify([contractSalt, cid])); - }; - updateContractSalt = async (contract, r, s, sig, hc, encryptedArgs) => { - if (!verifyChallenge(contract, r, s, sig)) { - console.warn("update: Error validating challenge: " + JSON.stringify({ contract, r, s, sig })); - throw new Error("update: Bad challenge"); + push(...arg) { + this.#redisArgs.push(...arg); } - const record2 = await getZkppSaltRecord(contract); - if (!record2) { - console.error("update: Error obtaining ZKPP salt record for contract ID " + contract); - return false; + pushVariadic(vals) { + if (Array.isArray(vals)) { + for (const val of vals) { + this.push(val); + } + } else { + this.push(vals); + } } - const { hashedPassword, contractSalt: oldContractSalt } = record2; - const c = contractSaltVerifyC(hashedPassword, r, s, hc); - if (!c) { - console.error(`update: Error verifying challenge for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); - throw new Error("update: Bad challenge"); - } - const encryptionKey = hashRawStringArray(SU, c).slice(0, nacl3.secretbox.keyLength); - const encryptedArgsBuf = Buffer9.from(base64urlToBase64(encryptedArgs), "base64"); - const nonce = encryptedArgsBuf.slice(0, nacl3.secretbox.nonceLength); - const encryptedArgsCiphertext = encryptedArgsBuf.slice(nacl3.secretbox.nonceLength); - const args = nacl3.secretbox.open(encryptedArgsCiphertext, nonce, encryptionKey); - if (!args) { - console.error(`update: Error decrypting arguments for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); - return false; + pushVariadicWithLength(vals) { + if (Array.isArray(vals)) { + this.#redisArgs.push(vals.length.toString()); + } else { + this.#redisArgs.push("1"); + } + this.pushVariadic(vals); } - try { - const hashedPassword2 = Buffer9.from(args).toString(); - const recordId = await computeZkppSaltRecordId(contract); - if (!recordId) { - console.error(`update: Error obtaining record ID for contract ID ${contract}`); - return false; + pushVariadicNumber(vals) { + if (Array.isArray(vals)) { + for (const val of vals) { + this.push(val.toString()); + } + } else { + this.push(vals.toString()); } - const authSalt = Buffer9.from(hashStringArray(AUTHSALT, c)).slice(0, SALT_LENGTH_IN_OCTETS).toString("base64"); - const contractSalt = Buffer9.from(hashStringArray(CONTRACTSALT, c)).slice(0, SALT_LENGTH_IN_OCTETS).toString("base64"); - const token = encryptSaltUpdate( - hashUpdateSecret, - recordId, - JSON.stringify([Date.now(), hashedPassword2, authSalt, contractSalt]) - ); - return encryptContractSalt(c, JSON.stringify([oldContractSalt, token])); - } catch { - console.error(`update: Error parsing encrypted arguments for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); } - return false; - }; - redeemSaltRegistrationToken = async (provisoryRegistrationKey, contract, token) => { - const decryptedToken = decryptSaltUpdate( - hashUpdateSecret, - provisoryRegistrationKey, - token - ); - const [timestamp, hashedPassword, authSalt, contractSalt] = JSON.parse(decryptedToken); - if (timestamp < Date.now() - 18e4) { - throw new Error("ZKPP token expired"); + pushKey(key) { + this.#keys.push(key); + this.#redisArgs.push(key); } - await setZkppSaltRecord(contract, hashedPassword, authSalt, contractSalt); - }; - redeemSaltUpdateToken = async (contract, token) => { - const recordId = await computeZkppSaltRecordId(contract); - if (!recordId) { - throw new Error("Record ID not found"); + pushKeysLength(keys) { + if (Array.isArray(keys)) { + this.#redisArgs.push(keys.length.toString()); + } else { + this.#redisArgs.push("1"); + } + this.pushKeys(keys); } - const decryptedToken = decryptSaltUpdate( - hashUpdateSecret, - recordId, - token - ); - const [timestamp, hashedPassword, authSalt, contractSalt] = JSON.parse(decryptedToken); - if (timestamp < Date.now() - 18e4) { - throw new Error("ZKPP token expired"); + pushKeys(keys) { + if (Array.isArray(keys)) { + this.#keys.push(...keys); + this.#redisArgs.push(...keys); + } else { + this.#keys.push(keys); + this.#redisArgs.push(keys); + } } - return (cid) => { - return setZkppSaltRecord(contract, hashedPassword, authSalt, contractSalt, cid); - }; }; + exports2.BasicCommandParser = BasicCommandParser; } }); -function namespaceKey(name) { - return "name=" + name; -} -var KEYOP_SEGMENT_LENGTH; -var updateSize; -var appendToIndexFactory; -var appendToNamesIndex; -var removeFromIndexFactory; -var lookupUltimateOwner; -var init_db_utils = __esm({ - "src/serve/db-utils.ts"() { +var require_generic_transformers = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/generic-transformers.js"(exports2) { "use strict"; - init_esm(); - KEYOP_SEGMENT_LENGTH = 1e4; - updateSize = async (resourceID, sizeKey, size, skipIfDeleted) => { - if (!Number.isSafeInteger(size)) { - throw new TypeError(`Invalid given size ${size} for ${resourceID}`); - } - await esm_default("okTurtles.eventQueue/queueEvent", sizeKey, async () => { - const storedSize = await esm_default("chelonia.db/get", sizeKey, { bypassCache: true }); - if (skipIfDeleted && storedSize == null) return; - const existingSize = parseInt(storedSize ?? "0", 10); - if (!(existingSize >= 0)) { - throw new TypeError(`Invalid stored size ${existingSize} for ${resourceID}`); - } - const updatedSize = existingSize + size; - if (!(updatedSize >= 0)) { - throw new TypeError(`Invalid stored updated size ${updatedSize} for ${resourceID}`); - } - await esm_default("chelonia.db/set", sizeKey, updatedSize.toString(10)); - }); - }; - appendToIndexFactory = (key) => { - return (value) => { - return esm_default("okTurtles.eventQueue/queueEvent", key, async () => { - const currentIndex = await esm_default("chelonia.db/get", key, { bypassCache: true }); - if (currentIndex) { - if ( - // Check if the value is at the end - currentIndex.endsWith("\0" + value) || // Check if the value is at the start - currentIndex.startsWith(value + "\0") || // Check if the current index is exactly the value - currentIndex === value || // Check if the value is in the middle - currentIndex.includes("\0" + value + "\0") - ) { - return; - } - await esm_default("chelonia.db/set", key, `${currentIndex}\0${value}`); - return; - } - await esm_default("chelonia.db/set", key, value); - }); - }; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.transformRedisJsonNullReply = exports2.transformRedisJsonReply = exports2.transformRedisJsonArgument = exports2.transformStreamsMessagesReplyResp3 = exports2.transformStreamsMessagesReplyResp2 = exports2.transformStreamMessagesReply = exports2.transformStreamMessageNullReply = exports2.transformStreamMessageReply = exports2.parseArgs = exports2.parseZKeysArguments = exports2.transformRangeReply = exports2.parseSlotRangesArguments = exports2.transformFunctionListItemReply = exports2.RedisFunctionFlags = exports2.transformCommandReply = exports2.CommandCategories = exports2.CommandFlags = exports2.parseOptionalVariadicArgument = exports2.pushVariadicArgument = exports2.pushVariadicNumberArguments = exports2.pushVariadicArguments = exports2.pushEvalArguments = exports2.evalFirstKeyIndex = exports2.transformPXAT = exports2.transformEXAT = exports2.transformSortedSetReply = exports2.transformTuplesReply = exports2.createTransformTuplesReplyFunc = exports2.transformTuplesToMap = exports2.transformNullableDoubleReply = exports2.createTransformNullableDoubleReplyResp2Func = exports2.transformDoubleArrayReply = exports2.createTransformDoubleReplyResp2Func = exports2.transformDoubleReply = exports2.transformStringDoubleArgument = exports2.transformDoubleArgument = exports2.transformBooleanArrayReply = exports2.transformBooleanReply = exports2.isArrayReply = exports2.isNullReply = void 0; + var parser_1 = require_parser(); + var decoder_1 = require_decoder(); + function isNullReply(reply) { + return reply === null; + } + exports2.isNullReply = isNullReply; + function isArrayReply(reply) { + return Array.isArray(reply); + } + exports2.isArrayReply = isArrayReply; + exports2.transformBooleanReply = { + 2: (reply) => reply === 1, + 3: void 0 }; - appendToNamesIndex = appendToIndexFactory("_private_names_index"); - removeFromIndexFactory = (key) => { - return (values) => { - return esm_default("okTurtles.eventQueue/queueEvent", key, async () => { - let existingEntries = await esm_default("chelonia.db/get", key, { bypassCache: true }); - if (!existingEntries) return; - if (!Array.isArray(values)) { - values = [values]; - } - for (const value of values) { - if (existingEntries.endsWith("\0" + value)) { - existingEntries = existingEntries.slice(0, -value.length - 1); - continue; - } - if (existingEntries.startsWith(value + "\0")) { - existingEntries = existingEntries.slice(value.length + 1); - continue; - } - if (existingEntries === value) { - existingEntries = void 0; - break; - } - const entryIndex = existingEntries.indexOf("\0" + value + "\0"); - if (entryIndex === -1) continue; - existingEntries = existingEntries.slice(0, entryIndex) + existingEntries.slice(entryIndex + value.length + 1); - } - if (existingEntries) { - await esm_default("chelonia.db/set", key, existingEntries); - } else { - await esm_default("chelonia.db/delete", key); - } - }); - }; + exports2.transformBooleanArrayReply = { + 2: (reply) => { + return reply.map(exports2.transformBooleanReply[2]); + }, + 3: void 0 }; - lookupUltimateOwner = async (resourceID) => { - let ownerID = resourceID; - for (let depth = 128; depth >= 0; depth--) { - const newOwnerID = await esm_default("chelonia.db/get", `_private_owner_${ownerID}`, { bypassCache: true }); - if (!newOwnerID) break; - if (!depth) { - throw new Error("Exceeded max depth looking up owner for " + resourceID); - } - ownerID = newOwnerID; + function transformDoubleArgument(num) { + switch (num) { + case Infinity: + return "+inf"; + case -Infinity: + return "-inf"; + default: + return num.toString(); } - return ownerID; - }; - } -}); -var requiredMethodNames; -var DatabaseBackend; -var init_DatabaseBackend = __esm({ - "src/serve/DatabaseBackend.ts"() { - "use strict"; - requiredMethodNames = ["init", "clear", "readData", "writeData", "deleteData", "close", "iterKeys", "keyCount"]; - DatabaseBackend = class _DatabaseBackend { - constructor() { - if (new.target === _DatabaseBackend) { - throw new Error("Class DatabaseBackend cannot be instantiated directly."); - } - const bindMethod = (name) => { - this[name] = this[name].bind(this); - }; - for (const name of requiredMethodNames) { - bindMethod(name); - } - } - }; - } -}); -var database_fs_exports = {}; -__export(database_fs_exports, { - default: () => FsBackend -}); -async function testCaseSensitivity(backend) { - const { readData, writeData, deleteData } = backend; - const date3 = /* @__PURE__ */ new Date(); - const dateString = date3.toISOString(); - const originalKey = `_private_testCaseSensitivity_${date3.getTime()}_${(0, Math.random)().toFixed(8).slice(2)}`; - const differentlyCasedKey = "_P" + originalKey.slice(2); - await writeData(originalKey, dateString); - try { - const valueOriginalCase = await readData(originalKey); - const valueDifferentCase = await readData(differentlyCasedKey); - if (valueOriginalCase?.toString() !== dateString) { - console.error(`Unexpected value on case-sensitivity test; expected ${dateString}`); - throw new Error("Unexpected value: original key does not have the correct value"); } - if (valueDifferentCase?.toString() === dateString) { - const errStr = "Filesystem database backend only works on case-sensitive filesystems. This appears to be a case insensitive file system. Set `skipFsCaseSensitivityCheck: true` on the FS backend configuration to skip."; - console.error(errStr); - throw new Error(errStr); + exports2.transformDoubleArgument = transformDoubleArgument; + function transformStringDoubleArgument(num) { + if (typeof num !== "number") + return num; + return transformDoubleArgument(num); } - } finally { - await deleteData(originalKey); - } -} -var ConfigSchema; -var splitAndGroup; -var FsBackend; -var init_database_fs = __esm({ - "src/serve/database-fs.ts"() { - "use strict"; - init_db(); - init_zod(); - init_DatabaseBackend(); - ConfigSchema = strictObject({ - dirname: optional(string2()), - depth: optional(number2()), - keyChunkLength: optional(number2()), - skipFsCaseSensitivityCheck: optional(boolean2()) - }); - splitAndGroup = (input, chunkLength, depth) => input.slice(0, chunkLength * depth).split("").reduce((acc, cv, i2) => { - acc[i2 / chunkLength | 0] = (acc[i2 / chunkLength | 0] || "") + cv; - return acc; - }, []); - FsBackend = class extends DatabaseBackend { - dataFolder = "data"; - depth = 0; - keyChunkLength = 2; - skipFsCaseSensitivityCheck = false; - constructor(options2 = {}) { - super(); - ConfigSchema.parse(options2); - if (options2.dirname) this.dataFolder = resolve9(options2.dirname); - if (options2.depth) this.depth = options2.depth; - if (options2.keyChunkLength) this.keyChunkLength = options2.keyChunkLength; - if (options2.skipFsCaseSensitivityCheck) this.skipFsCaseSensitivityCheck = true; - } - // Maps a given key to a real path on the filesystem. - mapKey(key) { - if (basename9(normalize8(key)) !== key) throw new TypeError("Invalid key"); - if (!this.depth) return join9(this.dataFolder, key); - const keyChunks = splitAndGroup(key, this.keyChunkLength, this.depth); - return join9(this.dataFolder, ...keyChunks, key); - } - async init() { - await mkdir(this.dataFolder, { mode: 488, recursive: true }); - if (!this.skipFsCaseSensitivityCheck) { - await testCaseSensitivity(this); - } - } - async clear() { - const names = await readdir(this.dataFolder); - const paths = names.map((name) => join9(this.dataFolder, name)); - await Promise.all( - paths.map((p) => rm(p, { recursive: true })) - ); - } - async readData(key) { - checkKey(key); - return await readFile(this.mapKey(key)).catch((err) => { - if (err.code !== "ENOENT") throw err; - }); - } - async writeData(key, value) { - const path8 = this.mapKey(key); - if (this.depth) await mkdir(dirname9(path8), { mode: 488, recursive: true }); - await writeFile(path8, value); - } - async deleteData(key) { - await unlink(this.mapKey(key)).catch((e2) => { - if (e2?.code === "ENOENT") { - return; + exports2.transformStringDoubleArgument = transformStringDoubleArgument; + exports2.transformDoubleReply = { + 2: (reply, preserve, typeMapping) => { + const double = typeMapping ? typeMapping[decoder_1.RESP_TYPES.DOUBLE] : void 0; + switch (double) { + case String: { + return reply; } - throw e2; - }); - } - close() { - } - async *iterKeys() { - const entries = await readdir(this.dataFolder, { withFileTypes: true }); - for (const entry of entries) { - if (entry.isFile()) { - yield entry.name; + default: { + let ret; + switch (reply.toString()) { + case "inf": + case "+inf": + ret = Infinity; + case "-inf": + ret = -Infinity; + case "nan": + ret = NaN; + default: + ret = Number(reply); + } + return ret; } } - } - async keyCount() { - const entries = await readdir(this.dataFolder, { withFileTypes: true }); - return entries.filter((e2) => e2.isFile()).length; - } - }; - } -}); -var require_verbatim_string = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/RESP/verbatim-string.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.VerbatimString = void 0; - var VerbatimString = class extends String { - format; - constructor(format52, value) { - super(value); - this.format = format52; - } - }; - exports2.VerbatimString = VerbatimString; - } -}); -var require_errors = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/errors.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.MultiErrorReply = exports2.CommandTimeoutDuringMaintenanceError = exports2.SocketTimeoutDuringMaintenanceError = exports2.TimeoutError = exports2.BlobError = exports2.SimpleError = exports2.ErrorReply = exports2.ReconnectStrategyError = exports2.RootNodesUnavailableError = exports2.SocketClosedUnexpectedlyError = exports2.DisconnectsClientError = exports2.ClientOfflineError = exports2.ClientClosedError = exports2.SocketTimeoutError = exports2.ConnectionTimeoutError = exports2.WatchError = exports2.AbortError = void 0; - var AbortError = class extends Error { - constructor() { - super("The command was aborted"); - } - }; - exports2.AbortError = AbortError; - var WatchError = class extends Error { - constructor(message = "One (or more) of the watched keys has been changed") { - super(message); - } + }, + 3: void 0 }; - exports2.WatchError = WatchError; - var ConnectionTimeoutError = class extends Error { - constructor() { - super("Connection timeout"); - } + function createTransformDoubleReplyResp2Func(preserve, typeMapping) { + return (reply) => { + return exports2.transformDoubleReply[2](reply, preserve, typeMapping); + }; + } + exports2.createTransformDoubleReplyResp2Func = createTransformDoubleReplyResp2Func; + exports2.transformDoubleArrayReply = { + 2: (reply, preserve, typeMapping) => { + return reply.map(createTransformDoubleReplyResp2Func(preserve, typeMapping)); + }, + 3: void 0 }; - exports2.ConnectionTimeoutError = ConnectionTimeoutError; - var SocketTimeoutError = class extends Error { - constructor(timeout) { - super(`Socket timeout timeout. Expecting data, but didn't receive any in ${timeout}ms.`); - } + function createTransformNullableDoubleReplyResp2Func(preserve, typeMapping) { + return (reply) => { + return exports2.transformNullableDoubleReply[2](reply, preserve, typeMapping); + }; + } + exports2.createTransformNullableDoubleReplyResp2Func = createTransformNullableDoubleReplyResp2Func; + exports2.transformNullableDoubleReply = { + 2: (reply, preserve, typeMapping) => { + if (reply === null) + return null; + return exports2.transformDoubleReply[2](reply, preserve, typeMapping); + }, + 3: void 0 }; - exports2.SocketTimeoutError = SocketTimeoutError; - var ClientClosedError = class extends Error { - constructor() { - super("The client is closed"); + function transformTuplesToMap(reply, func) { + const message = /* @__PURE__ */ Object.create(null); + for (let i2 = 0; i2 < reply.length; i2 += 2) { + message[reply[i2].toString()] = func(reply[i2 + 1]); } - }; - exports2.ClientClosedError = ClientClosedError; - var ClientOfflineError = class extends Error { - constructor() { - super("The client is offline"); + return message; + } + exports2.transformTuplesToMap = transformTuplesToMap; + function createTransformTuplesReplyFunc(preserve, typeMapping) { + return (reply) => { + return transformTuplesReply(reply, preserve, typeMapping); + }; + } + exports2.createTransformTuplesReplyFunc = createTransformTuplesReplyFunc; + function transformTuplesReply(reply, preserve, typeMapping) { + const mapType = typeMapping ? typeMapping[decoder_1.RESP_TYPES.MAP] : void 0; + const inferred = reply; + switch (mapType) { + case Array: { + return reply; + } + case Map: { + const ret = /* @__PURE__ */ new Map(); + for (let i2 = 0; i2 < inferred.length; i2 += 2) { + ret.set(inferred[i2].toString(), inferred[i2 + 1]); + } + return ret; + ; + } + default: { + const ret = /* @__PURE__ */ Object.create(null); + for (let i2 = 0; i2 < inferred.length; i2 += 2) { + ret[inferred[i2].toString()] = inferred[i2 + 1]; + } + return ret; + ; + } } - }; - exports2.ClientOfflineError = ClientOfflineError; - var DisconnectsClientError = class extends Error { - constructor() { - super("Disconnects client"); + } + exports2.transformTuplesReply = transformTuplesReply; + exports2.transformSortedSetReply = { + 2: (reply, preserve, typeMapping) => { + const inferred = reply, members = []; + for (let i2 = 0; i2 < inferred.length; i2 += 2) { + members.push({ + value: inferred[i2], + score: exports2.transformDoubleReply[2](inferred[i2 + 1], preserve, typeMapping) + }); + } + return members; + }, + 3: (reply) => { + return reply.map((member) => { + const [value, score] = member; + return { + value, + score + }; + }); } }; - exports2.DisconnectsClientError = DisconnectsClientError; - var SocketClosedUnexpectedlyError = class extends Error { - constructor() { - super("Socket closed unexpectedly"); + function transformEXAT(EXAT) { + return (typeof EXAT === "number" ? EXAT : Math.floor(EXAT.getTime() / 1e3)).toString(); + } + exports2.transformEXAT = transformEXAT; + function transformPXAT(PXAT) { + return (typeof PXAT === "number" ? PXAT : PXAT.getTime()).toString(); + } + exports2.transformPXAT = transformPXAT; + function evalFirstKeyIndex(options2) { + return options2?.keys?.[0]; + } + exports2.evalFirstKeyIndex = evalFirstKeyIndex; + function pushEvalArguments(args, options2) { + if (options2?.keys) { + args.push(options2.keys.length.toString(), ...options2.keys); + } else { + args.push("0"); } - }; - exports2.SocketClosedUnexpectedlyError = SocketClosedUnexpectedlyError; - var RootNodesUnavailableError = class extends Error { - constructor() { - super("All the root nodes are unavailable"); + if (options2?.arguments) { + args.push(...options2.arguments); } - }; - exports2.RootNodesUnavailableError = RootNodesUnavailableError; - var ReconnectStrategyError = class extends Error { - originalError; - socketError; - constructor(originalError, socketError) { - super(originalError.message); - this.originalError = originalError; - this.socketError = socketError; + return args; + } + exports2.pushEvalArguments = pushEvalArguments; + function pushVariadicArguments(args, value) { + if (Array.isArray(value)) { + args = args.concat(value); + } else { + args.push(value); } - }; - exports2.ReconnectStrategyError = ReconnectStrategyError; - var ErrorReply = class extends Error { - }; - exports2.ErrorReply = ErrorReply; - var SimpleError = class extends ErrorReply { - }; - exports2.SimpleError = SimpleError; - var BlobError = class extends ErrorReply { - }; - exports2.BlobError = BlobError; - var TimeoutError = class extends Error { - }; - exports2.TimeoutError = TimeoutError; - var SocketTimeoutDuringMaintenanceError = class extends TimeoutError { - constructor(timeout) { - super(`Socket timeout during maintenance. Expecting data, but didn't receive any in ${timeout}ms.`); + return args; + } + exports2.pushVariadicArguments = pushVariadicArguments; + function pushVariadicNumberArguments(args, value) { + if (Array.isArray(value)) { + for (const item of value) { + args.push(item.toString()); + } + } else { + args.push(value.toString()); } - }; - exports2.SocketTimeoutDuringMaintenanceError = SocketTimeoutDuringMaintenanceError; - var CommandTimeoutDuringMaintenanceError = class extends TimeoutError { - constructor(timeout) { - super(`Command timeout during maintenance. Waited to write command for more than ${timeout}ms.`); + return args; + } + exports2.pushVariadicNumberArguments = pushVariadicNumberArguments; + function pushVariadicArgument(args, value) { + if (Array.isArray(value)) { + args.push(value.length.toString(), ...value); + } else { + args.push("1", value); } - }; - exports2.CommandTimeoutDuringMaintenanceError = CommandTimeoutDuringMaintenanceError; - var MultiErrorReply = class extends ErrorReply { - replies; - errorIndexes; - constructor(replies, errorIndexes) { - super(`${errorIndexes.length} commands failed, see .replies and .errorIndexes for more information`); - this.replies = replies; - this.errorIndexes = errorIndexes; + return args; + } + exports2.pushVariadicArgument = pushVariadicArgument; + function parseOptionalVariadicArgument(parser3, name, value) { + if (value === void 0) + return; + parser3.push(name); + parser3.pushVariadicWithLength(value); + } + exports2.parseOptionalVariadicArgument = parseOptionalVariadicArgument; + var CommandFlags; + (function(CommandFlags2) { + CommandFlags2["WRITE"] = "write"; + CommandFlags2["READONLY"] = "readonly"; + CommandFlags2["DENYOOM"] = "denyoom"; + CommandFlags2["ADMIN"] = "admin"; + CommandFlags2["PUBSUB"] = "pubsub"; + CommandFlags2["NOSCRIPT"] = "noscript"; + CommandFlags2["RANDOM"] = "random"; + CommandFlags2["SORT_FOR_SCRIPT"] = "sort_for_script"; + CommandFlags2["LOADING"] = "loading"; + CommandFlags2["STALE"] = "stale"; + CommandFlags2["SKIP_MONITOR"] = "skip_monitor"; + CommandFlags2["ASKING"] = "asking"; + CommandFlags2["FAST"] = "fast"; + CommandFlags2["MOVABLEKEYS"] = "movablekeys"; + })(CommandFlags || (exports2.CommandFlags = CommandFlags = {})); + var CommandCategories; + (function(CommandCategories2) { + CommandCategories2["KEYSPACE"] = "@keyspace"; + CommandCategories2["READ"] = "@read"; + CommandCategories2["WRITE"] = "@write"; + CommandCategories2["SET"] = "@set"; + CommandCategories2["SORTEDSET"] = "@sortedset"; + CommandCategories2["LIST"] = "@list"; + CommandCategories2["HASH"] = "@hash"; + CommandCategories2["STRING"] = "@string"; + CommandCategories2["BITMAP"] = "@bitmap"; + CommandCategories2["HYPERLOGLOG"] = "@hyperloglog"; + CommandCategories2["GEO"] = "@geo"; + CommandCategories2["STREAM"] = "@stream"; + CommandCategories2["PUBSUB"] = "@pubsub"; + CommandCategories2["ADMIN"] = "@admin"; + CommandCategories2["FAST"] = "@fast"; + CommandCategories2["SLOW"] = "@slow"; + CommandCategories2["BLOCKING"] = "@blocking"; + CommandCategories2["DANGEROUS"] = "@dangerous"; + CommandCategories2["CONNECTION"] = "@connection"; + CommandCategories2["TRANSACTION"] = "@transaction"; + CommandCategories2["SCRIPTING"] = "@scripting"; + })(CommandCategories || (exports2.CommandCategories = CommandCategories = {})); + function transformCommandReply([name, arity, flags, firstKeyIndex, lastKeyIndex, step, categories]) { + return { + name, + arity, + flags: new Set(flags), + firstKeyIndex, + lastKeyIndex, + step, + categories: new Set(categories) + }; + } + exports2.transformCommandReply = transformCommandReply; + var RedisFunctionFlags; + (function(RedisFunctionFlags2) { + RedisFunctionFlags2["NO_WRITES"] = "no-writes"; + RedisFunctionFlags2["ALLOW_OOM"] = "allow-oom"; + RedisFunctionFlags2["ALLOW_STALE"] = "allow-stale"; + RedisFunctionFlags2["NO_CLUSTER"] = "no-cluster"; + })(RedisFunctionFlags || (exports2.RedisFunctionFlags = RedisFunctionFlags = {})); + function transformFunctionListItemReply(reply) { + return { + libraryName: reply[1], + engine: reply[3], + functions: reply[5].map((fn) => ({ + name: fn[1], + description: fn[3], + flags: fn[5] + })) + }; + } + exports2.transformFunctionListItemReply = transformFunctionListItemReply; + function parseSlotRangeArguments(parser3, range) { + parser3.push(range.start.toString(), range.end.toString()); + } + function parseSlotRangesArguments(parser3, ranges) { + if (Array.isArray(ranges)) { + for (const range of ranges) { + parseSlotRangeArguments(parser3, range); + } + } else { + parseSlotRangeArguments(parser3, ranges); } - *errors() { - for (const index of this.errorIndexes) { - yield this.replies[index]; + } + exports2.parseSlotRangesArguments = parseSlotRangesArguments; + function transformRangeReply([start, end]) { + return { + start, + end + }; + } + exports2.transformRangeReply = transformRangeReply; + function parseZKeysArguments(parser3, keys) { + if (Array.isArray(keys)) { + parser3.push(keys.length.toString()); + if (keys.length) { + if (isPlainKeys(keys)) { + parser3.pushKeys(keys); + } else { + for (let i2 = 0; i2 < keys.length; i2++) { + parser3.pushKey(keys[i2].key); + } + parser3.push("WEIGHTS"); + for (let i2 = 0; i2 < keys.length; i2++) { + parser3.push(transformDoubleArgument(keys[i2].weight)); + } + } + } + } else { + parser3.push("1"); + if (isPlainKey(keys)) { + parser3.pushKey(keys); + } else { + parser3.pushKey(keys.key); + parser3.push("WEIGHTS", transformDoubleArgument(keys.weight)); } } - }; - exports2.MultiErrorReply = MultiErrorReply; - } -}); -var require_decoder = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/RESP/decoder.js"(exports2) { - "use strict"; - var _a2; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.Decoder = exports2.PUSH_TYPE_MAPPING = exports2.RESP_TYPES = void 0; - var verbatim_string_1 = require_verbatim_string(); - var errors_1 = require_errors(); - exports2.RESP_TYPES = { - NULL: 95, - // _ - BOOLEAN: 35, - // # - NUMBER: 58, - // : - BIG_NUMBER: 40, - // ( - DOUBLE: 44, - // , - SIMPLE_STRING: 43, - // + - BLOB_STRING: 36, - // $ - VERBATIM_STRING: 61, - // = - SIMPLE_ERROR: 45, - // - - BLOB_ERROR: 33, - // ! - ARRAY: 42, - // * - SET: 126, - // ~ - MAP: 37, - // % - PUSH: 62 - // > - }; - var ASCII = { - "\r": 13, - "t": 116, - "+": 43, - "-": 45, - "0": 48, - ".": 46, - "i": 105, - "n": 110, - "E": 69, - "e": 101 - }; - exports2.PUSH_TYPE_MAPPING = { - [exports2.RESP_TYPES.BLOB_STRING]: Buffer - }; - var Decoder2 = class { - onReply; - onErrorReply; - onPush; - getTypeMapping; - #cursor = 0; - #next; - constructor(config2) { - this.onReply = config2.onReply; - this.onErrorReply = config2.onErrorReply; - this.onPush = config2.onPush; - this.getTypeMapping = config2.getTypeMapping; - } - reset() { - this.#cursor = 0; - this.#next = void 0; - } - write(chunk) { - if (this.#cursor >= chunk.length) { - this.#cursor -= chunk.length; - return; - } - if (this.#next) { - if (this.#next(chunk) || this.#cursor >= chunk.length) { - this.#cursor -= chunk.length; - return; - } - } - do { - const type = chunk[this.#cursor]; - if (++this.#cursor === chunk.length) { - this.#next = this.#continueDecodeTypeValue.bind(this, type); - break; - } - if (this.#decodeTypeValue(type, chunk)) { - break; - } - } while (this.#cursor < chunk.length); - this.#cursor -= chunk.length; - } - #continueDecodeTypeValue(type, chunk) { - this.#next = void 0; - return this.#decodeTypeValue(type, chunk); - } - #decodeTypeValue(type, chunk) { - switch (type) { - case exports2.RESP_TYPES.NULL: - this.onReply(this.#decodeNull()); - return false; - case exports2.RESP_TYPES.BOOLEAN: - return this.#handleDecodedValue(this.onReply, this.#decodeBoolean(chunk)); - case exports2.RESP_TYPES.NUMBER: - return this.#handleDecodedValue(this.onReply, this.#decodeNumber(this.getTypeMapping()[exports2.RESP_TYPES.NUMBER], chunk)); - case exports2.RESP_TYPES.BIG_NUMBER: - return this.#handleDecodedValue(this.onReply, this.#decodeBigNumber(this.getTypeMapping()[exports2.RESP_TYPES.BIG_NUMBER], chunk)); - case exports2.RESP_TYPES.DOUBLE: - return this.#handleDecodedValue(this.onReply, this.#decodeDouble(this.getTypeMapping()[exports2.RESP_TYPES.DOUBLE], chunk)); - case exports2.RESP_TYPES.SIMPLE_STRING: - return this.#handleDecodedValue(this.onReply, this.#decodeSimpleString(this.getTypeMapping()[exports2.RESP_TYPES.SIMPLE_STRING], chunk)); - case exports2.RESP_TYPES.BLOB_STRING: - return this.#handleDecodedValue(this.onReply, this.#decodeBlobString(this.getTypeMapping()[exports2.RESP_TYPES.BLOB_STRING], chunk)); - case exports2.RESP_TYPES.VERBATIM_STRING: - return this.#handleDecodedValue(this.onReply, this.#decodeVerbatimString(this.getTypeMapping()[exports2.RESP_TYPES.VERBATIM_STRING], chunk)); - case exports2.RESP_TYPES.SIMPLE_ERROR: - return this.#handleDecodedValue(this.onErrorReply, this.#decodeSimpleError(chunk)); - case exports2.RESP_TYPES.BLOB_ERROR: - return this.#handleDecodedValue(this.onErrorReply, this.#decodeBlobError(chunk)); - case exports2.RESP_TYPES.ARRAY: - return this.#handleDecodedValue(this.onReply, this.#decodeArray(this.getTypeMapping(), chunk)); - case exports2.RESP_TYPES.SET: - return this.#handleDecodedValue(this.onReply, this.#decodeSet(this.getTypeMapping(), chunk)); - case exports2.RESP_TYPES.MAP: - return this.#handleDecodedValue(this.onReply, this.#decodeMap(this.getTypeMapping(), chunk)); - case exports2.RESP_TYPES.PUSH: - return this.#handleDecodedValue(this.onPush, this.#decodeArray(exports2.PUSH_TYPE_MAPPING, chunk)); - default: - throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`); - } - } - #handleDecodedValue(cb, value) { - if (typeof value === "function") { - this.#next = this.#continueDecodeValue.bind(this, cb, value); - return true; - } - cb(value); - return false; - } - #continueDecodeValue(cb, next, chunk) { - this.#next = void 0; - return this.#handleDecodedValue(cb, next(chunk)); + } + exports2.parseZKeysArguments = parseZKeysArguments; + function isPlainKey(key) { + return typeof key === "string" || key instanceof Buffer; + } + function isPlainKeys(keys) { + return isPlainKey(keys[0]); + } + function parseArgs2(command2, ...args) { + const parser3 = new parser_1.BasicCommandParser(); + command2.parseCommand(parser3, ...args); + const redisArgs = parser3.redisArgs; + if (parser3.preserve) { + redisArgs.preserve = parser3.preserve; } - #decodeNull() { - this.#cursor += 2; + return redisArgs; + } + exports2.parseArgs = parseArgs2; + function transformStreamMessageReply(typeMapping, reply) { + const [id, message] = reply; + return { + id, + message: transformTuplesReply(message, void 0, typeMapping) + }; + } + exports2.transformStreamMessageReply = transformStreamMessageReply; + function transformStreamMessageNullReply(typeMapping, reply) { + return isNullReply(reply) ? reply : transformStreamMessageReply(typeMapping, reply); + } + exports2.transformStreamMessageNullReply = transformStreamMessageNullReply; + function transformStreamMessagesReply(r, typeMapping) { + const reply = r; + return reply.map(transformStreamMessageReply.bind(void 0, typeMapping)); + } + exports2.transformStreamMessagesReply = transformStreamMessagesReply; + function transformStreamsMessagesReplyResp2(reply, preserve, typeMapping) { + if (reply === null) return null; - } - #decodeBoolean(chunk) { - const boolean3 = chunk[this.#cursor] === ASCII.t; - this.#cursor += 3; - return boolean3; - } - #decodeNumber(type, chunk) { - if (type === String) { - return this.#decodeSimpleString(String, chunk); - } - switch (chunk[this.#cursor]) { - case ASCII["+"]: - return this.#maybeDecodeNumberValue(false, chunk); - case ASCII["-"]: - return this.#maybeDecodeNumberValue(true, chunk); - default: - return this.#decodeNumberValue(false, this.#decodeUnsingedNumber.bind(this, 0), chunk); - } - } - #maybeDecodeNumberValue(isNegative, chunk) { - const cb = this.#decodeUnsingedNumber.bind(this, 0); - return ++this.#cursor === chunk.length ? this.#decodeNumberValue.bind(this, isNegative, cb) : this.#decodeNumberValue(isNegative, cb, chunk); - } - #decodeNumberValue(isNegative, numberCb, chunk) { - const number3 = numberCb(chunk); - return typeof number3 === "function" ? this.#decodeNumberValue.bind(this, isNegative, number3) : isNegative ? -number3 : number3; - } - #decodeUnsingedNumber(number3, chunk) { - let cursor = this.#cursor; - do { - const byte = chunk[cursor]; - if (byte === ASCII["\r"]) { - this.#cursor = cursor + 2; - return number3; - } - number3 = number3 * 10 + byte - ASCII["0"]; - } while (++cursor < chunk.length); - this.#cursor = cursor; - return this.#decodeUnsingedNumber.bind(this, number3); - } - #decodeBigNumber(type, chunk) { - if (type === String) { - return this.#decodeSimpleString(String, chunk); - } - switch (chunk[this.#cursor]) { - case ASCII["+"]: - return this.#maybeDecodeBigNumberValue(false, chunk); - case ASCII["-"]: - return this.#maybeDecodeBigNumberValue(true, chunk); - default: - return this.#decodeBigNumberValue(false, this.#decodeUnsingedBigNumber.bind(this, 0n), chunk); - } - } - #maybeDecodeBigNumberValue(isNegative, chunk) { - const cb = this.#decodeUnsingedBigNumber.bind(this, 0n); - return ++this.#cursor === chunk.length ? this.#decodeBigNumberValue.bind(this, isNegative, cb) : this.#decodeBigNumberValue(isNegative, cb, chunk); - } - #decodeBigNumberValue(isNegative, bigNumberCb, chunk) { - const bigNumber = bigNumberCb(chunk); - return typeof bigNumber === "function" ? this.#decodeBigNumberValue.bind(this, isNegative, bigNumber) : isNegative ? -bigNumber : bigNumber; - } - #decodeUnsingedBigNumber(bigNumber, chunk) { - let cursor = this.#cursor; - do { - const byte = chunk[cursor]; - if (byte === ASCII["\r"]) { - this.#cursor = cursor + 2; - return bigNumber; + switch (typeMapping ? typeMapping[decoder_1.RESP_TYPES.MAP] : void 0) { + /* FUTURE: a response type for when resp3 is working properly + case Map: { + const ret = new Map(); + + for (let i=0; i < reply.length; i++) { + const stream = reply[i] as unknown as UnwrapReply; + + const name = stream[0]; + const rawMessages = stream[1]; + + ret.set(name.toString(), transformStreamMessagesReply(rawMessages, typeMapping)); + } + + return ret as unknown as MapReply; + } + case Array: { + const ret: Array = []; + + for (let i=0; i < reply.length; i++) { + const stream = reply[i] as unknown as UnwrapReply; + + const name = stream[0]; + const rawMessages = stream[1]; + + ret.push(name); + ret.push(transformStreamMessagesReply(rawMessages, typeMapping)); + } + + return ret as unknown as MapReply; + } + default: { + const ret: Record = Object.create(null); + + for (let i=0; i < reply.length; i++) { + const stream = reply[i] as unknown as UnwrapReply; + + const name = stream[0] as unknown as UnwrapReply; + const rawMessages = stream[1]; + + ret[name.toString()] = transformStreamMessagesReply(rawMessages); + } + + return ret as unknown as MapReply; + } + */ + // V4 compatible response type + default: { + const ret = []; + for (let i2 = 0; i2 < reply.length; i2++) { + const stream = reply[i2]; + ret.push({ + name: stream[0], + messages: transformStreamMessagesReply(stream[1]) + }); } - bigNumber = bigNumber * 10n + BigInt(byte - ASCII["0"]); - } while (++cursor < chunk.length); - this.#cursor = cursor; - return this.#decodeUnsingedBigNumber.bind(this, bigNumber); - } - #decodeDouble(type, chunk) { - if (type === String) { - return this.#decodeSimpleString(String, chunk); - } - switch (chunk[this.#cursor]) { - case ASCII.n: - this.#cursor += 5; - return NaN; - case ASCII["+"]: - return this.#maybeDecodeDoubleInteger(false, chunk); - case ASCII["-"]: - return this.#maybeDecodeDoubleInteger(true, chunk); - default: - return this.#decodeDoubleInteger(false, 0, chunk); + return ret; } } - #maybeDecodeDoubleInteger(isNegative, chunk) { - return ++this.#cursor === chunk.length ? this.#decodeDoubleInteger.bind(this, isNegative, 0) : this.#decodeDoubleInteger(isNegative, 0, chunk); - } - #decodeDoubleInteger(isNegative, integer2, chunk) { - if (chunk[this.#cursor] === ASCII.i) { - this.#cursor += 5; - return isNegative ? -Infinity : Infinity; + } + exports2.transformStreamsMessagesReplyResp2 = transformStreamsMessagesReplyResp2; + function transformStreamsMessagesReplyResp3(reply) { + if (reply === null) + return null; + if (reply instanceof Map) { + const ret = /* @__PURE__ */ new Map(); + for (const [n, rawMessages] of reply) { + const name = n; + ret.set(name.toString(), transformStreamMessagesReply(rawMessages)); } - return this.#continueDecodeDoubleInteger(isNegative, integer2, chunk); - } - #continueDecodeDoubleInteger(isNegative, integer2, chunk) { - let cursor = this.#cursor; - do { - const byte = chunk[cursor]; - switch (byte) { - case ASCII["."]: - this.#cursor = cursor + 1; - return this.#cursor < chunk.length ? this.#decodeDoubleDecimal(isNegative, 0, integer2, chunk) : this.#decodeDoubleDecimal.bind(this, isNegative, 0, integer2); - case ASCII.E: - case ASCII.e: - this.#cursor = cursor + 1; - const i2 = isNegative ? -integer2 : integer2; - return this.#cursor < chunk.length ? this.#decodeDoubleExponent(i2, chunk) : this.#decodeDoubleExponent.bind(this, i2); - case ASCII["\r"]: - this.#cursor = cursor + 2; - return isNegative ? -integer2 : integer2; - default: - integer2 = integer2 * 10 + byte - ASCII["0"]; - } - } while (++cursor < chunk.length); - this.#cursor = cursor; - return this.#continueDecodeDoubleInteger.bind(this, isNegative, integer2); - } - // Precalculated multipliers for decimal points to improve performance - // "... about 15 to 17 decimal places ..." - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#:~:text=about%2015%20to%2017%20decimal%20places - static #DOUBLE_DECIMAL_MULTIPLIERS = [ - 0.1, - 0.01, - 1e-3, - 1e-4, - 1e-5, - 1e-6, - 1e-7, - 1e-8, - 1e-9, - 1e-10, - 1e-11, - 1e-12, - 1e-13, - 1e-14, - 1e-15, - 1e-16, - 1e-17 - ]; - #decodeDoubleDecimal(isNegative, decimalIndex, double, chunk) { - let cursor = this.#cursor; - do { - const byte = chunk[cursor]; - switch (byte) { - case ASCII.E: - case ASCII.e: - this.#cursor = cursor + 1; - const d = isNegative ? -double : double; - return this.#cursor === chunk.length ? this.#decodeDoubleExponent.bind(this, d) : this.#decodeDoubleExponent(d, chunk); - case ASCII["\r"]: - this.#cursor = cursor + 2; - return isNegative ? -double : double; - } - if (decimalIndex < _a2.#DOUBLE_DECIMAL_MULTIPLIERS.length) { - double += (byte - ASCII["0"]) * _a2.#DOUBLE_DECIMAL_MULTIPLIERS[decimalIndex++]; - } - } while (++cursor < chunk.length); - this.#cursor = cursor; - return this.#decodeDoubleDecimal.bind(this, isNegative, decimalIndex, double); - } - #decodeDoubleExponent(double, chunk) { - switch (chunk[this.#cursor]) { - case ASCII["+"]: - return ++this.#cursor === chunk.length ? this.#continueDecodeDoubleExponent.bind(this, false, double, 0) : this.#continueDecodeDoubleExponent(false, double, 0, chunk); - case ASCII["-"]: - return ++this.#cursor === chunk.length ? this.#continueDecodeDoubleExponent.bind(this, true, double, 0) : this.#continueDecodeDoubleExponent(true, double, 0, chunk); + return ret; + } else if (reply instanceof Array) { + const ret = []; + for (let i2 = 0; i2 < reply.length; i2 += 2) { + const name = reply[i2]; + const rawMessages = reply[i2 + 1]; + ret.push(name); + ret.push(transformStreamMessagesReply(rawMessages)); } - return this.#continueDecodeDoubleExponent(false, double, 0, chunk); - } - #continueDecodeDoubleExponent(isNegative, double, exponent, chunk) { - let cursor = this.#cursor; - do { - const byte = chunk[cursor]; - if (byte === ASCII["\r"]) { - this.#cursor = cursor + 2; - return double * 10 ** (isNegative ? -exponent : exponent); - } - exponent = exponent * 10 + byte - ASCII["0"]; - } while (++cursor < chunk.length); - this.#cursor = cursor; - return this.#continueDecodeDoubleExponent.bind(this, isNegative, double, exponent); - } - #findCRLF(chunk, cursor) { - while (chunk[cursor] !== ASCII["\r"]) { - if (++cursor === chunk.length) { - this.#cursor = chunk.length; - return -1; - } + return ret; + } else { + const ret = /* @__PURE__ */ Object.create(null); + for (const [name, rawMessages] of Object.entries(reply)) { + ret[name] = transformStreamMessagesReply(rawMessages); } - this.#cursor = cursor + 2; - return cursor; + return ret; } - #decodeSimpleString(type, chunk) { - const start = this.#cursor, crlfIndex = this.#findCRLF(chunk, start); - if (crlfIndex === -1) { - return this.#continueDecodeSimpleString.bind(this, [chunk.subarray(start)], type); + } + exports2.transformStreamsMessagesReplyResp3 = transformStreamsMessagesReplyResp3; + function transformRedisJsonArgument(json) { + return JSON.stringify(json); + } + exports2.transformRedisJsonArgument = transformRedisJsonArgument; + function transformRedisJsonReply(json) { + const res = JSON.parse(json.toString()); + return res; + } + exports2.transformRedisJsonReply = transformRedisJsonReply; + function transformRedisJsonNullReply(json) { + return isNullReply(json) ? json : transformRedisJsonReply(json); + } + exports2.transformRedisJsonNullReply = transformRedisJsonNullReply; + } +}); +var require_ACL_LOG = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOG.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + var generic_transformers_1 = require_generic_transformers(); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Returns ACL security events log entries + * @param parser - The Redis command parser + * @param count - Optional maximum number of entries to return + */ + parseCommand(parser3, count) { + parser3.push("ACL", "LOG"); + if (count != void 0) { + parser3.push(count.toString()); } - const slice = chunk.subarray(start, crlfIndex); - return type === Buffer ? slice : slice.toString(); - } - #continueDecodeSimpleString(chunks, type, chunk) { - const start = this.#cursor, crlfIndex = this.#findCRLF(chunk, start); - if (crlfIndex === -1) { - chunks.push(chunk.subarray(start)); - return this.#continueDecodeSimpleString.bind(this, chunks, type); - } - chunks.push(chunk.subarray(start, crlfIndex)); - const buffer = Buffer.concat(chunks); - return type === Buffer ? buffer : buffer.toString(); - } - #decodeBlobString(type, chunk) { - if (chunk[this.#cursor] === ASCII["-"]) { - this.#cursor += 4; - return null; - } - const length2 = this.#decodeUnsingedNumber(0, chunk); - if (typeof length2 === "function") { - return this.#continueDecodeBlobStringLength.bind(this, length2, type); - } else if (this.#cursor >= chunk.length) { - return this.#decodeBlobStringWithLength.bind(this, length2, type); - } - return this.#decodeBlobStringWithLength(length2, type, chunk); - } - #continueDecodeBlobStringLength(lengthCb, type, chunk) { - const length2 = lengthCb(chunk); - if (typeof length2 === "function") { - return this.#continueDecodeBlobStringLength.bind(this, length2, type); - } else if (this.#cursor >= chunk.length) { - return this.#decodeBlobStringWithLength.bind(this, length2, type); - } - return this.#decodeBlobStringWithLength(length2, type, chunk); - } - #decodeStringWithLength(length2, skip, type, chunk) { - const end = this.#cursor + length2; - if (end >= chunk.length) { - const slice2 = chunk.subarray(this.#cursor); - this.#cursor = chunk.length; - return this.#continueDecodeStringWithLength.bind(this, length2 - slice2.length, [slice2], skip, type); - } - const slice = chunk.subarray(this.#cursor, end); - this.#cursor = end + skip; - return type === Buffer ? slice : slice.toString(); - } - #continueDecodeStringWithLength(length2, chunks, skip, type, chunk) { - const end = this.#cursor + length2; - if (end >= chunk.length) { - const slice = chunk.subarray(this.#cursor); - chunks.push(slice); - this.#cursor = chunk.length; - return this.#continueDecodeStringWithLength.bind(this, length2 - slice.length, chunks, skip, type); - } - chunks.push(chunk.subarray(this.#cursor, end)); - this.#cursor = end + skip; - const buffer = Buffer.concat(chunks); - return type === Buffer ? buffer : buffer.toString(); - } - #decodeBlobStringWithLength(length2, type, chunk) { - return this.#decodeStringWithLength(length2, 2, type, chunk); - } - #decodeVerbatimString(type, chunk) { - return this.#continueDecodeVerbatimStringLength(this.#decodeUnsingedNumber.bind(this, 0), type, chunk); - } - #continueDecodeVerbatimStringLength(lengthCb, type, chunk) { - const length2 = lengthCb(chunk); - return typeof length2 === "function" ? this.#continueDecodeVerbatimStringLength.bind(this, length2, type) : this.#decodeVerbatimStringWithLength(length2, type, chunk); - } - #decodeVerbatimStringWithLength(length2, type, chunk) { - const stringLength = length2 - 4; - if (type === verbatim_string_1.VerbatimString) { - return this.#decodeVerbatimStringFormat(stringLength, chunk); - } - this.#cursor += 4; - return this.#cursor >= chunk.length ? this.#decodeBlobStringWithLength.bind(this, stringLength, type) : this.#decodeBlobStringWithLength(stringLength, type, chunk); - } - #decodeVerbatimStringFormat(stringLength, chunk) { - const formatCb = this.#decodeStringWithLength.bind(this, 3, 1, String); - return this.#cursor >= chunk.length ? this.#continueDecodeVerbatimStringFormat.bind(this, stringLength, formatCb) : this.#continueDecodeVerbatimStringFormat(stringLength, formatCb, chunk); - } - #continueDecodeVerbatimStringFormat(stringLength, formatCb, chunk) { - const format52 = formatCb(chunk); - return typeof format52 === "function" ? this.#continueDecodeVerbatimStringFormat.bind(this, stringLength, format52) : this.#decodeVerbatimStringWithFormat(stringLength, format52, chunk); - } - #decodeVerbatimStringWithFormat(stringLength, format52, chunk) { - return this.#continueDecodeVerbatimStringWithFormat(format52, this.#decodeBlobStringWithLength.bind(this, stringLength, String), chunk); - } - #continueDecodeVerbatimStringWithFormat(format52, stringCb, chunk) { - const string3 = stringCb(chunk); - return typeof string3 === "function" ? this.#continueDecodeVerbatimStringWithFormat.bind(this, format52, string3) : new verbatim_string_1.VerbatimString(format52, string3); - } - #decodeSimpleError(chunk) { - const string3 = this.#decodeSimpleString(String, chunk); - return typeof string3 === "function" ? this.#continueDecodeSimpleError.bind(this, string3) : new errors_1.SimpleError(string3); - } - #continueDecodeSimpleError(stringCb, chunk) { - const string3 = stringCb(chunk); - return typeof string3 === "function" ? this.#continueDecodeSimpleError.bind(this, string3) : new errors_1.SimpleError(string3); - } - #decodeBlobError(chunk) { - const string3 = this.#decodeBlobString(String, chunk); - return typeof string3 === "function" ? this.#continueDecodeBlobError.bind(this, string3) : new errors_1.BlobError(string3); - } - #continueDecodeBlobError(stringCb, chunk) { - const string3 = stringCb(chunk); - return typeof string3 === "function" ? this.#continueDecodeBlobError.bind(this, string3) : new errors_1.BlobError(string3); - } - #decodeNestedType(typeMapping, chunk) { - const type = chunk[this.#cursor]; - return ++this.#cursor === chunk.length ? this.#decodeNestedTypeValue.bind(this, type, typeMapping) : this.#decodeNestedTypeValue(type, typeMapping, chunk); - } - #decodeNestedTypeValue(type, typeMapping, chunk) { - switch (type) { - case exports2.RESP_TYPES.NULL: - return this.#decodeNull(); - case exports2.RESP_TYPES.BOOLEAN: - return this.#decodeBoolean(chunk); - case exports2.RESP_TYPES.NUMBER: - return this.#decodeNumber(typeMapping[exports2.RESP_TYPES.NUMBER], chunk); - case exports2.RESP_TYPES.BIG_NUMBER: - return this.#decodeBigNumber(typeMapping[exports2.RESP_TYPES.BIG_NUMBER], chunk); - case exports2.RESP_TYPES.DOUBLE: - return this.#decodeDouble(typeMapping[exports2.RESP_TYPES.DOUBLE], chunk); - case exports2.RESP_TYPES.SIMPLE_STRING: - return this.#decodeSimpleString(typeMapping[exports2.RESP_TYPES.SIMPLE_STRING], chunk); - case exports2.RESP_TYPES.BLOB_STRING: - return this.#decodeBlobString(typeMapping[exports2.RESP_TYPES.BLOB_STRING], chunk); - case exports2.RESP_TYPES.VERBATIM_STRING: - return this.#decodeVerbatimString(typeMapping[exports2.RESP_TYPES.VERBATIM_STRING], chunk); - case exports2.RESP_TYPES.SIMPLE_ERROR: - return this.#decodeSimpleError(chunk); - case exports2.RESP_TYPES.BLOB_ERROR: - return this.#decodeBlobError(chunk); - case exports2.RESP_TYPES.ARRAY: - return this.#decodeArray(typeMapping, chunk); - case exports2.RESP_TYPES.SET: - return this.#decodeSet(typeMapping, chunk); - case exports2.RESP_TYPES.MAP: - return this.#decodeMap(typeMapping, chunk); - default: - throw new Error(`Unknown RESP type ${type} "${String.fromCharCode(type)}"`); - } - } - #decodeArray(typeMapping, chunk) { - if (chunk[this.#cursor] === ASCII["-"]) { - this.#cursor += 4; - return null; - } - return this.#decodeArrayWithLength(this.#decodeUnsingedNumber(0, chunk), typeMapping, chunk); - } - #decodeArrayWithLength(length2, typeMapping, chunk) { - return typeof length2 === "function" ? this.#continueDecodeArrayLength.bind(this, length2, typeMapping) : this.#decodeArrayItems(new Array(length2), 0, typeMapping, chunk); - } - #continueDecodeArrayLength(lengthCb, typeMapping, chunk) { - return this.#decodeArrayWithLength(lengthCb(chunk), typeMapping, chunk); - } - #decodeArrayItems(array2, filled, typeMapping, chunk) { - for (let i2 = filled; i2 < array2.length; i2++) { - if (this.#cursor >= chunk.length) { - return this.#decodeArrayItems.bind(this, array2, i2, typeMapping); - } - const item = this.#decodeNestedType(typeMapping, chunk); - if (typeof item === "function") { - return this.#continueDecodeArrayItems.bind(this, array2, i2, item, typeMapping); - } - array2[i2] = item; - } - return array2; - } - #continueDecodeArrayItems(array2, filled, itemCb, typeMapping, chunk) { - const item = itemCb(chunk); - if (typeof item === "function") { - return this.#continueDecodeArrayItems.bind(this, array2, filled, item, typeMapping); - } - array2[filled++] = item; - return this.#decodeArrayItems(array2, filled, typeMapping, chunk); - } - #decodeSet(typeMapping, chunk) { - const length2 = this.#decodeUnsingedNumber(0, chunk); - if (typeof length2 === "function") { - return this.#continueDecodeSetLength.bind(this, length2, typeMapping); - } - return this.#decodeSetItems(length2, typeMapping, chunk); - } - #continueDecodeSetLength(lengthCb, typeMapping, chunk) { - const length2 = lengthCb(chunk); - return typeof length2 === "function" ? this.#continueDecodeSetLength.bind(this, length2, typeMapping) : this.#decodeSetItems(length2, typeMapping, chunk); - } - #decodeSetItems(length2, typeMapping, chunk) { - return typeMapping[exports2.RESP_TYPES.SET] === Set ? this.#decodeSetAsSet(/* @__PURE__ */ new Set(), length2, typeMapping, chunk) : this.#decodeArrayItems(new Array(length2), 0, typeMapping, chunk); - } - #decodeSetAsSet(set, remaining, typeMapping, chunk) { - while (remaining > 0) { - if (this.#cursor >= chunk.length) { - return this.#decodeSetAsSet.bind(this, set, remaining, typeMapping); - } - const item = this.#decodeNestedType(typeMapping, chunk); - if (typeof item === "function") { - return this.#continueDecodeSetAsSet.bind(this, set, remaining, item, typeMapping); - } - set.add(item); - --remaining; - } - return set; - } - #continueDecodeSetAsSet(set, remaining, itemCb, typeMapping, chunk) { - const item = itemCb(chunk); - if (typeof item === "function") { - return this.#continueDecodeSetAsSet.bind(this, set, remaining, item, typeMapping); - } - set.add(item); - return this.#decodeSetAsSet(set, remaining - 1, typeMapping, chunk); - } - #decodeMap(typeMapping, chunk) { - const length2 = this.#decodeUnsingedNumber(0, chunk); - if (typeof length2 === "function") { - return this.#continueDecodeMapLength.bind(this, length2, typeMapping); - } - return this.#decodeMapItems(length2, typeMapping, chunk); - } - #continueDecodeMapLength(lengthCb, typeMapping, chunk) { - const length2 = lengthCb(chunk); - return typeof length2 === "function" ? this.#continueDecodeMapLength.bind(this, length2, typeMapping) : this.#decodeMapItems(length2, typeMapping, chunk); - } - #decodeMapItems(length2, typeMapping, chunk) { - switch (typeMapping[exports2.RESP_TYPES.MAP]) { - case Map: - return this.#decodeMapAsMap(/* @__PURE__ */ new Map(), length2, typeMapping, chunk); - case Array: - return this.#decodeArrayItems(new Array(length2 * 2), 0, typeMapping, chunk); - default: - return this.#decodeMapAsObject(/* @__PURE__ */ Object.create(null), length2, typeMapping, chunk); - } - } - #decodeMapAsMap(map, remaining, typeMapping, chunk) { - while (remaining > 0) { - if (this.#cursor >= chunk.length) { - return this.#decodeMapAsMap.bind(this, map, remaining, typeMapping); - } - const key = this.#decodeMapKey(typeMapping, chunk); - if (typeof key === "function") { - return this.#continueDecodeMapKey.bind(this, map, remaining, key, typeMapping); - } - if (this.#cursor >= chunk.length) { - return this.#continueDecodeMapValue.bind(this, map, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); - } - const value = this.#decodeNestedType(typeMapping, chunk); - if (typeof value === "function") { - return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); - } - map.set(key, value); - --remaining; - } - return map; - } - #decodeMapKey(typeMapping, chunk) { - const type = chunk[this.#cursor]; - return ++this.#cursor === chunk.length ? this.#decodeMapKeyValue.bind(this, type, typeMapping) : this.#decodeMapKeyValue(type, typeMapping, chunk); - } - #decodeMapKeyValue(type, typeMapping, chunk) { - switch (type) { - // decode simple string map key as string (and not as buffer) - case exports2.RESP_TYPES.SIMPLE_STRING: - return this.#decodeSimpleString(String, chunk); - // decode blob string map key as string (and not as buffer) - case exports2.RESP_TYPES.BLOB_STRING: - return this.#decodeBlobString(String, chunk); - default: - return this.#decodeNestedTypeValue(type, typeMapping, chunk); - } - } - #continueDecodeMapKey(map, remaining, keyCb, typeMapping, chunk) { - const key = keyCb(chunk); - if (typeof key === "function") { - return this.#continueDecodeMapKey.bind(this, map, remaining, key, typeMapping); - } - if (this.#cursor >= chunk.length) { - return this.#continueDecodeMapValue.bind(this, map, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); - } - const value = this.#decodeNestedType(typeMapping, chunk); - if (typeof value === "function") { - return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); - } - map.set(key, value); - return this.#decodeMapAsMap(map, remaining - 1, typeMapping, chunk); - } - #continueDecodeMapValue(map, remaining, key, valueCb, typeMapping, chunk) { - const value = valueCb(chunk); - if (typeof value === "function") { - return this.#continueDecodeMapValue.bind(this, map, remaining, key, value, typeMapping); - } - map.set(key, value); - return this.#decodeMapAsMap(map, remaining - 1, typeMapping, chunk); - } - #decodeMapAsObject(object2, remaining, typeMapping, chunk) { - while (remaining > 0) { - if (this.#cursor >= chunk.length) { - return this.#decodeMapAsObject.bind(this, object2, remaining, typeMapping); - } - const key = this.#decodeMapKey(typeMapping, chunk); - if (typeof key === "function") { - return this.#continueDecodeMapAsObjectKey.bind(this, object2, remaining, key, typeMapping); - } - if (this.#cursor >= chunk.length) { - return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); - } - const value = this.#decodeNestedType(typeMapping, chunk); - if (typeof value === "function") { - return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); - } - object2[key] = value; - --remaining; - } - return object2; - } - #continueDecodeMapAsObjectKey(object2, remaining, keyCb, typeMapping, chunk) { - const key = keyCb(chunk); - if (typeof key === "function") { - return this.#continueDecodeMapAsObjectKey.bind(this, object2, remaining, key, typeMapping); - } - if (this.#cursor >= chunk.length) { - return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, this.#decodeNestedType.bind(this, typeMapping), typeMapping); - } - const value = this.#decodeNestedType(typeMapping, chunk); - if (typeof value === "function") { - return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); - } - object2[key] = value; - return this.#decodeMapAsObject(object2, remaining - 1, typeMapping, chunk); - } - #continueDecodeMapAsObjectValue(object2, remaining, key, valueCb, typeMapping, chunk) { - const value = valueCb(chunk); - if (typeof value === "function") { - return this.#continueDecodeMapAsObjectValue.bind(this, object2, remaining, key, value, typeMapping); - } - object2[key] = value; - return this.#decodeMapAsObject(object2, remaining - 1, typeMapping, chunk); + }, + transformReply: { + 2: (reply, preserve, typeMapping) => { + return reply.map((item) => { + const inferred = item; + return { + count: inferred[1], + reason: inferred[3], + context: inferred[5], + object: inferred[7], + username: inferred[9], + "age-seconds": generic_transformers_1.transformDoubleReply[2](inferred[11], preserve, typeMapping), + "client-info": inferred[13], + "entry-id": inferred[15], + "timestamp-created": inferred[17], + "timestamp-last-updated": inferred[19] + }; + }); + }, + 3: void 0 } }; - exports2.Decoder = Decoder2; - _a2 = Decoder2; } }); -var require_lua_script = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/lua-script.js"(exports2) { +var require_ACL_LOG_RESET = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOG_RESET.js"(exports2) { "use strict"; + var __importDefault = exports2 && exports2.__importDefault || function(mod) { + return mod && mod.__esModule ? mod : { "default": mod }; + }; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.scriptSha1 = exports2.defineScript = void 0; - var node_crypto_1 = __require2("node:crypto"); - function defineScript(script) { - return { - ...script, - SHA1: scriptSha1(script.SCRIPT) - }; - } - exports2.defineScript = defineScript; - function scriptSha1(script) { - return (0, node_crypto_1.createHash)("sha1").update(script).digest("hex"); - } - exports2.scriptSha1 = scriptSha1; + var ACL_LOG_1 = __importDefault(require_ACL_LOG()); + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: ACL_LOG_1.default.IS_READ_ONLY, + /** + * Clears the ACL security events log + * @param parser - The Redis command parser + */ + parseCommand(parser3) { + parser3.push("ACL", "LOG", "RESET"); + }, + transformReply: void 0 + }; } }); -var require_ACL_CAT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_CAT.js"(exports2) { +var require_ACL_SAVE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_SAVE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Lists ACL categories or commands in a category + * Saves the current ACL configuration to the ACL file * @param parser - The Redis command parser - * @param categoryName - Optional category name to filter commands */ - parseCommand(parser3, categoryName) { - parser3.push("ACL", "CAT"); - if (categoryName) { - parser3.push(categoryName); - } + parseCommand(parser3) { + parser3.push("ACL", "SAVE"); }, transformReply: void 0 }; } }); -var require_ACL_DELUSER = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_DELUSER.js"(exports2) { +var require_ACL_SETUSER = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_SETUSER.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Deletes one or more users from the ACL + * Creates or modifies ACL user with specified rules * @param parser - The Redis command parser - * @param username - Username(s) to delete + * @param username - Username to create or modify + * @param rule - ACL rule(s) to apply to the user */ - parseCommand(parser3, username) { - parser3.push("ACL", "DELUSER"); - parser3.pushVariadic(username); + parseCommand(parser3, username, rule) { + parser3.push("ACL", "SETUSER", username); + parser3.pushVariadic(rule); }, transformReply: void 0 }; } }); -var require_ACL_DRYRUN = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_DRYRUN.js"(exports2) { +var require_ACL_USERS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_USERS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Simulates ACL operations without executing them + * Returns a list of all configured ACL usernames * @param parser - The Redis command parser - * @param username - Username to simulate ACL operations for - * @param command - Command arguments to simulate */ - parseCommand(parser3, username, command2) { - parser3.push("ACL", "DRYRUN", username, ...command2); + parseCommand(parser3) { + parser3.push("ACL", "USERS"); }, transformReply: void 0 }; } }); -var require_ACL_GENPASS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_GENPASS.js"(exports2) { +var require_ACL_WHOAMI = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_WHOAMI.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Generates a secure password for ACL users + * Returns the username of the current connection * @param parser - The Redis command parser - * @param bits - Optional number of bits for password entropy */ - parseCommand(parser3, bits) { - parser3.push("ACL", "GENPASS"); - if (bits) { - parser3.push(bits.toString()); - } + parseCommand(parser3) { + parser3.push("ACL", "WHOAMI"); }, transformReply: void 0 }; } }); -var require_ACL_GETUSER = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_GETUSER.js"(exports2) { +var require_APPEND = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/APPEND.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + IS_READ_ONLY: false, + /** + * Appends a value to a string key + * @param parser - The Redis command parser + * @param key - The key to append to + * @param value - The value to append + */ + parseCommand(parser3, key, value) { + parser3.push("APPEND", key, value); + }, + transformReply: void 0 + }; + } +}); +var require_ASKING = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ASKING.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.ASKING_CMD = void 0; + exports2.ASKING_CMD = "ASKING"; exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns ACL information about a specific user + * Tells a Redis cluster node that the client is ok receiving such redirects * @param parser - The Redis command parser - * @param username - Username to get information for */ - parseCommand(parser3, username) { - parser3.push("ACL", "GETUSER", username); + parseCommand(parser3) { + parser3.push(exports2.ASKING_CMD); }, - transformReply: { - 2: (reply) => ({ - flags: reply[1], - passwords: reply[3], - commands: reply[5], - keys: reply[7], - channels: reply[9], - selectors: reply[11]?.map((selector) => { - const inferred = selector; - return { - commands: inferred[1], - keys: inferred[3], - channels: inferred[5] - }; - }) - }), - 3: void 0 - } + transformReply: void 0 }; } }); -var require_ACL_LIST = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LIST.js"(exports2) { +var require_AUTH = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/AUTH.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns all configured ACL users and their permissions + * Authenticates the connection using a password or username and password * @param parser - The Redis command parser + * @param options - Authentication options containing username and/or password + * @param options.username - Optional username for authentication + * @param options.password - Password for authentication */ - parseCommand(parser3) { - parser3.push("ACL", "LIST"); + parseCommand(parser3, { username, password }) { + parser3.push("AUTH"); + if (username !== void 0) { + parser3.push(username); + } + parser3.push(password); }, transformReply: void 0 }; } }); -var require_ACL_LOAD = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOAD.js"(exports2) { +var require_BGREWRITEAOF = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BGREWRITEAOF.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Reloads ACL configuration from the ACL file + * Asynchronously rewrites the append-only file * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("ACL", "LOAD"); + parser3.push("BGREWRITEAOF"); }, transformReply: void 0 }; } }); -var require_parser = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/client/parser.js"(exports2) { +var require_BGSAVE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BGSAVE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.BasicCommandParser = void 0; - var BasicCommandParser = class { - #redisArgs = []; - #keys = []; - preserve; - get redisArgs() { - return this.#redisArgs; - } - get keys() { - return this.#keys; - } - get firstKey() { - return this.#keys[0]; - } - get cacheKey() { - const tmp = new Array(this.#redisArgs.length * 2); - for (let i2 = 0; i2 < this.#redisArgs.length; i2++) { - tmp[i2] = this.#redisArgs[i2].length; - tmp[i2 + this.#redisArgs.length] = this.#redisArgs[i2]; + exports2.default = { + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, + /** + * Asynchronously saves the dataset to disk + * @param parser - The Redis command parser + * @param options - Optional configuration + * @param options.SCHEDULE - Schedule a BGSAVE operation when no BGSAVE is already in progress + */ + parseCommand(parser3, options2) { + parser3.push("BGSAVE"); + if (options2?.SCHEDULE) { + parser3.push("SCHEDULE"); } - return tmp.join("_"); - } - push(...arg) { - this.#redisArgs.push(...arg); - } - pushVariadic(vals) { - if (Array.isArray(vals)) { - for (const val of vals) { - this.push(val); + }, + transformReply: void 0 + }; + } +}); +var require_BITCOUNT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITCOUNT.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + CACHEABLE: true, + IS_READ_ONLY: true, + /** + * Returns the count of set bits in a string key + * @param parser - The Redis command parser + * @param key - The key to count bits in + * @param range - Optional range specification + * @param range.start - Start offset in bytes/bits + * @param range.end - End offset in bytes/bits + * @param range.mode - Optional counting mode: BYTE or BIT + */ + parseCommand(parser3, key, range) { + parser3.push("BITCOUNT"); + parser3.pushKey(key); + if (range) { + parser3.push(range.start.toString()); + parser3.push(range.end.toString()); + if (range.mode) { + parser3.push(range.mode); } - } else { - this.push(vals); } - } - pushVariadicWithLength(vals) { - if (Array.isArray(vals)) { - this.#redisArgs.push(vals.length.toString()); - } else { - this.#redisArgs.push("1"); + }, + transformReply: void 0 + }; + } +}); +var require_BITFIELD_RO = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITFIELD_RO.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + CACHEABLE: true, + IS_READ_ONLY: true, + /** + * Performs read-only bitfield integer operations on strings + * @param parser - The Redis command parser + * @param key - The key holding the string + * @param operations - Array of GET operations to perform on the bitfield + */ + parseCommand(parser3, key, operations) { + parser3.push("BITFIELD_RO"); + parser3.pushKey(key); + for (const operation of operations) { + parser3.push("GET"); + parser3.push(operation.encoding); + parser3.push(operation.offset.toString()); } - this.pushVariadic(vals); - } - pushVariadicNumber(vals) { - if (Array.isArray(vals)) { - for (const val of vals) { - this.push(val.toString()); + }, + transformReply: void 0 + }; + } +}); +var require_BITFIELD = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITFIELD.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + IS_READ_ONLY: false, + /** + * Performs arbitrary bitfield integer operations on strings + * @param parser - The Redis command parser + * @param key - The key holding the string + * @param operations - Array of bitfield operations to perform: GET, SET, INCRBY or OVERFLOW + */ + parseCommand(parser3, key, operations) { + parser3.push("BITFIELD"); + parser3.pushKey(key); + for (const options2 of operations) { + switch (options2.operation) { + case "GET": + parser3.push("GET", options2.encoding, options2.offset.toString()); + break; + case "SET": + parser3.push("SET", options2.encoding, options2.offset.toString(), options2.value.toString()); + break; + case "INCRBY": + parser3.push("INCRBY", options2.encoding, options2.offset.toString(), options2.increment.toString()); + break; + case "OVERFLOW": + parser3.push("OVERFLOW", options2.behavior); + break; } - } else { - this.push(vals.toString()); } - } - pushKey(key) { - this.#keys.push(key); - this.#redisArgs.push(key); - } - pushKeysLength(keys) { - if (Array.isArray(keys)) { - this.#redisArgs.push(keys.length.toString()); - } else { - this.#redisArgs.push("1"); + }, + transformReply: void 0 + }; + } +}); +var require_BITOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITOP.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + IS_READ_ONLY: false, + /** + * Performs bitwise operations between strings + * @param parser - The Redis command parser + * @param operation - Bitwise operation to perform: AND, OR, XOR, NOT, DIFF, DIFF1, ANDOR, ONE + * @param destKey - Destination key to store the result + * @param key - Source key(s) to perform operation on + */ + parseCommand(parser3, operation, destKey, key) { + parser3.push("BITOP", operation); + parser3.pushKey(destKey); + parser3.pushKeys(key); + }, + transformReply: void 0 + }; + } +}); +var require_BITPOS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITPOS.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + CACHEABLE: true, + IS_READ_ONLY: true, + /** + * Returns the position of first bit set to 0 or 1 in a string + * @param parser - The Redis command parser + * @param key - The key holding the string + * @param bit - The bit value to look for (0 or 1) + * @param start - Optional starting position in bytes/bits + * @param end - Optional ending position in bytes/bits + * @param mode - Optional counting mode: BYTE or BIT + */ + parseCommand(parser3, key, bit, start, end, mode) { + parser3.push("BITPOS"); + parser3.pushKey(key); + parser3.push(bit.toString()); + if (start !== void 0) { + parser3.push(start.toString()); } - this.pushKeys(keys); - } - pushKeys(keys) { - if (Array.isArray(keys)) { - this.#keys.push(...keys); - this.#redisArgs.push(...keys); - } else { - this.#keys.push(keys); - this.#redisArgs.push(keys); + if (end !== void 0) { + parser3.push(end.toString()); } - } + if (mode) { + parser3.push(mode); + } + }, + transformReply: void 0 }; - exports2.BasicCommandParser = BasicCommandParser; } }); -var require_generic_transformers = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/generic-transformers.js"(exports2) { +var require_BLMOVE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLMOVE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.transformRedisJsonNullReply = exports2.transformRedisJsonReply = exports2.transformRedisJsonArgument = exports2.transformStreamsMessagesReplyResp3 = exports2.transformStreamsMessagesReplyResp2 = exports2.transformStreamMessagesReply = exports2.transformStreamMessageNullReply = exports2.transformStreamMessageReply = exports2.parseArgs = exports2.parseZKeysArguments = exports2.transformRangeReply = exports2.parseSlotRangesArguments = exports2.transformFunctionListItemReply = exports2.RedisFunctionFlags = exports2.transformCommandReply = exports2.CommandCategories = exports2.CommandFlags = exports2.parseOptionalVariadicArgument = exports2.pushVariadicArgument = exports2.pushVariadicNumberArguments = exports2.pushVariadicArguments = exports2.pushEvalArguments = exports2.evalFirstKeyIndex = exports2.transformPXAT = exports2.transformEXAT = exports2.transformSortedSetReply = exports2.transformTuplesReply = exports2.createTransformTuplesReplyFunc = exports2.transformTuplesToMap = exports2.transformNullableDoubleReply = exports2.createTransformNullableDoubleReplyResp2Func = exports2.transformDoubleArrayReply = exports2.createTransformDoubleReplyResp2Func = exports2.transformDoubleReply = exports2.transformStringDoubleArgument = exports2.transformDoubleArgument = exports2.transformBooleanArrayReply = exports2.transformBooleanReply = exports2.isArrayReply = exports2.isNullReply = void 0; - var parser_1 = require_parser(); - var decoder_1 = require_decoder(); - function isNullReply(reply) { - return reply === null; - } - exports2.isNullReply = isNullReply; - function isArrayReply(reply) { - return Array.isArray(reply); - } - exports2.isArrayReply = isArrayReply; - exports2.transformBooleanReply = { - 2: (reply) => reply === 1, - 3: void 0 - }; - exports2.transformBooleanArrayReply = { - 2: (reply) => { - return reply.map(exports2.transformBooleanReply[2]); + exports2.default = { + IS_READ_ONLY: false, + /** + * Pop an element from a list, push it to another list and return it; or block until one is available + * @param parser - The Redis command parser + * @param source - Key of the source list + * @param destination - Key of the destination list + * @param sourceSide - Side of source list to pop from (LEFT or RIGHT) + * @param destinationSide - Side of destination list to push to (LEFT or RIGHT) + * @param timeout - Timeout in seconds, 0 to block indefinitely + */ + parseCommand(parser3, source, destination, sourceSide, destinationSide, timeout) { + parser3.push("BLMOVE"); + parser3.pushKeys([source, destination]); + parser3.push(sourceSide, destinationSide, timeout.toString()); }, - 3: void 0 + transformReply: void 0 }; - function transformDoubleArgument(num) { - switch (num) { - case Infinity: - return "+inf"; - case -Infinity: - return "-inf"; - default: - return num.toString(); + } +}); +var require_LMPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/LMPOP.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.parseLMPopArguments = void 0; + function parseLMPopArguments(parser3, keys, side, options2) { + parser3.pushKeysLength(keys); + parser3.push(side); + if (options2?.COUNT !== void 0) { + parser3.push("COUNT", options2.COUNT.toString()); } } - exports2.transformDoubleArgument = transformDoubleArgument; - function transformStringDoubleArgument(num) { - if (typeof num !== "number") - return num; - return transformDoubleArgument(num); - } - exports2.transformStringDoubleArgument = transformStringDoubleArgument; - exports2.transformDoubleReply = { - 2: (reply, preserve, typeMapping) => { - const double = typeMapping ? typeMapping[decoder_1.RESP_TYPES.DOUBLE] : void 0; - switch (double) { - case String: { - return reply; - } - default: { - let ret; - switch (reply.toString()) { - case "inf": - case "+inf": - ret = Infinity; - case "-inf": - ret = -Infinity; - case "nan": - ret = NaN; - default: - ret = Number(reply); - } - return ret; - } - } + exports2.parseLMPopArguments = parseLMPopArguments; + exports2.default = { + IS_READ_ONLY: false, + /** + * Constructs the LMPOP command + * + * @param parser - The command parser + * @param args - Arguments including keys, side (LEFT or RIGHT), and options + * @see https://redis.io/commands/lmpop/ + */ + parseCommand(parser3, ...args) { + parser3.push("LMPOP"); + parseLMPopArguments(parser3, ...args); }, - 3: void 0 + transformReply: void 0 }; - function createTransformDoubleReplyResp2Func(preserve, typeMapping) { - return (reply) => { - return exports2.transformDoubleReply[2](reply, preserve, typeMapping); - }; - } - exports2.createTransformDoubleReplyResp2Func = createTransformDoubleReplyResp2Func; - exports2.transformDoubleArrayReply = { - 2: (reply, preserve, typeMapping) => { - return reply.map(createTransformDoubleReplyResp2Func(preserve, typeMapping)); + } +}); +var require_BLMPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLMPOP.js"(exports2) { + "use strict"; + var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o2, m3, k, k2) { + if (k2 === void 0) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m3, k); + if (!desc || ("get" in desc ? !m3.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m3[k]; + } }; + } + Object.defineProperty(o2, k2, desc); + } : function(o2, m3, k, k2) { + if (k2 === void 0) k2 = k; + o2[k2] = m3[k]; + }); + var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o2, v2) { + Object.defineProperty(o2, "default", { enumerable: true, value: v2 }); + } : function(o2, v2) { + o2["default"] = v2; + }); + var __importStar = exports2 && exports2.__importStar || function(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) { + for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + } + __setModuleDefault(result, mod); + return result; + }; + Object.defineProperty(exports2, "__esModule", { value: true }); + var LMPOP_1 = __importStar(require_LMPOP()); + exports2.default = { + IS_READ_ONLY: false, + /** + * Pops elements from multiple lists; blocks until elements are available + * @param parser - The Redis command parser + * @param timeout - Timeout in seconds, 0 to block indefinitely + * @param args - Additional arguments for LMPOP command + */ + parseCommand(parser3, timeout, ...args) { + parser3.push("BLMPOP", timeout.toString()); + (0, LMPOP_1.parseLMPopArguments)(parser3, ...args); }, - 3: void 0 + transformReply: LMPOP_1.default.transformReply }; - function createTransformNullableDoubleReplyResp2Func(preserve, typeMapping) { - return (reply) => { - return exports2.transformNullableDoubleReply[2](reply, preserve, typeMapping); - }; - } - exports2.createTransformNullableDoubleReplyResp2Func = createTransformNullableDoubleReplyResp2Func; - exports2.transformNullableDoubleReply = { - 2: (reply, preserve, typeMapping) => { + } +}); +var require_BLPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLPOP.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + IS_READ_ONLY: true, + /** + * Removes and returns the first element in a list, or blocks until one is available + * @param parser - The Redis command parser + * @param key - Key of the list to pop from, or array of keys to try sequentially + * @param timeout - Maximum seconds to block, 0 to block indefinitely + */ + parseCommand(parser3, key, timeout) { + parser3.push("BLPOP"); + parser3.pushKeys(key); + parser3.push(timeout.toString()); + }, + transformReply(reply) { if (reply === null) return null; - return exports2.transformDoubleReply[2](reply, preserve, typeMapping); + return { + key: reply[0], + element: reply[1] + }; + } + }; + } +}); +var require_BRPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BRPOP.js"(exports2) { + "use strict"; + var __importDefault = exports2 && exports2.__importDefault || function(mod) { + return mod && mod.__esModule ? mod : { "default": mod }; + }; + Object.defineProperty(exports2, "__esModule", { value: true }); + var BLPOP_1 = __importDefault(require_BLPOP()); + exports2.default = { + IS_READ_ONLY: true, + /** + * Removes and returns the last element in a list, or blocks until one is available + * @param parser - The Redis command parser + * @param key - Key of the list to pop from, or array of keys to try sequentially + * @param timeout - Maximum seconds to block, 0 to block indefinitely + */ + parseCommand(parser3, key, timeout) { + parser3.push("BRPOP"); + parser3.pushKeys(key); + parser3.push(timeout.toString()); }, - 3: void 0 + transformReply: BLPOP_1.default.transformReply }; - function transformTuplesToMap(reply, func) { - const message = /* @__PURE__ */ Object.create(null); - for (let i2 = 0; i2 < reply.length; i2 += 2) { - message[reply[i2].toString()] = func(reply[i2 + 1]); - } - return message; - } - exports2.transformTuplesToMap = transformTuplesToMap; - function createTransformTuplesReplyFunc(preserve, typeMapping) { - return (reply) => { - return transformTuplesReply(reply, preserve, typeMapping); - }; - } - exports2.createTransformTuplesReplyFunc = createTransformTuplesReplyFunc; - function transformTuplesReply(reply, preserve, typeMapping) { - const mapType = typeMapping ? typeMapping[decoder_1.RESP_TYPES.MAP] : void 0; - const inferred = reply; - switch (mapType) { - case Array: { - return reply; - } - case Map: { - const ret = /* @__PURE__ */ new Map(); - for (let i2 = 0; i2 < inferred.length; i2 += 2) { - ret.set(inferred[i2].toString(), inferred[i2 + 1]); - } - return ret; - ; - } - default: { - const ret = /* @__PURE__ */ Object.create(null); - for (let i2 = 0; i2 < inferred.length; i2 += 2) { - ret[inferred[i2].toString()] = inferred[i2 + 1]; - } - return ret; - ; - } + } +}); +var require_BRPOPLPUSH = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BRPOPLPUSH.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.default = { + IS_READ_ONLY: false, + /** + * Pops an element from a list, pushes it to another list and returns it; blocks until element is available + * @param parser - The Redis command parser + * @param source - Key of the source list to pop from + * @param destination - Key of the destination list to push to + * @param timeout - Maximum seconds to block, 0 to block indefinitely + */ + parseCommand(parser3, source, destination, timeout) { + parser3.push("BRPOPLPUSH"); + parser3.pushKeys([source, destination]); + parser3.push(timeout.toString()); + }, + transformReply: void 0 + }; + } +}); +var require_ZMPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ZMPOP.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.parseZMPopArguments = void 0; + var generic_transformers_1 = require_generic_transformers(); + function parseZMPopArguments(parser3, keys, side, options2) { + parser3.pushKeysLength(keys); + parser3.push(side); + if (options2?.COUNT) { + parser3.push("COUNT", options2.COUNT.toString()); } } - exports2.transformTuplesReply = transformTuplesReply; - exports2.transformSortedSetReply = { - 2: (reply, preserve, typeMapping) => { - const inferred = reply, members = []; - for (let i2 = 0; i2 < inferred.length; i2 += 2) { - members.push({ - value: inferred[i2], - score: exports2.transformDoubleReply[2](inferred[i2 + 1], preserve, typeMapping) - }); - } - return members; + exports2.parseZMPopArguments = parseZMPopArguments; + exports2.default = { + IS_READ_ONLY: false, + /** + * Removes and returns up to count members with the highest/lowest scores from the first non-empty sorted set. + * @param parser - The Redis command parser. + * @param keys - Keys of the sorted sets to pop from. + * @param side - Side to pop from (MIN or MAX). + * @param options - Optional parameters including COUNT. + */ + parseCommand(parser3, keys, side, options2) { + parser3.push("ZMPOP"); + parseZMPopArguments(parser3, keys, side, options2); }, - 3: (reply) => { - return reply.map((member) => { - const [value, score] = member; - return { - value, - score + transformReply: { + 2(reply, preserve, typeMapping) { + return reply === null ? null : { + key: reply[0], + members: reply[1].map((member) => { + const [value, score] = member; + return { + value, + score: generic_transformers_1.transformDoubleReply[2](score, preserve, typeMapping) + }; + }) + }; + }, + 3(reply) { + return reply === null ? null : { + key: reply[0], + members: generic_transformers_1.transformSortedSetReply[3](reply[1]) }; - }); - } - }; - function transformEXAT(EXAT) { - return (typeof EXAT === "number" ? EXAT : Math.floor(EXAT.getTime() / 1e3)).toString(); - } - exports2.transformEXAT = transformEXAT; - function transformPXAT(PXAT) { - return (typeof PXAT === "number" ? PXAT : PXAT.getTime()).toString(); - } - exports2.transformPXAT = transformPXAT; - function evalFirstKeyIndex(options2) { - return options2?.keys?.[0]; - } - exports2.evalFirstKeyIndex = evalFirstKeyIndex; - function pushEvalArguments(args, options2) { - if (options2?.keys) { - args.push(options2.keys.length.toString(), ...options2.keys); - } else { - args.push("0"); - } - if (options2?.arguments) { - args.push(...options2.arguments); - } - return args; - } - exports2.pushEvalArguments = pushEvalArguments; - function pushVariadicArguments(args, value) { - if (Array.isArray(value)) { - args = args.concat(value); - } else { - args.push(value); - } - return args; - } - exports2.pushVariadicArguments = pushVariadicArguments; - function pushVariadicNumberArguments(args, value) { - if (Array.isArray(value)) { - for (const item of value) { - args.push(item.toString()); - } - } else { - args.push(value.toString()); - } - return args; - } - exports2.pushVariadicNumberArguments = pushVariadicNumberArguments; - function pushVariadicArgument(args, value) { - if (Array.isArray(value)) { - args.push(value.length.toString(), ...value); - } else { - args.push("1", value); - } - return args; - } - exports2.pushVariadicArgument = pushVariadicArgument; - function parseOptionalVariadicArgument(parser3, name, value) { - if (value === void 0) - return; - parser3.push(name); - parser3.pushVariadicWithLength(value); - } - exports2.parseOptionalVariadicArgument = parseOptionalVariadicArgument; - var CommandFlags; - (function(CommandFlags2) { - CommandFlags2["WRITE"] = "write"; - CommandFlags2["READONLY"] = "readonly"; - CommandFlags2["DENYOOM"] = "denyoom"; - CommandFlags2["ADMIN"] = "admin"; - CommandFlags2["PUBSUB"] = "pubsub"; - CommandFlags2["NOSCRIPT"] = "noscript"; - CommandFlags2["RANDOM"] = "random"; - CommandFlags2["SORT_FOR_SCRIPT"] = "sort_for_script"; - CommandFlags2["LOADING"] = "loading"; - CommandFlags2["STALE"] = "stale"; - CommandFlags2["SKIP_MONITOR"] = "skip_monitor"; - CommandFlags2["ASKING"] = "asking"; - CommandFlags2["FAST"] = "fast"; - CommandFlags2["MOVABLEKEYS"] = "movablekeys"; - })(CommandFlags || (exports2.CommandFlags = CommandFlags = {})); - var CommandCategories; - (function(CommandCategories2) { - CommandCategories2["KEYSPACE"] = "@keyspace"; - CommandCategories2["READ"] = "@read"; - CommandCategories2["WRITE"] = "@write"; - CommandCategories2["SET"] = "@set"; - CommandCategories2["SORTEDSET"] = "@sortedset"; - CommandCategories2["LIST"] = "@list"; - CommandCategories2["HASH"] = "@hash"; - CommandCategories2["STRING"] = "@string"; - CommandCategories2["BITMAP"] = "@bitmap"; - CommandCategories2["HYPERLOGLOG"] = "@hyperloglog"; - CommandCategories2["GEO"] = "@geo"; - CommandCategories2["STREAM"] = "@stream"; - CommandCategories2["PUBSUB"] = "@pubsub"; - CommandCategories2["ADMIN"] = "@admin"; - CommandCategories2["FAST"] = "@fast"; - CommandCategories2["SLOW"] = "@slow"; - CommandCategories2["BLOCKING"] = "@blocking"; - CommandCategories2["DANGEROUS"] = "@dangerous"; - CommandCategories2["CONNECTION"] = "@connection"; - CommandCategories2["TRANSACTION"] = "@transaction"; - CommandCategories2["SCRIPTING"] = "@scripting"; - })(CommandCategories || (exports2.CommandCategories = CommandCategories = {})); - function transformCommandReply([name, arity, flags, firstKeyIndex, lastKeyIndex, step, categories]) { - return { - name, - arity, - flags: new Set(flags), - firstKeyIndex, - lastKeyIndex, - step, - categories: new Set(categories) - }; - } - exports2.transformCommandReply = transformCommandReply; - var RedisFunctionFlags; - (function(RedisFunctionFlags2) { - RedisFunctionFlags2["NO_WRITES"] = "no-writes"; - RedisFunctionFlags2["ALLOW_OOM"] = "allow-oom"; - RedisFunctionFlags2["ALLOW_STALE"] = "allow-stale"; - RedisFunctionFlags2["NO_CLUSTER"] = "no-cluster"; - })(RedisFunctionFlags || (exports2.RedisFunctionFlags = RedisFunctionFlags = {})); - function transformFunctionListItemReply(reply) { - return { - libraryName: reply[1], - engine: reply[3], - functions: reply[5].map((fn) => ({ - name: fn[1], - description: fn[3], - flags: fn[5] - })) - }; - } - exports2.transformFunctionListItemReply = transformFunctionListItemReply; - function parseSlotRangeArguments(parser3, range) { - parser3.push(range.start.toString(), range.end.toString()); - } - function parseSlotRangesArguments(parser3, ranges) { - if (Array.isArray(ranges)) { - for (const range of ranges) { - parseSlotRangeArguments(parser3, range); - } - } else { - parseSlotRangeArguments(parser3, ranges); - } - } - exports2.parseSlotRangesArguments = parseSlotRangesArguments; - function transformRangeReply([start, end]) { - return { - start, - end - }; - } - exports2.transformRangeReply = transformRangeReply; - function parseZKeysArguments(parser3, keys) { - if (Array.isArray(keys)) { - parser3.push(keys.length.toString()); - if (keys.length) { - if (isPlainKeys(keys)) { - parser3.pushKeys(keys); - } else { - for (let i2 = 0; i2 < keys.length; i2++) { - parser3.pushKey(keys[i2].key); - } - parser3.push("WEIGHTS"); - for (let i2 = 0; i2 < keys.length; i2++) { - parser3.push(transformDoubleArgument(keys[i2].weight)); - } - } - } - } else { - parser3.push("1"); - if (isPlainKey(keys)) { - parser3.pushKey(keys); - } else { - parser3.pushKey(keys.key); - parser3.push("WEIGHTS", transformDoubleArgument(keys.weight)); } } - } - exports2.parseZKeysArguments = parseZKeysArguments; - function isPlainKey(key) { - return typeof key === "string" || key instanceof Buffer; - } - function isPlainKeys(keys) { - return isPlainKey(keys[0]); - } - function parseArgs2(command2, ...args) { - const parser3 = new parser_1.BasicCommandParser(); - command2.parseCommand(parser3, ...args); - const redisArgs = parser3.redisArgs; - if (parser3.preserve) { - redisArgs.preserve = parser3.preserve; - } - return redisArgs; - } - exports2.parseArgs = parseArgs2; - function transformStreamMessageReply(typeMapping, reply) { - const [id, message] = reply; - return { - id, - message: transformTuplesReply(message, void 0, typeMapping) - }; - } - exports2.transformStreamMessageReply = transformStreamMessageReply; - function transformStreamMessageNullReply(typeMapping, reply) { - return isNullReply(reply) ? reply : transformStreamMessageReply(typeMapping, reply); - } - exports2.transformStreamMessageNullReply = transformStreamMessageNullReply; - function transformStreamMessagesReply(r, typeMapping) { - const reply = r; - return reply.map(transformStreamMessageReply.bind(void 0, typeMapping)); - } - exports2.transformStreamMessagesReply = transformStreamMessagesReply; - function transformStreamsMessagesReplyResp2(reply, preserve, typeMapping) { - if (reply === null) - return null; - switch (typeMapping ? typeMapping[decoder_1.RESP_TYPES.MAP] : void 0) { - /* FUTURE: a response type for when resp3 is working properly - case Map: { - const ret = new Map(); - - for (let i=0; i < reply.length; i++) { - const stream = reply[i] as unknown as UnwrapReply; - - const name = stream[0]; - const rawMessages = stream[1]; - - ret.set(name.toString(), transformStreamMessagesReply(rawMessages, typeMapping)); - } - - return ret as unknown as MapReply; - } - case Array: { - const ret: Array = []; - - for (let i=0; i < reply.length; i++) { - const stream = reply[i] as unknown as UnwrapReply; - - const name = stream[0]; - const rawMessages = stream[1]; - - ret.push(name); - ret.push(transformStreamMessagesReply(rawMessages, typeMapping)); - } - - return ret as unknown as MapReply; - } - default: { - const ret: Record = Object.create(null); - - for (let i=0; i < reply.length; i++) { - const stream = reply[i] as unknown as UnwrapReply; - - const name = stream[0] as unknown as UnwrapReply; - const rawMessages = stream[1]; - - ret[name.toString()] = transformStreamMessagesReply(rawMessages); - } - - return ret as unknown as MapReply; - } - */ - // V4 compatible response type - default: { - const ret = []; - for (let i2 = 0; i2 < reply.length; i2++) { - const stream = reply[i2]; - ret.push({ - name: stream[0], - messages: transformStreamMessagesReply(stream[1]) - }); - } - return ret; - } + }; + } +}); +var require_BZMPOP = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZMPOP.js"(exports2) { + "use strict"; + var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o2, m3, k, k2) { + if (k2 === void 0) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m3, k); + if (!desc || ("get" in desc ? !m3.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { + return m3[k]; + } }; } - } - exports2.transformStreamsMessagesReplyResp2 = transformStreamsMessagesReplyResp2; - function transformStreamsMessagesReplyResp3(reply) { - if (reply === null) - return null; - if (reply instanceof Map) { - const ret = /* @__PURE__ */ new Map(); - for (const [n, rawMessages] of reply) { - const name = n; - ret.set(name.toString(), transformStreamMessagesReply(rawMessages)); - } - return ret; - } else if (reply instanceof Array) { - const ret = []; - for (let i2 = 0; i2 < reply.length; i2 += 2) { - const name = reply[i2]; - const rawMessages = reply[i2 + 1]; - ret.push(name); - ret.push(transformStreamMessagesReply(rawMessages)); - } - return ret; - } else { - const ret = /* @__PURE__ */ Object.create(null); - for (const [name, rawMessages] of Object.entries(reply)) { - ret[name] = transformStreamMessagesReply(rawMessages); - } - return ret; + Object.defineProperty(o2, k2, desc); + } : function(o2, m3, k, k2) { + if (k2 === void 0) k2 = k; + o2[k2] = m3[k]; + }); + var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o2, v2) { + Object.defineProperty(o2, "default", { enumerable: true, value: v2 }); + } : function(o2, v2) { + o2["default"] = v2; + }); + var __importStar = exports2 && exports2.__importStar || function(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) { + for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); } - } - exports2.transformStreamsMessagesReplyResp3 = transformStreamsMessagesReplyResp3; - function transformRedisJsonArgument(json) { - return JSON.stringify(json); - } - exports2.transformRedisJsonArgument = transformRedisJsonArgument; - function transformRedisJsonReply(json) { - const res = JSON.parse(json.toString()); - return res; - } - exports2.transformRedisJsonReply = transformRedisJsonReply; - function transformRedisJsonNullReply(json) { - return isNullReply(json) ? json : transformRedisJsonReply(json); - } - exports2.transformRedisJsonNullReply = transformRedisJsonNullReply; + __setModuleDefault(result, mod); + return result; + }; + Object.defineProperty(exports2, "__esModule", { value: true }); + var ZMPOP_1 = __importStar(require_ZMPOP()); + exports2.default = { + IS_READ_ONLY: false, + /** + * Removes and returns members from one or more sorted sets in the specified order; blocks until elements are available + * @param parser - The Redis command parser + * @param timeout - Maximum seconds to block, 0 to block indefinitely + * @param args - Additional arguments specifying the keys, min/max count, and order (MIN/MAX) + */ + parseCommand(parser3, timeout, ...args) { + parser3.push("BZMPOP", timeout.toString()); + (0, ZMPOP_1.parseZMPopArguments)(parser3, ...args); + }, + transformReply: ZMPOP_1.default.transformReply + }; } }); -var require_ACL_LOG = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOG.js"(exports2) { +var require_BZPOPMAX = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZPOPMAX.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); var generic_transformers_1 = require_generic_transformers(); exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, + IS_READ_ONLY: false, /** - * Returns ACL security events log entries + * Removes and returns the member with the highest score in a sorted set, or blocks until one is available * @param parser - The Redis command parser - * @param count - Optional maximum number of entries to return + * @param keys - Key of the sorted set, or array of keys to try sequentially + * @param timeout - Maximum seconds to block, 0 to block indefinitely */ - parseCommand(parser3, count) { - parser3.push("ACL", "LOG"); - if (count != void 0) { - parser3.push(count.toString()); - } + parseCommand(parser3, keys, timeout) { + parser3.push("BZPOPMAX"); + parser3.pushKeys(keys); + parser3.push(timeout.toString()); }, transformReply: { - 2: (reply, preserve, typeMapping) => { - return reply.map((item) => { - const inferred = item; - return { - count: inferred[1], - reason: inferred[3], - context: inferred[5], - object: inferred[7], - username: inferred[9], - "age-seconds": generic_transformers_1.transformDoubleReply[2](inferred[11], preserve, typeMapping), - "client-info": inferred[13], - "entry-id": inferred[15], - "timestamp-created": inferred[17], - "timestamp-last-updated": inferred[19] - }; - }); + 2(reply, preserve, typeMapping) { + return reply === null ? null : { + key: reply[0], + value: reply[1], + score: generic_transformers_1.transformDoubleReply[2](reply[2], preserve, typeMapping) + }; }, - 3: void 0 + 3(reply) { + return reply === null ? null : { + key: reply[0], + value: reply[1], + score: reply[2] + }; + } } }; } }); -var require_ACL_LOG_RESET = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_LOG_RESET.js"(exports2) { +var require_BZPOPMIN = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZPOPMIN.js"(exports2) { "use strict"; var __importDefault = exports2 && exports2.__importDefault || function(mod) { return mod && mod.__esModule ? mod : { "default": mod }; }; Object.defineProperty(exports2, "__esModule", { value: true }); - var ACL_LOG_1 = __importDefault(require_ACL_LOG()); + var BZPOPMAX_1 = __importDefault(require_BZPOPMAX()); exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: ACL_LOG_1.default.IS_READ_ONLY, + IS_READ_ONLY: BZPOPMAX_1.default.IS_READ_ONLY, /** - * Clears the ACL security events log + * Removes and returns the member with the lowest score in a sorted set, or blocks until one is available * @param parser - The Redis command parser + * @param keys - Key of the sorted set, or array of keys to try sequentially + * @param timeout - Maximum seconds to block, 0 to block indefinitely */ - parseCommand(parser3) { - parser3.push("ACL", "LOG", "RESET"); + parseCommand(parser3, keys, timeout) { + parser3.push("BZPOPMIN"); + parser3.pushKeys(keys); + parser3.push(timeout.toString()); }, - transformReply: void 0 + transformReply: BZPOPMAX_1.default.transformReply }; } }); -var require_ACL_SAVE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_SAVE.js"(exports2) { +var require_CLIENT_CACHING = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_CACHING.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Saves the current ACL configuration to the ACL file + * Instructs the server about tracking or not keys in the next request * @param parser - The Redis command parser + * @param value - Whether to enable (true) or disable (false) tracking */ - parseCommand(parser3) { - parser3.push("ACL", "SAVE"); + parseCommand(parser3, value) { + parser3.push("CLIENT", "CACHING", value ? "YES" : "NO"); }, transformReply: void 0 }; } }); -var require_ACL_SETUSER = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_SETUSER.js"(exports2) { +var require_CLIENT_GETNAME = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_GETNAME.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Creates or modifies ACL user with specified rules + * Returns the name of the current connection * @param parser - The Redis command parser - * @param username - Username to create or modify - * @param rule - ACL rule(s) to apply to the user */ - parseCommand(parser3, username, rule) { - parser3.push("ACL", "SETUSER", username); - parser3.pushVariadic(rule); + parseCommand(parser3) { + parser3.push("CLIENT", "GETNAME"); }, transformReply: void 0 }; } }); -var require_ACL_USERS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_USERS.js"(exports2) { +var require_CLIENT_GETREDIR = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_GETREDIR.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns a list of all configured ACL usernames + * Returns the ID of the client to which the current client is redirecting tracking notifications * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("ACL", "USERS"); + parser3.push("CLIENT", "GETREDIR"); }, transformReply: void 0 }; } }); -var require_ACL_WHOAMI = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ACL_WHOAMI.js"(exports2) { +var require_CLIENT_ID = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_ID.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the username of the current connection + * Returns the client ID for the current connection * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("ACL", "WHOAMI"); + parser3.push("CLIENT", "ID"); }, transformReply: void 0 }; } }); -var require_APPEND = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/APPEND.js"(exports2) { +var require_CLIENT_INFO = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_INFO.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); + var CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g; exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Appends a value to a string key + * Returns information and statistics about the current client connection * @param parser - The Redis command parser - * @param key - The key to append to - * @param value - The value to append */ - parseCommand(parser3, key, value) { - parser3.push("APPEND", key, value); + parseCommand(parser3) { + parser3.push("CLIENT", "INFO"); }, - transformReply: void 0 + transformReply(rawReply) { + const map = {}; + for (const item of rawReply.toString().matchAll(CLIENT_INFO_REGEX)) { + map[item[1]] = item[2]; + } + const reply = { + id: Number(map.id), + addr: map.addr, + fd: Number(map.fd), + name: map.name, + age: Number(map.age), + idle: Number(map.idle), + flags: map.flags, + db: Number(map.db), + sub: Number(map.sub), + psub: Number(map.psub), + multi: Number(map.multi), + qbuf: Number(map.qbuf), + qbufFree: Number(map["qbuf-free"]), + argvMem: Number(map["argv-mem"]), + obl: Number(map.obl), + oll: Number(map.oll), + omem: Number(map.omem), + totMem: Number(map["tot-mem"]), + events: map.events, + cmd: map.cmd, + user: map.user, + libName: map["lib-name"], + libVer: map["lib-ver"] + }; + if (map.laddr !== void 0) { + reply.laddr = map.laddr; + } + if (map.redir !== void 0) { + reply.redir = Number(map.redir); + } + if (map.ssub !== void 0) { + reply.ssub = Number(map.ssub); + } + if (map["multi-mem"] !== void 0) { + reply.multiMem = Number(map["multi-mem"]); + } + if (map.resp !== void 0) { + reply.resp = Number(map.resp); + } + return reply; + } }; } }); -var require_ASKING = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ASKING.js"(exports2) { +var require_CLIENT_KILL = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_KILL.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.ASKING_CMD = void 0; - exports2.ASKING_CMD = "ASKING"; + exports2.CLIENT_KILL_FILTERS = void 0; + exports2.CLIENT_KILL_FILTERS = { + ADDRESS: "ADDR", + LOCAL_ADDRESS: "LADDR", + ID: "ID", + TYPE: "TYPE", + USER: "USER", + SKIP_ME: "SKIPME", + MAXAGE: "MAXAGE" + }; exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Tells a Redis cluster node that the client is ok receiving such redirects + * Closes client connections matching the specified filters * @param parser - The Redis command parser + * @param filters - One or more filters to match client connections to kill */ - parseCommand(parser3) { - parser3.push(exports2.ASKING_CMD); + parseCommand(parser3, filters) { + parser3.push("CLIENT", "KILL"); + if (Array.isArray(filters)) { + for (const filter of filters) { + pushFilter(parser3, filter); + } + } else { + pushFilter(parser3, filters); + } }, transformReply: void 0 }; + function pushFilter(parser3, filter) { + if (filter === exports2.CLIENT_KILL_FILTERS.SKIP_ME) { + parser3.push("SKIPME"); + return; + } + parser3.push(filter.filter); + switch (filter.filter) { + case exports2.CLIENT_KILL_FILTERS.ADDRESS: + parser3.push(filter.address); + break; + case exports2.CLIENT_KILL_FILTERS.LOCAL_ADDRESS: + parser3.push(filter.localAddress); + break; + case exports2.CLIENT_KILL_FILTERS.ID: + parser3.push(typeof filter.id === "number" ? filter.id.toString() : filter.id); + break; + case exports2.CLIENT_KILL_FILTERS.TYPE: + parser3.push(filter.type); + break; + case exports2.CLIENT_KILL_FILTERS.USER: + parser3.push(filter.username); + break; + case exports2.CLIENT_KILL_FILTERS.SKIP_ME: + parser3.push(filter.skipMe ? "yes" : "no"); + break; + case exports2.CLIENT_KILL_FILTERS.MAXAGE: + parser3.push(filter.maxAge.toString()); + break; + } + } } }); -var require_AUTH = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/AUTH.js"(exports2) { +var require_CLIENT_LIST = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_LIST.js"(exports2) { "use strict"; + var __importDefault = exports2 && exports2.__importDefault || function(mod) { + return mod && mod.__esModule ? mod : { "default": mod }; + }; Object.defineProperty(exports2, "__esModule", { value: true }); + var CLIENT_INFO_1 = __importDefault(require_CLIENT_INFO()); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Authenticates the connection using a password or username and password + * Returns information about all client connections. Can be filtered by type or ID * @param parser - The Redis command parser - * @param options - Authentication options containing username and/or password - * @param options.username - Optional username for authentication - * @param options.password - Password for authentication + * @param filter - Optional filter to return only specific client types or IDs */ - parseCommand(parser3, { username, password }) { - parser3.push("AUTH"); - if (username !== void 0) { - parser3.push(username); + parseCommand(parser3, filter) { + parser3.push("CLIENT", "LIST"); + if (filter) { + if (filter.TYPE !== void 0) { + parser3.push("TYPE", filter.TYPE); + } else { + parser3.push("ID"); + parser3.pushVariadic(filter.ID); + } } - parser3.push(password); }, - transformReply: void 0 + transformReply(rawReply) { + const split = rawReply.toString().split("\n"), length2 = split.length - 1, reply = []; + for (let i2 = 0; i2 < length2; i2++) { + reply.push(CLIENT_INFO_1.default.transformReply(split[i2])); + } + return reply; + } }; } }); -var require_BGREWRITEAOF = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BGREWRITEAOF.js"(exports2) { +var require_CLIENT_NO_EVICT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_NO-EVICT.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Asynchronously rewrites the append-only file + * Controls whether to prevent the client's connections from being evicted * @param parser - The Redis command parser + * @param value - Whether to enable (true) or disable (false) the no-evict mode */ - parseCommand(parser3) { - parser3.push("BGREWRITEAOF"); + parseCommand(parser3, value) { + parser3.push("CLIENT", "NO-EVICT", value ? "ON" : "OFF"); }, transformReply: void 0 }; } }); -var require_BGSAVE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BGSAVE.js"(exports2) { +var require_CLIENT_NO_TOUCH = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_NO-TOUCH.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Asynchronously saves the dataset to disk + * Controls whether to prevent the client from touching the LRU/LFU of keys * @param parser - The Redis command parser - * @param options - Optional configuration - * @param options.SCHEDULE - Schedule a BGSAVE operation when no BGSAVE is already in progress + * @param value - Whether to enable (true) or disable (false) the no-touch mode */ - parseCommand(parser3, options2) { - parser3.push("BGSAVE"); - if (options2?.SCHEDULE) { - parser3.push("SCHEDULE"); - } + parseCommand(parser3, value) { + parser3.push("CLIENT", "NO-TOUCH", value ? "ON" : "OFF"); }, transformReply: void 0 }; } }); -var require_BITCOUNT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITCOUNT.js"(exports2) { +var require_CLIENT_PAUSE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_PAUSE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - CACHEABLE: true, + NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the count of set bits in a string key + * Stops the server from processing client commands for the specified duration * @param parser - The Redis command parser - * @param key - The key to count bits in - * @param range - Optional range specification - * @param range.start - Start offset in bytes/bits - * @param range.end - End offset in bytes/bits - * @param range.mode - Optional counting mode: BYTE or BIT + * @param timeout - Time in milliseconds to pause command processing + * @param mode - Optional mode: 'WRITE' to pause only write commands, 'ALL' to pause all commands */ - parseCommand(parser3, key, range) { - parser3.push("BITCOUNT"); - parser3.pushKey(key); - if (range) { - parser3.push(range.start.toString()); - parser3.push(range.end.toString()); - if (range.mode) { - parser3.push(range.mode); - } + parseCommand(parser3, timeout, mode) { + parser3.push("CLIENT", "PAUSE", timeout.toString()); + if (mode) { + parser3.push(mode); } }, transformReply: void 0 }; } }); -var require_BITFIELD_RO = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITFIELD_RO.js"(exports2) { +var require_CLIENT_SETNAME = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_SETNAME.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - CACHEABLE: true, + NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Performs read-only bitfield integer operations on strings + * Assigns a name to the current connection * @param parser - The Redis command parser - * @param key - The key holding the string - * @param operations - Array of GET operations to perform on the bitfield + * @param name - The name to assign to the connection */ - parseCommand(parser3, key, operations) { - parser3.push("BITFIELD_RO"); - parser3.pushKey(key); - for (const operation of operations) { - parser3.push("GET"); - parser3.push(operation.encoding); - parser3.push(operation.offset.toString()); - } + parseCommand(parser3, name) { + parser3.push("CLIENT", "SETNAME", name); }, transformReply: void 0 }; } }); -var require_BITFIELD = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITFIELD.js"(exports2) { +var require_CLIENT_TRACKING = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_TRACKING.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Performs arbitrary bitfield integer operations on strings + * Controls server-assisted client side caching for the current connection * @param parser - The Redis command parser - * @param key - The key holding the string - * @param operations - Array of bitfield operations to perform: GET, SET, INCRBY or OVERFLOW + * @param mode - Whether to enable (true) or disable (false) tracking + * @param options - Optional configuration including REDIRECT, BCAST, PREFIX, OPTIN, OPTOUT, and NOLOOP options */ - parseCommand(parser3, key, operations) { - parser3.push("BITFIELD"); - parser3.pushKey(key); - for (const options2 of operations) { - switch (options2.operation) { - case "GET": - parser3.push("GET", options2.encoding, options2.offset.toString()); - break; - case "SET": - parser3.push("SET", options2.encoding, options2.offset.toString(), options2.value.toString()); - break; - case "INCRBY": - parser3.push("INCRBY", options2.encoding, options2.offset.toString(), options2.increment.toString()); - break; - case "OVERFLOW": - parser3.push("OVERFLOW", options2.behavior); - break; + parseCommand(parser3, mode, options2) { + parser3.push("CLIENT", "TRACKING", mode ? "ON" : "OFF"); + if (mode) { + if (options2?.REDIRECT) { + parser3.push("REDIRECT", options2.REDIRECT.toString()); + } + if (isBroadcast(options2)) { + parser3.push("BCAST"); + if (options2?.PREFIX) { + if (Array.isArray(options2.PREFIX)) { + for (const prefix of options2.PREFIX) { + parser3.push("PREFIX", prefix); + } + } else { + parser3.push("PREFIX", options2.PREFIX); + } + } + } else if (isOptIn(options2)) { + parser3.push("OPTIN"); + } else if (isOptOut(options2)) { + parser3.push("OPTOUT"); + } + if (options2?.NOLOOP) { + parser3.push("NOLOOP"); } } }, transformReply: void 0 }; + function isBroadcast(options2) { + return options2?.BCAST === true; + } + function isOptIn(options2) { + return options2?.OPTIN === true; + } + function isOptOut(options2) { + return options2?.OPTOUT === true; + } } }); -var require_BITOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITOP.js"(exports2) { +var require_CLIENT_TRACKINGINFO = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_TRACKINGINFO.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Performs bitwise operations between strings + * Returns information about the current connection's key tracking state * @param parser - The Redis command parser - * @param operation - Bitwise operation to perform: AND, OR, XOR, NOT, DIFF, DIFF1, ANDOR, ONE - * @param destKey - Destination key to store the result - * @param key - Source key(s) to perform operation on */ - parseCommand(parser3, operation, destKey, key) { - parser3.push("BITOP", operation); - parser3.pushKey(destKey); - parser3.pushKeys(key); + parseCommand(parser3) { + parser3.push("CLIENT", "TRACKINGINFO"); }, - transformReply: void 0 + transformReply: { + 2: (reply) => ({ + flags: reply[1], + redirect: reply[3], + prefixes: reply[5] + }), + 3: void 0 + } }; } }); -var require_BITPOS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BITPOS.js"(exports2) { +var require_CLIENT_UNPAUSE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_UNPAUSE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - CACHEABLE: true, + NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the position of first bit set to 0 or 1 in a string + * Resumes processing of client commands after a CLIENT PAUSE * @param parser - The Redis command parser - * @param key - The key holding the string - * @param bit - The bit value to look for (0 or 1) - * @param start - Optional starting position in bytes/bits - * @param end - Optional ending position in bytes/bits - * @param mode - Optional counting mode: BYTE or BIT */ - parseCommand(parser3, key, bit, start, end, mode) { - parser3.push("BITPOS"); - parser3.pushKey(key); - parser3.push(bit.toString()); - if (start !== void 0) { - parser3.push(start.toString()); - } - if (end !== void 0) { - parser3.push(end.toString()); - } - if (mode) { - parser3.push(mode); - } + parseCommand(parser3) { + parser3.push("CLIENT", "UNPAUSE"); }, transformReply: void 0 }; } }); -var require_BLMOVE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLMOVE.js"(exports2) { +var require_CLUSTER_ADDSLOTS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_ADDSLOTS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Pop an element from a list, push it to another list and return it; or block until one is available + * Assigns hash slots to the current node in a Redis Cluster * @param parser - The Redis command parser - * @param source - Key of the source list - * @param destination - Key of the destination list - * @param sourceSide - Side of source list to pop from (LEFT or RIGHT) - * @param destinationSide - Side of destination list to push to (LEFT or RIGHT) - * @param timeout - Timeout in seconds, 0 to block indefinitely + * @param slots - One or more hash slots to be assigned */ - parseCommand(parser3, source, destination, sourceSide, destinationSide, timeout) { - parser3.push("BLMOVE"); - parser3.pushKeys([source, destination]); - parser3.push(sourceSide, destinationSide, timeout.toString()); + parseCommand(parser3, slots) { + parser3.push("CLUSTER", "ADDSLOTS"); + parser3.pushVariadicNumber(slots); }, transformReply: void 0 }; } }); -var require_LMPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/LMPOP.js"(exports2) { +var require_CLUSTER_ADDSLOTSRANGE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_ADDSLOTSRANGE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.parseLMPopArguments = void 0; - function parseLMPopArguments(parser3, keys, side, options2) { - parser3.pushKeysLength(keys); - parser3.push(side); - if (options2?.COUNT !== void 0) { - parser3.push("COUNT", options2.COUNT.toString()); - } - } - exports2.parseLMPopArguments = parseLMPopArguments; + var generic_transformers_1 = require_generic_transformers(); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Constructs the LMPOP command - * - * @param parser - The command parser - * @param args - Arguments including keys, side (LEFT or RIGHT), and options - * @see https://redis.io/commands/lmpop/ + * Assigns hash slot ranges to the current node in a Redis Cluster + * @param parser - The Redis command parser + * @param ranges - One or more slot ranges to be assigned, each specified as [start, end] */ - parseCommand(parser3, ...args) { - parser3.push("LMPOP"); - parseLMPopArguments(parser3, ...args); + parseCommand(parser3, ranges) { + parser3.push("CLUSTER", "ADDSLOTSRANGE"); + (0, generic_transformers_1.parseSlotRangesArguments)(parser3, ranges); }, transformReply: void 0 }; } }); -var require_BLMPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLMPOP.js"(exports2) { +var require_CLUSTER_BUMPEPOCH = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_BUMPEPOCH.js"(exports2) { "use strict"; - var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m3, k); - if (!desc || ("get" in desc ? !m3.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { - return m3[k]; - } }; - } - Object.defineProperty(o2, k2, desc); - } : function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - o2[k2] = m3[k]; - }); - var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o2, v2) { - Object.defineProperty(o2, "default", { enumerable: true, value: v2 }); - } : function(o2, v2) { - o2["default"] = v2; - }); - var __importStar = exports2 && exports2.__importStar || function(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) { - for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - } - __setModuleDefault(result, mod); - return result; - }; Object.defineProperty(exports2, "__esModule", { value: true }); - var LMPOP_1 = __importStar(require_LMPOP()); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Pops elements from multiple lists; blocks until elements are available + * Advances the cluster config epoch * @param parser - The Redis command parser - * @param timeout - Timeout in seconds, 0 to block indefinitely - * @param args - Additional arguments for LMPOP command */ - parseCommand(parser3, timeout, ...args) { - parser3.push("BLMPOP", timeout.toString()); - (0, LMPOP_1.parseLMPopArguments)(parser3, ...args); + parseCommand(parser3) { + parser3.push("CLUSTER", "BUMPEPOCH"); }, - transformReply: LMPOP_1.default.transformReply + transformReply: void 0 }; } }); -var require_BLPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BLPOP.js"(exports2) { +var require_CLUSTER_COUNT_FAILURE_REPORTS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { + NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Removes and returns the first element in a list, or blocks until one is available + * Returns the number of failure reports for a given node * @param parser - The Redis command parser - * @param key - Key of the list to pop from, or array of keys to try sequentially - * @param timeout - Maximum seconds to block, 0 to block indefinitely + * @param nodeId - The ID of the node to check */ - parseCommand(parser3, key, timeout) { - parser3.push("BLPOP"); - parser3.pushKeys(key); - parser3.push(timeout.toString()); + parseCommand(parser3, nodeId) { + parser3.push("CLUSTER", "COUNT-FAILURE-REPORTS", nodeId); }, - transformReply(reply) { - if (reply === null) - return null; - return { - key: reply[0], - element: reply[1] - }; - } + transformReply: void 0 }; } }); -var require_BRPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BRPOP.js"(exports2) { +var require_CLUSTER_COUNTKEYSINSLOT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_COUNTKEYSINSLOT.js"(exports2) { "use strict"; - var __importDefault = exports2 && exports2.__importDefault || function(mod) { - return mod && mod.__esModule ? mod : { "default": mod }; - }; Object.defineProperty(exports2, "__esModule", { value: true }); - var BLPOP_1 = __importDefault(require_BLPOP()); exports2.default = { + NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Removes and returns the last element in a list, or blocks until one is available + * Returns the number of keys in the specified hash slot * @param parser - The Redis command parser - * @param key - Key of the list to pop from, or array of keys to try sequentially - * @param timeout - Maximum seconds to block, 0 to block indefinitely + * @param slot - The hash slot to check */ - parseCommand(parser3, key, timeout) { - parser3.push("BRPOP"); - parser3.pushKeys(key); - parser3.push(timeout.toString()); + parseCommand(parser3, slot) { + parser3.push("CLUSTER", "COUNTKEYSINSLOT", slot.toString()); }, - transformReply: BLPOP_1.default.transformReply + transformReply: void 0 }; } }); -var require_BRPOPLPUSH = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BRPOPLPUSH.js"(exports2) { +var require_CLUSTER_DELSLOTS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_DELSLOTS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Pops an element from a list, pushes it to another list and returns it; blocks until element is available + * Removes hash slots from the current node in a Redis Cluster * @param parser - The Redis command parser - * @param source - Key of the source list to pop from - * @param destination - Key of the destination list to push to - * @param timeout - Maximum seconds to block, 0 to block indefinitely + * @param slots - One or more hash slots to be removed */ - parseCommand(parser3, source, destination, timeout) { - parser3.push("BRPOPLPUSH"); - parser3.pushKeys([source, destination]); - parser3.push(timeout.toString()); + parseCommand(parser3, slots) { + parser3.push("CLUSTER", "DELSLOTS"); + parser3.pushVariadicNumber(slots); }, transformReply: void 0 }; } }); -var require_ZMPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/ZMPOP.js"(exports2) { +var require_CLUSTER_DELSLOTSRANGE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_DELSLOTSRANGE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.parseZMPopArguments = void 0; var generic_transformers_1 = require_generic_transformers(); - function parseZMPopArguments(parser3, keys, side, options2) { - parser3.pushKeysLength(keys); - parser3.push(side); - if (options2?.COUNT) { - parser3.push("COUNT", options2.COUNT.toString()); - } - } - exports2.parseZMPopArguments = parseZMPopArguments; - exports2.default = { - IS_READ_ONLY: false, - /** - * Removes and returns up to count members with the highest/lowest scores from the first non-empty sorted set. - * @param parser - The Redis command parser. - * @param keys - Keys of the sorted sets to pop from. - * @param side - Side to pop from (MIN or MAX). - * @param options - Optional parameters including COUNT. - */ - parseCommand(parser3, keys, side, options2) { - parser3.push("ZMPOP"); - parseZMPopArguments(parser3, keys, side, options2); - }, - transformReply: { - 2(reply, preserve, typeMapping) { - return reply === null ? null : { - key: reply[0], - members: reply[1].map((member) => { - const [value, score] = member; - return { - value, - score: generic_transformers_1.transformDoubleReply[2](score, preserve, typeMapping) - }; - }) - }; - }, - 3(reply) { - return reply === null ? null : { - key: reply[0], - members: generic_transformers_1.transformSortedSetReply[3](reply[1]) - }; - } - } - }; - } -}); -var require_BZMPOP = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZMPOP.js"(exports2) { - "use strict"; - var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - var desc = Object.getOwnPropertyDescriptor(m3, k); - if (!desc || ("get" in desc ? !m3.__esModule : desc.writable || desc.configurable)) { - desc = { enumerable: true, get: function() { - return m3[k]; - } }; - } - Object.defineProperty(o2, k2, desc); - } : function(o2, m3, k, k2) { - if (k2 === void 0) k2 = k; - o2[k2] = m3[k]; - }); - var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o2, v2) { - Object.defineProperty(o2, "default", { enumerable: true, value: v2 }); - } : function(o2, v2) { - o2["default"] = v2; - }); - var __importStar = exports2 && exports2.__importStar || function(mod) { - if (mod && mod.__esModule) return mod; - var result = {}; - if (mod != null) { - for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); - } - __setModuleDefault(result, mod); - return result; - }; - Object.defineProperty(exports2, "__esModule", { value: true }); - var ZMPOP_1 = __importStar(require_ZMPOP()); exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Removes and returns members from one or more sorted sets in the specified order; blocks until elements are available + * Removes hash slot ranges from the current node in a Redis Cluster * @param parser - The Redis command parser - * @param timeout - Maximum seconds to block, 0 to block indefinitely - * @param args - Additional arguments specifying the keys, min/max count, and order (MIN/MAX) + * @param ranges - One or more slot ranges to be removed, each specified as [start, end] */ - parseCommand(parser3, timeout, ...args) { - parser3.push("BZMPOP", timeout.toString()); - (0, ZMPOP_1.parseZMPopArguments)(parser3, ...args); + parseCommand(parser3, ranges) { + parser3.push("CLUSTER", "DELSLOTSRANGE"); + (0, generic_transformers_1.parseSlotRangesArguments)(parser3, ranges); }, - transformReply: ZMPOP_1.default.transformReply + transformReply: void 0 }; } }); -var require_BZPOPMAX = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZPOPMAX.js"(exports2) { +var require_CLUSTER_FAILOVER = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FAILOVER.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - var generic_transformers_1 = require_generic_transformers(); + exports2.FAILOVER_MODES = void 0; + exports2.FAILOVER_MODES = { + FORCE: "FORCE", + TAKEOVER: "TAKEOVER" + }; exports2.default = { - IS_READ_ONLY: false, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Removes and returns the member with the highest score in a sorted set, or blocks until one is available + * Forces a replica to perform a manual failover of its master * @param parser - The Redis command parser - * @param keys - Key of the sorted set, or array of keys to try sequentially - * @param timeout - Maximum seconds to block, 0 to block indefinitely + * @param options - Optional configuration with FORCE or TAKEOVER mode */ - parseCommand(parser3, keys, timeout) { - parser3.push("BZPOPMAX"); - parser3.pushKeys(keys); - parser3.push(timeout.toString()); - }, - transformReply: { - 2(reply, preserve, typeMapping) { - return reply === null ? null : { - key: reply[0], - value: reply[1], - score: generic_transformers_1.transformDoubleReply[2](reply[2], preserve, typeMapping) - }; - }, - 3(reply) { - return reply === null ? null : { - key: reply[0], - value: reply[1], - score: reply[2] - }; + parseCommand(parser3, options2) { + parser3.push("CLUSTER", "FAILOVER"); + if (options2?.mode) { + parser3.push(options2.mode); } - } + }, + transformReply: void 0 }; } }); -var require_BZPOPMIN = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/BZPOPMIN.js"(exports2) { +var require_CLUSTER_FLUSHSLOTS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FLUSHSLOTS.js"(exports2) { "use strict"; - var __importDefault = exports2 && exports2.__importDefault || function(mod) { - return mod && mod.__esModule ? mod : { "default": mod }; - }; Object.defineProperty(exports2, "__esModule", { value: true }); - var BZPOPMAX_1 = __importDefault(require_BZPOPMAX()); exports2.default = { - IS_READ_ONLY: BZPOPMAX_1.default.IS_READ_ONLY, + NOT_KEYED_COMMAND: true, + IS_READ_ONLY: true, /** - * Removes and returns the member with the lowest score in a sorted set, or blocks until one is available + * Deletes all hash slots from the current node in a Redis Cluster * @param parser - The Redis command parser - * @param keys - Key of the sorted set, or array of keys to try sequentially - * @param timeout - Maximum seconds to block, 0 to block indefinitely */ - parseCommand(parser3, keys, timeout) { - parser3.push("BZPOPMIN"); - parser3.pushKeys(keys); - parser3.push(timeout.toString()); + parseCommand(parser3) { + parser3.push("CLUSTER", "FLUSHSLOTS"); }, - transformReply: BZPOPMAX_1.default.transformReply + transformReply: void 0 }; } }); -var require_CLIENT_CACHING = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_CACHING.js"(exports2) { +var require_CLUSTER_FORGET = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FORGET.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Instructs the server about tracking or not keys in the next request + * Removes a node from the cluster * @param parser - The Redis command parser - * @param value - Whether to enable (true) or disable (false) tracking + * @param nodeId - The ID of the node to remove */ - parseCommand(parser3, value) { - parser3.push("CLIENT", "CACHING", value ? "YES" : "NO"); + parseCommand(parser3, nodeId) { + parser3.push("CLUSTER", "FORGET", nodeId); }, transformReply: void 0 }; } }); -var require_CLIENT_GETNAME = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_GETNAME.js"(exports2) { +var require_CLUSTER_GETKEYSINSLOT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_GETKEYSINSLOT.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the name of the current connection + * Returns a number of keys from the specified hash slot * @param parser - The Redis command parser + * @param slot - The hash slot to get keys from + * @param count - Maximum number of keys to return */ - parseCommand(parser3) { - parser3.push("CLIENT", "GETNAME"); + parseCommand(parser3, slot, count) { + parser3.push("CLUSTER", "GETKEYSINSLOT", slot.toString(), count.toString()); }, transformReply: void 0 }; } }); -var require_CLIENT_GETREDIR = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_GETREDIR.js"(exports2) { +var require_CLUSTER_INFO = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_INFO.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the ID of the client to which the current client is redirecting tracking notifications + * Returns information about the state of a Redis Cluster * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("CLIENT", "GETREDIR"); + parser3.push("CLUSTER", "INFO"); }, transformReply: void 0 }; } }); -var require_CLIENT_ID = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_ID.js"(exports2) { +var require_CLUSTER_KEYSLOT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_KEYSLOT.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns the client ID for the current connection + * Returns the hash slot number for a given key * @param parser - The Redis command parser + * @param key - The key to get the hash slot for */ - parseCommand(parser3) { - parser3.push("CLIENT", "ID"); + parseCommand(parser3, key) { + parser3.push("CLUSTER", "KEYSLOT", key); }, transformReply: void 0 }; } }); -var require_CLIENT_INFO = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_INFO.js"(exports2) { +var require_CLUSTER_LINKS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_LINKS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - var CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g; exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns information and statistics about the current client connection + * Returns information about all cluster links (lower level connections to other nodes) * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("CLIENT", "INFO"); + parser3.push("CLUSTER", "LINKS"); }, - transformReply(rawReply) { - const map = {}; - for (const item of rawReply.toString().matchAll(CLIENT_INFO_REGEX)) { - map[item[1]] = item[2]; - } - const reply = { - id: Number(map.id), - addr: map.addr, - fd: Number(map.fd), - name: map.name, - age: Number(map.age), - idle: Number(map.idle), - flags: map.flags, - db: Number(map.db), - sub: Number(map.sub), - psub: Number(map.psub), - multi: Number(map.multi), - qbuf: Number(map.qbuf), - qbufFree: Number(map["qbuf-free"]), - argvMem: Number(map["argv-mem"]), - obl: Number(map.obl), - oll: Number(map.oll), - omem: Number(map.omem), - totMem: Number(map["tot-mem"]), - events: map.events, - cmd: map.cmd, - user: map.user, - libName: map["lib-name"], - libVer: map["lib-ver"] - }; - if (map.laddr !== void 0) { - reply.laddr = map.laddr; - } - if (map.redir !== void 0) { - reply.redir = Number(map.redir); - } - if (map.ssub !== void 0) { - reply.ssub = Number(map.ssub); - } - if (map["multi-mem"] !== void 0) { - reply.multiMem = Number(map["multi-mem"]); - } - if (map.resp !== void 0) { - reply.resp = Number(map.resp); - } - return reply; + transformReply: { + 2: (reply) => reply.map((link) => { + const unwrapped = link; + return { + direction: unwrapped[1], + node: unwrapped[3], + "create-time": unwrapped[5], + events: unwrapped[7], + "send-buffer-allocated": unwrapped[9], + "send-buffer-used": unwrapped[11] + }; + }), + 3: void 0 } }; } }); -var require_CLIENT_KILL = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_KILL.js"(exports2) { +var require_CLUSTER_MEET = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MEET.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.CLIENT_KILL_FILTERS = void 0; - exports2.CLIENT_KILL_FILTERS = { - ADDRESS: "ADDR", - LOCAL_ADDRESS: "LADDR", - ID: "ID", - TYPE: "TYPE", - USER: "USER", - SKIP_ME: "SKIPME", - MAXAGE: "MAXAGE" - }; exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Closes client connections matching the specified filters + * Initiates a handshake with another node in the cluster * @param parser - The Redis command parser - * @param filters - One or more filters to match client connections to kill + * @param host - Host name or IP address of the node + * @param port - TCP port of the node */ - parseCommand(parser3, filters) { - parser3.push("CLIENT", "KILL"); - if (Array.isArray(filters)) { - for (const filter of filters) { - pushFilter(parser3, filter); - } - } else { - pushFilter(parser3, filters); - } + parseCommand(parser3, host, port) { + parser3.push("CLUSTER", "MEET", host, port.toString()); }, transformReply: void 0 }; - function pushFilter(parser3, filter) { - if (filter === exports2.CLIENT_KILL_FILTERS.SKIP_ME) { - parser3.push("SKIPME"); - return; - } - parser3.push(filter.filter); - switch (filter.filter) { - case exports2.CLIENT_KILL_FILTERS.ADDRESS: - parser3.push(filter.address); - break; - case exports2.CLIENT_KILL_FILTERS.LOCAL_ADDRESS: - parser3.push(filter.localAddress); - break; - case exports2.CLIENT_KILL_FILTERS.ID: - parser3.push(typeof filter.id === "number" ? filter.id.toString() : filter.id); - break; - case exports2.CLIENT_KILL_FILTERS.TYPE: - parser3.push(filter.type); - break; - case exports2.CLIENT_KILL_FILTERS.USER: - parser3.push(filter.username); - break; - case exports2.CLIENT_KILL_FILTERS.SKIP_ME: - parser3.push(filter.skipMe ? "yes" : "no"); - break; - case exports2.CLIENT_KILL_FILTERS.MAXAGE: - parser3.push(filter.maxAge.toString()); - break; - } - } } }); -var require_CLIENT_LIST = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_LIST.js"(exports2) { +var require_CLUSTER_MYID = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MYID.js"(exports2) { "use strict"; - var __importDefault = exports2 && exports2.__importDefault || function(mod) { - return mod && mod.__esModule ? mod : { "default": mod }; - }; Object.defineProperty(exports2, "__esModule", { value: true }); - var CLIENT_INFO_1 = __importDefault(require_CLIENT_INFO()); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns information about all client connections. Can be filtered by type or ID + * Returns the node ID of the current Redis Cluster node * @param parser - The Redis command parser - * @param filter - Optional filter to return only specific client types or IDs */ - parseCommand(parser3, filter) { - parser3.push("CLIENT", "LIST"); - if (filter) { - if (filter.TYPE !== void 0) { - parser3.push("TYPE", filter.TYPE); - } else { - parser3.push("ID"); - parser3.pushVariadic(filter.ID); - } - } + parseCommand(parser3) { + parser3.push("CLUSTER", "MYID"); }, - transformReply(rawReply) { - const split = rawReply.toString().split("\n"), length2 = split.length - 1, reply = []; - for (let i2 = 0; i2 < length2; i2++) { - reply.push(CLIENT_INFO_1.default.transformReply(split[i2])); - } - return reply; - } + transformReply: void 0 }; } }); -var require_CLIENT_NO_EVICT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_NO-EVICT.js"(exports2) { +var require_CLUSTER_MYSHARDID = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MYSHARDID.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Controls whether to prevent the client's connections from being evicted + * Returns the shard ID of the current Redis Cluster node * @param parser - The Redis command parser - * @param value - Whether to enable (true) or disable (false) the no-evict mode */ - parseCommand(parser3, value) { - parser3.push("CLIENT", "NO-EVICT", value ? "ON" : "OFF"); + parseCommand(parser3) { + parser3.push("CLUSTER", "MYSHARDID"); }, transformReply: void 0 }; } }); -var require_CLIENT_NO_TOUCH = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_NO-TOUCH.js"(exports2) { +var require_CLUSTER_NODES = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_NODES.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Controls whether to prevent the client from touching the LRU/LFU of keys + * Returns serialized information about the nodes in a Redis Cluster * @param parser - The Redis command parser - * @param value - Whether to enable (true) or disable (false) the no-touch mode */ - parseCommand(parser3, value) { - parser3.push("CLIENT", "NO-TOUCH", value ? "ON" : "OFF"); + parseCommand(parser3) { + parser3.push("CLUSTER", "NODES"); }, transformReply: void 0 }; } }); -var require_CLIENT_PAUSE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_PAUSE.js"(exports2) { +var require_CLUSTER_REPLICAS = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_REPLICAS.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Stops the server from processing client commands for the specified duration + * Returns the replica nodes replicating from the specified primary node * @param parser - The Redis command parser - * @param timeout - Time in milliseconds to pause command processing - * @param mode - Optional mode: 'WRITE' to pause only write commands, 'ALL' to pause all commands + * @param nodeId - Node ID of the primary node */ - parseCommand(parser3, timeout, mode) { - parser3.push("CLIENT", "PAUSE", timeout.toString()); - if (mode) { - parser3.push(mode); - } + parseCommand(parser3, nodeId) { + parser3.push("CLUSTER", "REPLICAS", nodeId); }, transformReply: void 0 }; } }); -var require_CLIENT_SETNAME = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_SETNAME.js"(exports2) { +var require_CLUSTER_REPLICATE = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_REPLICATE.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Assigns a name to the current connection + * Reconfigures a node as a replica of the specified primary node * @param parser - The Redis command parser - * @param name - The name to assign to the connection + * @param nodeId - Node ID of the primary node to replicate */ - parseCommand(parser3, name) { - parser3.push("CLIENT", "SETNAME", name); + parseCommand(parser3, nodeId) { + parser3.push("CLUSTER", "REPLICATE", nodeId); }, transformReply: void 0 }; } }); -var require_CLIENT_TRACKING = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_TRACKING.js"(exports2) { +var require_CLUSTER_RESET = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_RESET.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Controls server-assisted client side caching for the current connection + * Resets a Redis Cluster node, clearing all information and returning it to a brand new state * @param parser - The Redis command parser - * @param mode - Whether to enable (true) or disable (false) tracking - * @param options - Optional configuration including REDIRECT, BCAST, PREFIX, OPTIN, OPTOUT, and NOLOOP options + * @param options - Options for the reset operation */ - parseCommand(parser3, mode, options2) { - parser3.push("CLIENT", "TRACKING", mode ? "ON" : "OFF"); - if (mode) { - if (options2?.REDIRECT) { - parser3.push("REDIRECT", options2.REDIRECT.toString()); - } - if (isBroadcast(options2)) { - parser3.push("BCAST"); - if (options2?.PREFIX) { - if (Array.isArray(options2.PREFIX)) { - for (const prefix of options2.PREFIX) { - parser3.push("PREFIX", prefix); - } - } else { - parser3.push("PREFIX", options2.PREFIX); - } - } - } else if (isOptIn(options2)) { - parser3.push("OPTIN"); - } else if (isOptOut(options2)) { - parser3.push("OPTOUT"); - } - if (options2?.NOLOOP) { - parser3.push("NOLOOP"); - } + parseCommand(parser3, options2) { + parser3.push("CLUSTER", "RESET"); + if (options2?.mode) { + parser3.push(options2.mode); } }, transformReply: void 0 }; - function isBroadcast(options2) { - return options2?.BCAST === true; - } - function isOptIn(options2) { - return options2?.OPTIN === true; - } - function isOptOut(options2) { - return options2?.OPTOUT === true; - } } }); -var require_CLIENT_TRACKINGINFO = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_TRACKINGINFO.js"(exports2) { +var require_CLUSTER_SAVECONFIG = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SAVECONFIG.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Returns information about the current connection's key tracking state + * Forces a Redis Cluster node to save the cluster configuration to disk * @param parser - The Redis command parser */ parseCommand(parser3) { - parser3.push("CLIENT", "TRACKINGINFO"); + parser3.push("CLUSTER", "SAVECONFIG"); }, - transformReply: { - 2: (reply) => ({ - flags: reply[1], - redirect: reply[3], - prefixes: reply[5] - }), - 3: void 0 - } + transformReply: void 0 }; } }); -var require_CLIENT_UNPAUSE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLIENT_UNPAUSE.js"(exports2) { +var require_CLUSTER_SET_CONFIG_EPOCH = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SET-CONFIG-EPOCH.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.default = { NOT_KEYED_COMMAND: true, IS_READ_ONLY: true, /** - * Resumes processing of client commands after a CLIENT PAUSE + * Sets the configuration epoch for a Redis Cluster node * @param parser - The Redis command parser + * @param configEpoch - The configuration epoch to set */ - parseCommand(parser3) { - parser3.push("CLIENT", "UNPAUSE"); + parseCommand(parser3, configEpoch) { + parser3.push("CLUSTER", "SET-CONFIG-EPOCH", configEpoch.toString()); }, transformReply: void 0 }; } }); -var require_CLUSTER_ADDSLOTS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_ADDSLOTS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Assigns hash slots to the current node in a Redis Cluster - * @param parser - The Redis command parser - * @param slots - One or more hash slots to be assigned - */ - parseCommand(parser3, slots) { - parser3.push("CLUSTER", "ADDSLOTS"); - parser3.pushVariadicNumber(slots); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_ADDSLOTSRANGE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_ADDSLOTSRANGE.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - var generic_transformers_1 = require_generic_transformers(); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Assigns hash slot ranges to the current node in a Redis Cluster - * @param parser - The Redis command parser - * @param ranges - One or more slot ranges to be assigned, each specified as [start, end] - */ - parseCommand(parser3, ranges) { - parser3.push("CLUSTER", "ADDSLOTSRANGE"); - (0, generic_transformers_1.parseSlotRangesArguments)(parser3, ranges); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_BUMPEPOCH = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_BUMPEPOCH.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Advances the cluster config epoch - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "BUMPEPOCH"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_COUNT_FAILURE_REPORTS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_COUNT-FAILURE-REPORTS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the number of failure reports for a given node - * @param parser - The Redis command parser - * @param nodeId - The ID of the node to check - */ - parseCommand(parser3, nodeId) { - parser3.push("CLUSTER", "COUNT-FAILURE-REPORTS", nodeId); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_COUNTKEYSINSLOT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_COUNTKEYSINSLOT.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the number of keys in the specified hash slot - * @param parser - The Redis command parser - * @param slot - The hash slot to check - */ - parseCommand(parser3, slot) { - parser3.push("CLUSTER", "COUNTKEYSINSLOT", slot.toString()); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_DELSLOTS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_DELSLOTS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Removes hash slots from the current node in a Redis Cluster - * @param parser - The Redis command parser - * @param slots - One or more hash slots to be removed - */ - parseCommand(parser3, slots) { - parser3.push("CLUSTER", "DELSLOTS"); - parser3.pushVariadicNumber(slots); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_DELSLOTSRANGE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_DELSLOTSRANGE.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - var generic_transformers_1 = require_generic_transformers(); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Removes hash slot ranges from the current node in a Redis Cluster - * @param parser - The Redis command parser - * @param ranges - One or more slot ranges to be removed, each specified as [start, end] - */ - parseCommand(parser3, ranges) { - parser3.push("CLUSTER", "DELSLOTSRANGE"); - (0, generic_transformers_1.parseSlotRangesArguments)(parser3, ranges); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_FAILOVER = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FAILOVER.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.FAILOVER_MODES = void 0; - exports2.FAILOVER_MODES = { - FORCE: "FORCE", - TAKEOVER: "TAKEOVER" - }; - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Forces a replica to perform a manual failover of its master - * @param parser - The Redis command parser - * @param options - Optional configuration with FORCE or TAKEOVER mode - */ - parseCommand(parser3, options2) { - parser3.push("CLUSTER", "FAILOVER"); - if (options2?.mode) { - parser3.push(options2.mode); - } - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_FLUSHSLOTS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FLUSHSLOTS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Deletes all hash slots from the current node in a Redis Cluster - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "FLUSHSLOTS"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_FORGET = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_FORGET.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Removes a node from the cluster - * @param parser - The Redis command parser - * @param nodeId - The ID of the node to remove - */ - parseCommand(parser3, nodeId) { - parser3.push("CLUSTER", "FORGET", nodeId); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_GETKEYSINSLOT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_GETKEYSINSLOT.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns a number of keys from the specified hash slot - * @param parser - The Redis command parser - * @param slot - The hash slot to get keys from - * @param count - Maximum number of keys to return - */ - parseCommand(parser3, slot, count) { - parser3.push("CLUSTER", "GETKEYSINSLOT", slot.toString(), count.toString()); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_INFO = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_INFO.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns information about the state of a Redis Cluster - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "INFO"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_KEYSLOT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_KEYSLOT.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the hash slot number for a given key - * @param parser - The Redis command parser - * @param key - The key to get the hash slot for - */ - parseCommand(parser3, key) { - parser3.push("CLUSTER", "KEYSLOT", key); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_LINKS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_LINKS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns information about all cluster links (lower level connections to other nodes) - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "LINKS"); - }, - transformReply: { - 2: (reply) => reply.map((link) => { - const unwrapped = link; - return { - direction: unwrapped[1], - node: unwrapped[3], - "create-time": unwrapped[5], - events: unwrapped[7], - "send-buffer-allocated": unwrapped[9], - "send-buffer-used": unwrapped[11] - }; - }), - 3: void 0 - } - }; - } -}); -var require_CLUSTER_MEET = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MEET.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Initiates a handshake with another node in the cluster - * @param parser - The Redis command parser - * @param host - Host name or IP address of the node - * @param port - TCP port of the node - */ - parseCommand(parser3, host, port) { - parser3.push("CLUSTER", "MEET", host, port.toString()); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_MYID = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MYID.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the node ID of the current Redis Cluster node - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "MYID"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_MYSHARDID = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_MYSHARDID.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the shard ID of the current Redis Cluster node - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "MYSHARDID"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_NODES = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_NODES.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns serialized information about the nodes in a Redis Cluster - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "NODES"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_REPLICAS = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_REPLICAS.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Returns the replica nodes replicating from the specified primary node - * @param parser - The Redis command parser - * @param nodeId - Node ID of the primary node - */ - parseCommand(parser3, nodeId) { - parser3.push("CLUSTER", "REPLICAS", nodeId); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_REPLICATE = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_REPLICATE.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Reconfigures a node as a replica of the specified primary node - * @param parser - The Redis command parser - * @param nodeId - Node ID of the primary node to replicate - */ - parseCommand(parser3, nodeId) { - parser3.push("CLUSTER", "REPLICATE", nodeId); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_RESET = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_RESET.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Resets a Redis Cluster node, clearing all information and returning it to a brand new state - * @param parser - The Redis command parser - * @param options - Options for the reset operation - */ - parseCommand(parser3, options2) { - parser3.push("CLUSTER", "RESET"); - if (options2?.mode) { - parser3.push(options2.mode); - } - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_SAVECONFIG = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SAVECONFIG.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Forces a Redis Cluster node to save the cluster configuration to disk - * @param parser - The Redis command parser - */ - parseCommand(parser3) { - parser3.push("CLUSTER", "SAVECONFIG"); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_SET_CONFIG_EPOCH = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SET-CONFIG-EPOCH.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.default = { - NOT_KEYED_COMMAND: true, - IS_READ_ONLY: true, - /** - * Sets the configuration epoch for a Redis Cluster node - * @param parser - The Redis command parser - * @param configEpoch - The configuration epoch to set - */ - parseCommand(parser3, configEpoch) { - parser3.push("CLUSTER", "SET-CONFIG-EPOCH", configEpoch.toString()); - }, - transformReply: void 0 - }; - } -}); -var require_CLUSTER_SETSLOT = __commonJS({ - "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SETSLOT.js"(exports2) { +var require_CLUSTER_SETSLOT = __commonJS({ + "node_modules/.deno/@redis+client@5.9.0/node_modules/@redis/client/dist/lib/commands/CLUSTER_SETSLOT.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.CLUSTER_SLOT_STATES = void 0; @@ -56886,7 +50595,7 @@ var db; var init_database_router_test = __esm({ "src/serve/database-router.test.ts"() { "use strict"; - init_esm5(); + init_esm4(); init_database_router(); CID2 = "Q"; randomKeyWithPrefix = (prefix) => `${prefix}${globalThis.crypto.randomUUID().replaceAll("-", "")}`; @@ -56961,19198 +50670,24587 @@ var init_database_router_test = __esm({ }); } }); -var globImport_database_ts2; -var init_2 = __esm({ - 'import("./database-*.ts") in src/serve/database.ts'() { - globImport_database_ts2 = __glob({ - "./database-fs.ts": () => Promise.resolve().then(() => (init_database_fs(), database_fs_exports)), - "./database-redis.ts": () => Promise.resolve().then(() => (init_database_redis(), database_redis_exports)), - "./database-router.test.ts": () => Promise.resolve().then(() => (init_database_router_test(), database_router_test_exports)), - "./database-router.ts": () => Promise.resolve().then(() => (init_database_router(), database_router_exports)), - "./database-sqlite.ts": () => Promise.resolve().then(() => (init_database_sqlite(), database_sqlite_exports)) - }); - } -}); -var import_npm_lru_cache; -var import_npm_nconf2; -var production; -var database_default; -var initedDB; -var initDB; -var init_database = __esm({ - "src/serve/database.ts"() { +var require_has_flag = __commonJS({ + "node_modules/.deno/has-flag@4.0.0/node_modules/has-flag/index.js"(exports2, module14) { "use strict"; - init_chelonia(); - init_db(); - init_db(); - init_functions(); - init_esm(); - import_npm_lru_cache = __toESM(require_lru_cache()); - init_errors4(); - init_events2(); - init_vapid(); - init_zkppSalt(); - import_npm_nconf2 = __toESM(require_nconf()); - init_db_utils(); - init_db_utils(); - init_2(); - production = process2.env.NODE_ENV === "production"; - database_default = esm_default("sbp/selectors/register", { - "backend/db/streamEntriesAfter": async function(contractID, height, requestedLimit, options2 = {}) { - const batchMaxSize = import_npm_nconf2.default.get("server:maxEventsBatchSize") ?? 500; - const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize); - const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); - if (latestHEADinfo === "") { - throw new BackendErrorGone(`contractID ${contractID} has been deleted!`); - } - if (!latestHEADinfo) { - throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`); - } - let counter = 0; - let currentHeight = height; - let currentHash, serverMeta; - let prefix = ""; - const nextKeyOp = /* @__PURE__ */ (() => { - let index; - return async () => { - if (!index) { - index = (await esm_default("chelonia.db/get", `_private_keyop_idx_${contractID}_${currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH}`))?.split("\0"); - } - const value = index?.find((h2, i2) => { - if (Number(h2) >= currentHeight) { - index = index.slice(i2 + 1); - return true; - } else { - return false; - } - }); - if (value != null) { - const newHeight = Number(value); - currentHeight = newHeight; - } else { - currentHeight = currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH + KEYOP_SEGMENT_LENGTH; - index = void 0; - if (currentHeight > latestHEADinfo.height) { - return false; - } else { - return null; - } - } - return true; - }; - })(); - const fetchMeta = async () => { - if (currentHeight > latestHEADinfo.height) { - return false; - } - const meta = await esm_default("chelonia/db/getEntryMeta", contractID, currentHeight); - if (!meta) { - return false; - } - const { hash: newCurrentHash, ...newServerMeta } = meta; - currentHash = newCurrentHash; - serverMeta = newServerMeta; - return true; - }; - const stream = Readable.from(async function* () { - yield "["; - await fetchMeta(); - while (serverMeta && counter < limit) { - try { - const entry = await esm_default("chelonia/db/getEntry", currentHash); - if (!entry) break; - const currentPrefix = prefix; - prefix = ","; - counter++; - yield `${currentPrefix}"${strToB64( - JSON.stringify({ serverMeta, message: entry.serialize() }) - )}"`; - currentHeight++; - currentHash = void 0; - serverMeta = void 0; - if (options2.keyOps) { - while (await nextKeyOp() === null) ; - } - await fetchMeta(); - } catch (e2) { - console.error(e2, "[backend] streamEntriesAfter: read()"); - break; - } - } - yield "]"; - }(), { encoding: "utf-8", objectMode: false }); - stream.headers = { - "shelter-headinfo-head": latestHEADinfo.HEAD, - "shelter-headinfo-height": latestHEADinfo.height - }; - return stream; - }, - // ======================= - // wrapper methods to add / lookup names - // ======================= - "backend/db/registerName": async function(name, value) { - const exists = await esm_default("backend/db/lookupName", name); - if (exists) { - throw new BackendErrorConflict("exists"); - } - await esm_default("chelonia.db/set", namespaceKey(name), value); - await esm_default("chelonia.db/set", `_private_cid2name_${value}`, name); - await appendToNamesIndex(name); - return { name, value }; - }, - "backend/db/lookupName": async function(name) { - const value = await esm_default("chelonia.db/get", namespaceKey(name)); - return value; - } - }); - initedDB = false; - initDB = async ({ skipDbPreloading } = {}) => { - if (!initedDB) { - const backend = import_npm_nconf2.default.get("database:backend"); - const persistence = backend || (production ? "fs" : void 0); - const options2 = import_npm_nconf2.default.get("database:backendOptions"); - const ARCHIVE_MODE3 = import_npm_nconf2.default.get("server:archiveMode"); - if (persistence && persistence !== "mem") { - const Ctor = (await globImport_database_ts2(`./database-${persistence}.ts`)).default; - const { init: init2, readData, writeData, deleteData, iterKeys, keyCount, close } = new Ctor(options2[persistence]); - await init2(); - esm_default("okTurtles.events/once", SERVER_EXITING, () => { - esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, async () => { - try { - await close(); - } catch (e2) { - console.error(e2, `Error closing DB ${persistence}`); - } - }); - }); - const cache2 = new import_npm_lru_cache.default({ - max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 - }); - const prefixes = Object.keys(prefixHandlers); - esm_default("sbp/selectors/overwrite", { - "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { - if (!bypassCache) { - const lookupValue = cache2.get(prefixableKey); - if (lookupValue !== void 0) { - return lookupValue; - } - } - const [prefix, key] = parsePrefixableKey(prefixableKey); - let value = await readData(key); - if (value === void 0) { - return; - } - value = prefixHandlers[prefix](value); - cache2.set(prefixableKey, value); - return value; - }, - "chelonia.db/set": async function(key, value) { - if (ARCHIVE_MODE3) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - const existingValue = await readData(key); - if (existingValue !== void 0) { - throw new Error("Cannot set already set immutable key"); - } - } - await writeData(key, value); - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/delete": async function(key) { - if (ARCHIVE_MODE3) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - throw new Error("Cannot delete immutable key"); - } - await deleteData(key); - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/iterKeys": () => { - return iterKeys(); - }, - "chelonia.db/keyCount": () => { - return keyCount(); - } - }); - esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); - } - initedDB = true; - } - if (skipDbPreloading || initedDB === "preloaded") return; - await Promise.all([initVapid(), initZkpp()]); - initedDB = "preloaded"; - }; - } -}); -var compose; -var init_compose = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/compose.js"() { - compose = (middleware, onError, onNotFound) => { - return (context, next) => { - let index = -1; - return dispatch(0); - async function dispatch(i2) { - if (i2 <= index) { - throw new Error("next() called multiple times"); - } - index = i2; - let res; - let isError = false; - let handler; - if (middleware[i2]) { - handler = middleware[i2][0][0]; - context.req.routeIndex = i2; - } else { - handler = i2 === middleware.length && next || void 0; - } - if (handler) { - try { - res = await handler(context, () => dispatch(i2 + 1)); - } catch (err) { - if (err instanceof Error && onError) { - context.error = err; - res = await onError(err, context); - isError = true; - } else { - throw err; - } - } - } else { - if (context.finalized === false && onNotFound) { - res = await onNotFound(context); - } - } - if (res && (context.finalized === false || isError)) { - context.res = res; - } - return context; - } - }; + module14.exports = (flag, argv = process.argv) => { + const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; + const position = argv.indexOf(prefix + flag); + const terminatorPosition = argv.indexOf("--"); + return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); }; } }); -var HTTPException; -var init_http_exception = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/http-exception.js"() { - HTTPException = class extends Error { - res; - status; - /** - * Creates an instance of `HTTPException`. - * @param status - HTTP status code for the exception. Defaults to 500. - * @param options - Additional options for the exception. - */ - constructor(status = 500, options2) { - super(options2?.message, { cause: options2?.cause }); - this.res = options2?.res; - this.status = status; +var require_supports_color = __commonJS({ + "node_modules/.deno/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module14) { + "use strict"; + var os = __require2("os"); + var tty = __require2("tty"); + var hasFlag = require_has_flag(); + var { env: env2 } = process; + var forceColor; + if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { + forceColor = 0; + } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { + forceColor = 1; + } + if ("FORCE_COLOR" in env2) { + if (env2.FORCE_COLOR === "true") { + forceColor = 1; + } else if (env2.FORCE_COLOR === "false") { + forceColor = 0; + } else { + forceColor = env2.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env2.FORCE_COLOR, 10), 3); } - /** - * Returns the response object associated with the exception. - * If a response object is not provided, a new response is created with the error message and status code. - * @returns The response object. - */ - getResponse() { - if (this.res) { - const newResponse = new Response(this.res.body, { - status: this.status, - headers: this.res.headers - }); - return newResponse; - } - return new Response(this.message, { - status: this.status - }); + } + function translateLevel(level) { + if (level === 0) { + return false; } - }; - } -}); -var GET_MATCH_RESULT; -var init_constants2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/request/constants.js"() { - GET_MATCH_RESULT = /* @__PURE__ */ Symbol(); - } -}); -async function parseFormData(request, options2) { - const formData = await request.formData(); - if (formData) { - return convertFormDataToBodyData(formData, options2); - } - return {}; -} -function convertFormDataToBodyData(formData, options2) { - const form = /* @__PURE__ */ Object.create(null); - formData.forEach((value, key) => { - const shouldParseAllValues = options2.all || key.endsWith("[]"); - if (!shouldParseAllValues) { - form[key] = value; - } else { - handleParsingAllValues(form, key, value); + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; } - }); - if (options2.dot) { - Object.entries(form).forEach(([key, value]) => { - const shouldParseDotValues = key.includes("."); - if (shouldParseDotValues) { - handleParsingNestedValues(form, key, value); - delete form[key]; + function supportsColor(haveStream, streamIsTTY) { + if (forceColor === 0) { + return 0; } - }); - } - return form; -} -var parseBody; -var handleParsingAllValues; -var handleParsingNestedValues; -var init_body = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/body.js"() { - init_request(); - parseBody = async (request, options2 = /* @__PURE__ */ Object.create(null)) => { - const { all = false, dot = false } = options2; - const headers = request instanceof HonoRequest ? request.raw.headers : request.headers; - const contentType = headers.get("Content-Type"); - if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) { - return parseFormData(request, { all, dot }); + if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { + return 3; } - return {}; - }; - handleParsingAllValues = (form, key, value) => { - if (form[key] !== void 0) { - if (Array.isArray(form[key])) { - ; - form[key].push(value); - } else { - form[key] = [form[key], value]; - } - } else { - if (!key.endsWith("[]")) { - form[key] = value; - } else { - form[key] = [value]; - } + if (hasFlag("color=256")) { + return 2; } - }; - handleParsingNestedValues = (form, key, value) => { - if (/(?:^|\.)__proto__\./.test(key)) { - return; + if (haveStream && !streamIsTTY && forceColor === void 0) { + return 0; } - let nestedForm = form; - const keys = key.split("."); - keys.forEach((key2, index) => { - if (index === keys.length - 1) { - nestedForm[key2] = value; - } else { - if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) { - nestedForm[key2] = /* @__PURE__ */ Object.create(null); - } - nestedForm = nestedForm[key2]; + const min = forceColor || 0; + if (env2.TERM === "dumb") { + return min; + } + if (process.platform === "win32") { + const osRelease = os.release().split("."); + if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; } - }); - }; - } -}); -var splitPath; -var splitRoutingPath; -var extractGroupsFromPath; -var replaceGroupMarks; -var patternCache; -var getPattern; -var tryDecode; -var tryDecodeURI; -var getPath; -var getPathNoStrict; -var mergePath; -var checkOptionalParameter; -var _decodeURI; -var _getQueryParam; -var getQueryParam; -var getQueryParams; -var decodeURIComponent_; -var init_url = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/url.js"() { - splitPath = (path8) => { - const paths = path8.split("/"); - if (paths[0] === "") { - paths.shift(); - } - return paths; - }; - splitRoutingPath = (routePath) => { - const { groups, path: path8 } = extractGroupsFromPath(routePath); - const paths = splitPath(path8); - return replaceGroupMarks(paths, groups); - }; - extractGroupsFromPath = (path8) => { - const groups = []; - path8 = path8.replace(/\{[^}]+\}/g, (match2, index) => { - const mark = `@${index}`; - groups.push([mark, match2]); - return mark; - }); - return { groups, path: path8 }; - }; - replaceGroupMarks = (paths, groups) => { - for (let i2 = groups.length - 1; i2 >= 0; i2--) { - const [mark] = groups[i2]; - for (let j = paths.length - 1; j >= 0; j--) { - if (paths[j].includes(mark)) { - paths[j] = paths[j].replace(mark, groups[i2][1]); - break; - } + return 1; + } + if ("CI" in env2) { + if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign2) => sign2 in env2) || env2.CI_NAME === "codeship") { + return 1; } + return min; } - return paths; - }; - patternCache = {}; - getPattern = (label, next) => { - if (label === "*") { - return "*"; + if ("TEAMCITY_VERSION" in env2) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env2.TEAMCITY_VERSION) ? 1 : 0; } - const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); - if (match2) { - const cacheKey2 = `${label}#${next}`; - if (!patternCache[cacheKey2]) { - if (match2[2]) { - patternCache[cacheKey2] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey2, match2[1], new RegExp(`^${match2[2]}(?=/${next})`)] : [label, match2[1], new RegExp(`^${match2[2]}$`)]; - } else { - patternCache[cacheKey2] = [label, match2[1], true]; - } + if (env2.COLORTERM === "truecolor") { + return 3; + } + if ("TERM_PROGRAM" in env2) { + const version3 = parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10); + switch (env2.TERM_PROGRAM) { + case "iTerm.app": + return version3 >= 3 ? 3 : 2; + case "Apple_Terminal": + return 2; } - return patternCache[cacheKey2]; } - return null; - }; - tryDecode = (str, decoder) => { - try { - return decoder(str); - } catch { - return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => { - try { - return decoder(match2); - } catch { - return match2; - } - }); + if (/-256(color)?$/i.test(env2.TERM)) { + return 2; + } + if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env2.TERM)) { + return 1; + } + if ("COLORTERM" in env2) { + return 1; } + return min; + } + function getSupportLevel(stream) { + const level = supportsColor(stream, stream && stream.isTTY); + return translateLevel(level); + } + module14.exports = { + supportsColor: getSupportLevel, + stdout: translateLevel(supportsColor(true, tty.isatty(1))), + stderr: translateLevel(supportsColor(true, tty.isatty(2))) }; - tryDecodeURI = (str) => tryDecode(str, decodeURI); - getPath = (request) => { - const url2 = request.url; - const start = url2.indexOf("/", url2.indexOf(":") + 4); - let i2 = start; - for (; i2 < url2.length; i2++) { - const charCode = url2.charCodeAt(i2); - if (charCode === 37) { - const queryIndex = url2.indexOf("?", i2); - const hashIndex = url2.indexOf("#", i2); - const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex); - const path8 = url2.slice(start, end); - return tryDecodeURI(path8.includes("%25") ? path8.replace(/%25/g, "%2525") : path8); - } else if (charCode === 63 || charCode === 35) { - break; - } + } +}); +var require_util2 = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/util.js"(exports2, module14) { + "use strict"; + var stringReplaceAll = (string3, substring, replacer) => { + let index = string3.indexOf(substring); + if (index === -1) { + return string3; } - return url2.slice(start, i2); + const substringLength = substring.length; + let endIndex = 0; + let returnValue = ""; + do { + returnValue += string3.substr(endIndex, index - endIndex) + substring + replacer; + endIndex = index + substringLength; + index = string3.indexOf(substring, endIndex); + } while (index !== -1); + returnValue += string3.substr(endIndex); + return returnValue; }; - getPathNoStrict = (request) => { - const result = getPath(request); - return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result; + var stringEncaseCRLFWithFirstIndex = (string3, prefix, postfix, index) => { + let endIndex = 0; + let returnValue = ""; + do { + const gotCR = string3[index - 1] === "\r"; + returnValue += string3.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? "\r\n" : "\n") + postfix; + endIndex = index + 1; + index = string3.indexOf("\n", endIndex); + } while (index !== -1); + returnValue += string3.substr(endIndex); + return returnValue; }; - mergePath = (base2, sub, ...rest) => { - if (rest.length) { - sub = mergePath(sub, ...rest); - } - return `${base2?.[0] === "/" ? "" : "/"}${base2}${sub === "/" ? "" : `${base2?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`; + module14.exports = { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex }; - checkOptionalParameter = (path8) => { - if (path8.charCodeAt(path8.length - 1) !== 63 || !path8.includes(":")) { - return null; + } +}); +var require_templates = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/templates.js"(exports2, module14) { + "use strict"; + var TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; + var STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; + var STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; + var ESCAPE_REGEX2 = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; + var ESCAPES = /* @__PURE__ */ new Map([ + ["n", "\n"], + ["r", "\r"], + ["t", " "], + ["b", "\b"], + ["f", "\f"], + ["v", "\v"], + ["0", "\0"], + ["\\", "\\"], + ["e", "\x1B"], + ["a", "\x07"] + ]); + function unescape(c) { + const u2 = c[0] === "u"; + const bracket = c[1] === "{"; + if (u2 && !bracket && c.length === 5 || c[0] === "x" && c.length === 3) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } + if (u2 && bracket) { + return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); } - const segments = path8.split("/"); + return ESCAPES.get(c) || c; + } + function parseArguments(name, arguments_) { const results = []; - let basePath = ""; - segments.forEach((segment) => { - if (segment !== "" && !/\:/.test(segment)) { - basePath += "/" + segment; - } else if (/\:/.test(segment)) { - if (/\?/.test(segment)) { - if (results.length === 0 && basePath === "") { - results.push("/"); - } else { - results.push(basePath); - } - const optionalSegment = segment.replace("?", ""); - basePath += "/" + optionalSegment; - results.push(basePath); - } else { - basePath += "/" + segment; - } + const chunks = arguments_.trim().split(/\s*,\s*/g); + let matches; + for (const chunk of chunks) { + const number3 = Number(chunk); + if (!Number.isNaN(number3)) { + results.push(number3); + } else if (matches = chunk.match(STRING_REGEX)) { + results.push(matches[2].replace(ESCAPE_REGEX2, (m3, escape, character) => escape ? unescape(escape) : character)); + } else { + throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); } - }); - return results.filter((v2, i2, a) => a.indexOf(v2) === i2); - }; - _decodeURI = (value) => { - if (!/[%+]/.test(value)) { - return value; - } - if (value.indexOf("+") !== -1) { - value = value.replace(/\+/g, " "); } - return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value; - }; - _getQueryParam = (url2, key, multiple) => { - let encoded; - if (!multiple && key && !/[%+]/.test(key)) { - let keyIndex2 = url2.indexOf("?", 8); - if (keyIndex2 === -1) { - return void 0; - } - if (!url2.startsWith(key, keyIndex2 + 1)) { - keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); - } - while (keyIndex2 !== -1) { - const trailingKeyCode = url2.charCodeAt(keyIndex2 + key.length + 1); - if (trailingKeyCode === 61) { - const valueIndex = keyIndex2 + key.length + 2; - const endIndex = url2.indexOf("&", valueIndex); - return _decodeURI(url2.slice(valueIndex, endIndex === -1 ? void 0 : endIndex)); - } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) { - return ""; - } - keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); - } - encoded = /[%+]/.test(url2); - if (!encoded) { - return void 0; + return results; + } + function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; + const results = []; + let matches; + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); } } - const results = {}; - encoded ??= /[%+]/.test(url2); - let keyIndex = url2.indexOf("?", 8); - while (keyIndex !== -1) { - const nextKeyIndex = url2.indexOf("&", keyIndex + 1); - let valueIndex = url2.indexOf("=", keyIndex); - if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) { - valueIndex = -1; - } - let name = url2.slice( - keyIndex + 1, - valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex - ); - if (encoded) { - name = _decodeURI(name); + return results; + } + function buildStyle(chalk5, styles) { + const enabled2 = {}; + for (const layer of styles) { + for (const style of layer.styles) { + enabled2[style[0]] = layer.inverse ? null : style.slice(1); } - keyIndex = nextKeyIndex; - if (name === "") { + } + let current = chalk5; + for (const [styleName, styles2] of Object.entries(enabled2)) { + if (!Array.isArray(styles2)) { continue; } - let value; - if (valueIndex === -1) { - value = ""; - } else { - value = url2.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex); - if (encoded) { - value = _decodeURI(value); - } + if (!(styleName in current)) { + throw new Error(`Unknown Chalk style: ${styleName}`); } - if (multiple) { - if (!(results[name] && Array.isArray(results[name]))) { - results[name] = []; + current = styles2.length > 0 ? current[styleName](...styles2) : current[styleName]; + } + return current; + } + module14.exports = (chalk5, temporary) => { + const styles = []; + const chunks = []; + let chunk = []; + temporary.replace(TEMPLATE_REGEX, (m3, escapeCharacter, inverse, style, close, character) => { + if (escapeCharacter) { + chunk.push(unescape(escapeCharacter)); + } else if (style) { + const string3 = chunk.join(""); + chunk = []; + chunks.push(styles.length === 0 ? string3 : buildStyle(chalk5, styles)(string3)); + styles.push({ inverse, styles: parseStyle(style) }); + } else if (close) { + if (styles.length === 0) { + throw new Error("Found extraneous } in Chalk template literal"); } - ; - results[name].push(value); + chunks.push(buildStyle(chalk5, styles)(chunk.join(""))); + chunk = []; + styles.pop(); } else { - results[name] ??= value; + chunk.push(character); } + }); + chunks.push(chunk.join("")); + if (styles.length > 0) { + const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? "" : "s"} (\`}\`)`; + throw new Error(errMessage); } - return key ? results[key] : results; - }; - getQueryParam = _getQueryParam; - getQueryParams = (url2, key) => { - return _getQueryParam(url2, key, true); + return chunks.join(""); }; - decodeURIComponent_ = decodeURIComponent; } }); -var tryDecodeURIComponent; -var HonoRequest; -var init_request = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/request.js"() { - init_http_exception(); - init_constants2(); - init_body(); - init_url(); - tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_); - HonoRequest = class { - /** - * `.raw` can get the raw Request object. - * - * @see {@link https://hono.dev/docs/api/request#raw} - * - * @example - * ```ts - * // For Cloudflare Workers - * app.post('/', async (c) => { - * const metadata = c.req.raw.cf?.hostMetadata? - * ... - * }) - * ``` - */ - raw; - #validatedData; - // Short name of validatedData - #matchResult; - routeIndex = 0; - /** - * `.path` can get the pathname of the request. - * - * @see {@link https://hono.dev/docs/api/request#path} - * - * @example - * ```ts - * app.get('/about/me', (c) => { - * const pathname = c.req.path // `/about/me` - * }) - * ``` - */ - path; - bodyCache = {}; - constructor(request, path8 = "/", matchResult = [[]]) { - this.raw = request; - this.path = path8; - this.#matchResult = matchResult; - this.#validatedData = {}; - } - param(key) { - return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams(); - } - #getDecodedParam(key) { - const paramKey = this.#matchResult[0][this.routeIndex][1][key]; - const param = this.#getParamValue(paramKey); - return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param; - } - #getAllDecodedParams() { - const decoded = {}; - const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]); - for (const key of keys) { - const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]); - if (value !== void 0) { - decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value; - } - } - return decoded; - } - #getParamValue(paramKey) { - return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey; +var require_source = __commonJS({ + "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/index.js"(exports2, module14) { + "use strict"; + var ansiStyles = require_ansi_styles(); + var { stdout: stdoutColor, stderr: stderrColor } = require_supports_color(); + var { + stringReplaceAll, + stringEncaseCRLFWithFirstIndex + } = require_util2(); + var { isArray } = Array; + var levelMapping = [ + "ansi", + "ansi", + "ansi256", + "ansi16m" + ]; + var styles = /* @__PURE__ */ Object.create(null); + var applyOptions = (object2, options2 = {}) => { + if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) { + throw new Error("The `level` option should be an integer from 0 to 3"); } - query(key) { - return getQueryParam(this.url, key); + const colorLevel = stdoutColor ? stdoutColor.level : 0; + object2.level = options2.level === void 0 ? colorLevel : options2.level; + }; + var ChalkClass = class { + constructor(options2) { + return chalkFactory(options2); } - queries(key) { - return getQueryParams(this.url, key); + }; + var chalkFactory = (options2) => { + const chalk6 = {}; + applyOptions(chalk6, options2); + chalk6.template = (...arguments_) => chalkTag(chalk6.template, ...arguments_); + Object.setPrototypeOf(chalk6, Chalk.prototype); + Object.setPrototypeOf(chalk6.template, chalk6); + chalk6.template.constructor = () => { + throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead."); + }; + chalk6.template.Instance = ChalkClass; + return chalk6.template; + }; + function Chalk(options2) { + return chalkFactory(options2); + } + for (const [styleName, style] of Object.entries(ansiStyles)) { + styles[styleName] = { + get() { + const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); + Object.defineProperty(this, styleName, { value: builder }); + return builder; + } + }; + } + styles.visible = { + get() { + const builder = createBuilder(this, this._styler, true); + Object.defineProperty(this, "visible", { value: builder }); + return builder; } - header(name) { - if (name) { - return this.raw.headers.get(name) ?? void 0; + }; + var usedModels = ["rgb", "hex", "keyword", "hsl", "hsv", "hwb", "ansi", "ansi256"]; + for (const model of usedModels) { + styles[model] = { + get() { + const { level } = this; + return function(...arguments_) { + const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; } - const headerData = {}; - this.raw.headers.forEach((value, key) => { - headerData[key] = value; - }); - return headerData; - } - async parseBody(options2) { - return parseBody(this, options2); - } - #cachedBody = (key) => { - const { bodyCache, raw: raw2 } = this; - const cachedBody = bodyCache[key]; - if (cachedBody) { - return cachedBody; - } - const anyCachedKey = Object.keys(bodyCache)[0]; - if (anyCachedKey) { - return bodyCache[anyCachedKey].then((body) => { - if (anyCachedKey === "json") { - body = JSON.stringify(body); - } - return new Response(body)[key](); - }); + }; + } + for (const model of usedModels) { + const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); + styles[bgModel] = { + get() { + const { level } = this; + return function(...arguments_) { + const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); + return createBuilder(this, styler, this._isEmpty); + }; } - return bodyCache[key] = raw2[key](); }; - /** - * `.json()` can parse Request body of type `application/json` - * - * @see {@link https://hono.dev/docs/api/request#json} - * - * @example - * ```ts - * app.post('/entry', async (c) => { - * const body = await c.req.json() - * }) - * ``` - */ - json() { - return this.#cachedBody("text").then((text) => JSON.parse(text)); + } + var proto3 = Object.defineProperties(() => { + }, { + ...styles, + level: { + enumerable: true, + get() { + return this._generator.level; + }, + set(level) { + this._generator.level = level; + } } - /** - * `.text()` can parse Request body of type `text/plain` - * - * @see {@link https://hono.dev/docs/api/request#text} - * - * @example - * ```ts - * app.post('/entry', async (c) => { - * const body = await c.req.text() - * }) - * ``` - */ - text() { - return this.#cachedBody("text"); - } - /** - * `.arrayBuffer()` parse Request body as an `ArrayBuffer` - * - * @see {@link https://hono.dev/docs/api/request#arraybuffer} - * - * @example - * ```ts - * app.post('/entry', async (c) => { - * const body = await c.req.arrayBuffer() - * }) - * ``` - */ - arrayBuffer() { - return this.#cachedBody("arrayBuffer"); - } - /** - * Parses the request body as a `Blob`. - * @example - * ```ts - * app.post('/entry', async (c) => { - * const body = await c.req.blob(); - * }); - * ``` - * @see https://hono.dev/docs/api/request#blob - */ - blob() { - return this.#cachedBody("blob"); - } - /** - * Parses the request body as `FormData`. - * @example - * ```ts - * app.post('/entry', async (c) => { - * const body = await c.req.formData(); - * }); - * ``` - * @see https://hono.dev/docs/api/request#formdata - */ - formData() { - return this.#cachedBody("formData"); + }); + var createStyler = (open2, close, parent) => { + let openAll; + let closeAll; + if (parent === void 0) { + openAll = open2; + closeAll = close; + } else { + openAll = parent.openAll + open2; + closeAll = close + parent.closeAll; } - /** - * Adds validated data to the request. - * - * @param target - The target of the validation. - * @param data - The validated data to add. - */ - addValidatedData(target, data) { - this.#validatedData[target] = data; + return { + open: open2, + close, + openAll, + closeAll, + parent + }; + }; + var createBuilder = (self2, _styler, _isEmpty) => { + const builder = (...arguments_) => { + if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { + return applyStyle(builder, chalkTag(builder, ...arguments_)); + } + return applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")); + }; + Object.setPrototypeOf(builder, proto3); + builder._generator = self2; + builder._styler = _styler; + builder._isEmpty = _isEmpty; + return builder; + }; + var applyStyle = (self2, string3) => { + if (self2.level <= 0 || !string3) { + return self2._isEmpty ? "" : string3; } - valid(target) { - return this.#validatedData[target]; + let styler = self2._styler; + if (styler === void 0) { + return string3; } - /** - * `.url()` can get the request url strings. - * - * @see {@link https://hono.dev/docs/api/request#url} - * - * @example - * ```ts - * app.get('/about/me', (c) => { - * const url = c.req.url // `http://localhost:8787/about/me` - * ... - * }) - * ``` - */ - get url() { - return this.raw.url; + const { openAll, closeAll } = styler; + if (string3.indexOf("\x1B") !== -1) { + while (styler !== void 0) { + string3 = stringReplaceAll(string3, styler.close, styler.open); + styler = styler.parent; + } } - /** - * `.method()` can get the method name of the request. - * - * @see {@link https://hono.dev/docs/api/request#method} - * - * @example - * ```ts - * app.get('/about/me', (c) => { - * const method = c.req.method // `GET` - * }) - * ``` - */ - get method() { - return this.raw.method; + const lfIndex = string3.indexOf("\n"); + if (lfIndex !== -1) { + string3 = stringEncaseCRLFWithFirstIndex(string3, closeAll, openAll, lfIndex); } - get [GET_MATCH_RESULT]() { - return this.#matchResult; + return openAll + string3 + closeAll; + }; + var template; + var chalkTag = (chalk6, ...strings) => { + const [firstString] = strings; + if (!isArray(firstString) || !isArray(firstString.raw)) { + return strings.join(" "); } - /** - * `.matchedRoutes()` can return a matched route in the handler - * - * @deprecated - * - * Use matchedRoutes helper defined in "hono/route" instead. - * - * @see {@link https://hono.dev/docs/api/request#matchedroutes} - * - * @example - * ```ts - * app.use('*', async function logger(c, next) { - * await next() - * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => { - * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]') - * console.log( - * method, - * ' ', - * path, - * ' '.repeat(Math.max(10 - path.length, 0)), - * name, - * i === c.req.routeIndex ? '<- respond from here' : '' - * ) - * }) - * }) - * ``` - */ - get matchedRoutes() { - return this.#matchResult[0].map(([[, route]]) => route); + const arguments_ = strings.slice(1); + const parts = [firstString.raw[0]]; + for (let i2 = 1; i2 < firstString.length; i2++) { + parts.push( + String(arguments_[i2 - 1]).replace(/[{}\\]/g, "\\$&"), + String(firstString.raw[i2]) + ); } - /** - * `routePath()` can retrieve the path registered within the handler - * - * @deprecated - * - * Use routePath helper defined in "hono/route" instead. - * - * @see {@link https://hono.dev/docs/api/request#routepath} - * - * @example - * ```ts - * app.get('/posts/:id', (c) => { - * return c.json({ path: c.req.routePath }) - * }) - * ``` - */ - get routePath() { - return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path; + if (template === void 0) { + template = require_templates(); } + return template(chalk6, parts.join("")); }; + Object.defineProperties(Chalk.prototype, styles); + var chalk5 = Chalk(); + chalk5.supportsColor = stdoutColor; + chalk5.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 }); + chalk5.stderr.supportsColor = stderrColor; + module14.exports = chalk5; } }); -var HtmlEscapedCallbackPhase; -var raw; -var resolveCallback; -var init_html = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/html.js"() { - HtmlEscapedCallbackPhase = { - Stringify: 1, - BeforeStream: 2, - Stream: 3 - }; - raw = (value, callbacks) => { - const escapedString = new String(value); - escapedString.isEscaped = true; - escapedString.callbacks = callbacks; - return escapedString; +var require_parser2 = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js"(exports2) { + "use strict"; + exports2.load = function(received, defaults, onto = {}) { + var k, ref, v2; + for (k in defaults) { + v2 = defaults[k]; + onto[k] = (ref = received[k]) != null ? ref : v2; + } + return onto; }; - resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => { - if (typeof str === "object" && !(str instanceof String)) { - if (!(str instanceof Promise)) { - str = str.toString(); - } - if (str instanceof Promise) { - str = await str; + exports2.overwrite = function(received, defaults, onto = {}) { + var k, v2; + for (k in received) { + v2 = received[k]; + if (defaults[k] !== void 0) { + onto[k] = v2; } } - const callbacks = str.callbacks; - if (!callbacks?.length) { - return Promise.resolve(str); - } - if (buffer) { - buffer[0] += str; - } else { - buffer = [str]; - } - const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then( - (res) => Promise.all( - res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer)) - ).then(() => buffer[0]) - ); - if (preserveCallbacks) { - return raw(await resStr, callbacks); - } else { - return resStr; - } + return onto; }; } }); -var TEXT_PLAIN; -var setDefaultContentType; -var createResponseInstance; -var Context; -var init_context = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/context.js"() { - init_request(); - init_html(); - TEXT_PLAIN = "text/plain; charset=UTF-8"; - setDefaultContentType = (contentType, headers) => { - return { - "Content-Type": contentType, - ...headers - }; - }; - createResponseInstance = (body, init2) => new Response(body, init2); - Context = class { - #rawRequest; - #req; - /** - * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers. - * - * @see {@link https://hono.dev/docs/api/context#env} - * - * @example - * ```ts - * // Environment object for Cloudflare Workers - * app.get('*', async c => { - * const counter = c.env.COUNTER - * }) - * ``` - */ - env = {}; - #var; - finalized = false; - /** - * `.error` can get the error object from the middleware if the Handler throws an error. - * - * @see {@link https://hono.dev/docs/api/context#error} - * - * @example - * ```ts - * app.use('*', async (c, next) => { - * await next() - * if (c.error) { - * // do something... - * } - * }) - * ``` - */ - error; - #status; - #executionCtx; - #res; - #layout; - #renderer; - #notFoundHandler; - #preparedHeaders; - #matchResult; - #path; - /** - * Creates an instance of the Context class. - * - * @param req - The Request object. - * @param options - Optional configuration options for the context. - */ - constructor(req, options2) { - this.#rawRequest = req; - if (options2) { - this.#executionCtx = options2.executionCtx; - this.env = options2.env; - this.#notFoundHandler = options2.notFoundHandler; - this.#path = options2.path; - this.#matchResult = options2.matchResult; - } - } - /** - * `.req` is the instance of {@link HonoRequest}. - */ - get req() { - this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult); - return this.#req; +var require_DLList = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/DLList.js"(exports2, module14) { + "use strict"; + var DLList; + DLList = class DLList { + constructor(incr, decr) { + this.incr = incr; + this.decr = decr; + this._first = null; + this._last = null; + this.length = 0; } - /** - * @see {@link https://hono.dev/docs/api/context#event} - * The FetchEvent associated with the current request. - * - * @throws Will throw an error if the context does not have a FetchEvent. - */ - get event() { - if (this.#executionCtx && "respondWith" in this.#executionCtx) { - return this.#executionCtx; - } else { - throw Error("This context has no FetchEvent"); + push(value) { + var node; + this.length++; + if (typeof this.incr === "function") { + this.incr(); } - } - /** - * @see {@link https://hono.dev/docs/api/context#executionctx} - * The ExecutionContext associated with the current request. - * - * @throws Will throw an error if the context does not have an ExecutionContext. - */ - get executionCtx() { - if (this.#executionCtx) { - return this.#executionCtx; + node = { + value, + prev: this._last, + next: null + }; + if (this._last != null) { + this._last.next = node; + this._last = node; } else { - throw Error("This context has no ExecutionContext"); + this._first = this._last = node; } + return void 0; } - /** - * @see {@link https://hono.dev/docs/api/context#res} - * The Response object for the current request. - */ - get res() { - return this.#res ||= createResponseInstance(null, { - headers: this.#preparedHeaders ??= new Headers() - }); - } - /** - * Sets the Response object for the current request. - * - * @param _res - The Response object to set. - */ - set res(_res) { - if (this.#res && _res) { - _res = createResponseInstance(_res.body, _res); - for (const [k, v2] of this.#res.headers.entries()) { - if (k === "content-type") { - continue; - } - if (k === "set-cookie") { - const cookies = this.#res.headers.getSetCookie(); - _res.headers.delete("set-cookie"); - for (const cookie of cookies) { - _res.headers.append("set-cookie", cookie); - } - } else { - _res.headers.set(k, v2); - } + shift() { + var value; + if (this._first == null) { + return; + } else { + this.length--; + if (typeof this.decr === "function") { + this.decr(); } } - this.#res = _res; - this.finalized = true; - } - /** - * `.render()` can create a response within a layout. - * - * @see {@link https://hono.dev/docs/api/context#render-setrenderer} - * - * @example - * ```ts - * app.get('/', (c) => { - * return c.render('Hello!') - * }) - * ``` - */ - render = (...args) => { - this.#renderer ??= (content) => this.html(content); - return this.#renderer(...args); - }; - /** - * Sets the layout for the response. - * - * @param layout - The layout to set. - * @returns The layout function. - */ - setLayout = (layout) => this.#layout = layout; - /** - * Gets the current layout for the response. - * - * @returns The current layout function. - */ - getLayout = () => this.#layout; - /** - * `.setRenderer()` can set the layout in the custom middleware. - * - * @see {@link https://hono.dev/docs/api/context#render-setrenderer} - * - * @example - * ```tsx - * app.use('*', async (c, next) => { - * c.setRenderer((content) => { - * return c.html( - * - * - *

{content}

- * - * - * ) - * }) - * await next() - * }) - * ``` - */ - setRenderer = (renderer) => { - this.#renderer = renderer; - }; - /** - * `.header()` can set headers. - * - * @see {@link https://hono.dev/docs/api/context#header} - * - * @example - * ```ts - * app.get('/welcome', (c) => { - * // Set headers - * c.header('X-Message', 'Hello!') - * c.header('Content-Type', 'text/plain') - * - * return c.body('Thank you for coming') - * }) - * ``` - */ - header = (name, value, options2) => { - if (this.finalized) { - this.#res = createResponseInstance(this.#res.body, this.#res); - } - const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers(); - if (value === void 0) { - headers.delete(name); - } else if (options2?.append) { - headers.append(name, value); + value = this._first.value; + if ((this._first = this._first.next) != null) { + this._first.prev = null; } else { - headers.set(name, value); + this._last = null; } - }; - status = (status) => { - this.#status = status; - }; - /** - * `.set()` can set the value specified by the key. - * - * @see {@link https://hono.dev/docs/api/context#set-get} - * - * @example - * ```ts - * app.use('*', async (c, next) => { - * c.set('message', 'Hono is hot!!') - * await next() - * }) - * ``` - */ - set = (key, value) => { - this.#var ??= /* @__PURE__ */ new Map(); - this.#var.set(key, value); - }; - /** - * `.get()` can use the value specified by the key. - * - * @see {@link https://hono.dev/docs/api/context#set-get} - * - * @example - * ```ts - * app.get('/', (c) => { - * const message = c.get('message') - * return c.text(`The message is "${message}"`) - * }) - * ``` - */ - get = (key) => { - return this.#var ? this.#var.get(key) : void 0; - }; - /** - * `.var` can access the value of a variable. - * - * @see {@link https://hono.dev/docs/api/context#var} - * - * @example - * ```ts - * const result = c.var.client.oneMethod() - * ``` - */ - // c.var.propName is a read-only - get var() { - if (!this.#var) { - return {}; + return value; + } + first() { + if (this._first != null) { + return this._first.value; } - return Object.fromEntries(this.#var); } - #newResponse(data, arg, headers) { - const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers(); - if (typeof arg === "object" && "headers" in arg) { - const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers); - for (const [key, value] of argHeaders) { - if (key.toLowerCase() === "set-cookie") { - responseHeaders.append(key, value); - } else { - responseHeaders.set(key, value); - } - } + getArray() { + var node, ref, results; + node = this._first; + results = []; + while (node != null) { + results.push((ref = node, node = node.next, ref.value)); } - if (headers) { - for (const [k, v2] of Object.entries(headers)) { - if (typeof v2 === "string") { - responseHeaders.set(k, v2); - } else { - responseHeaders.delete(k); - for (const v22 of v2) { - responseHeaders.append(k, v22); - } - } - } + return results; + } + forEachShift(cb) { + var node; + node = this.shift(); + while (node != null) { + cb(node), node = this.shift(); } - const status = typeof arg === "number" ? arg : arg?.status ?? this.#status; - return createResponseInstance(data, { status, headers: responseHeaders }); + return void 0; + } + debug() { + var node, ref, ref1, ref2, results; + node = this._first; + results = []; + while (node != null) { + results.push((ref = node, node = node.next, { + value: ref.value, + prev: (ref1 = ref.prev) != null ? ref1.value : void 0, + next: (ref2 = ref.next) != null ? ref2.value : void 0 + })); + } + return results; } - newResponse = (...args) => this.#newResponse(...args); - /** - * `.body()` can return the HTTP response. - * You can set headers with `.header()` and set HTTP status code with `.status`. - * This can also be set in `.text()`, `.json()` and so on. - * - * @see {@link https://hono.dev/docs/api/context#body} - * - * @example - * ```ts - * app.get('/welcome', (c) => { - * // Set headers - * c.header('X-Message', 'Hello!') - * c.header('Content-Type', 'text/plain') - * // Set HTTP status code - * c.status(201) - * - * // Return the response body - * return c.body('Thank you for coming') - * }) - * ``` - */ - body = (data, arg, headers) => this.#newResponse(data, arg, headers); - /** - * `.text()` can render text as `Content-Type:text/plain`. - * - * @see {@link https://hono.dev/docs/api/context#text} - * - * @example - * ```ts - * app.get('/say', (c) => { - * return c.text('Hello!') - * }) - * ``` - */ - text = (text, arg, headers) => { - return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse( - text, - arg, - setDefaultContentType(TEXT_PLAIN, headers) - ); - }; - /** - * `.json()` can render JSON as `Content-Type:application/json`. - * - * @see {@link https://hono.dev/docs/api/context#json} - * - * @example - * ```ts - * app.get('/api', (c) => { - * return c.json({ message: 'Hello!' }) - * }) - * ``` - */ - json = (object2, arg, headers) => { - return this.#newResponse( - JSON.stringify(object2), - arg, - setDefaultContentType("application/json", headers) - ); - }; - html = (html2, arg, headers) => { - const res = (html22) => this.#newResponse(html22, arg, setDefaultContentType("text/html; charset=UTF-8", headers)); - return typeof html2 === "object" ? resolveCallback(html2, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html2); - }; - /** - * `.redirect()` can Redirect, default status code is 302. - * - * @see {@link https://hono.dev/docs/api/context#redirect} - * - * @example - * ```ts - * app.get('/redirect', (c) => { - * return c.redirect('/') - * }) - * app.get('/redirect-permanently', (c) => { - * return c.redirect('/', 301) - * }) - * ``` - */ - redirect = (location, status) => { - const locationString = String(location); - this.header( - "Location", - // Multibyes should be encoded - // eslint-disable-next-line no-control-regex - !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString) - ); - return this.newResponse(null, status ?? 302); - }; - /** - * `.notFound()` can return the Not Found Response. - * - * @see {@link https://hono.dev/docs/api/context#notfound} - * - * @example - * ```ts - * app.get('/notfound', (c) => { - * return c.notFound() - * }) - * ``` - */ - notFound = () => { - this.#notFoundHandler ??= () => createResponseInstance(); - return this.#notFoundHandler(this); - }; }; + module14.exports = DLList; } }); -var METHOD_NAME_ALL; -var METHOD_NAME_ALL_LOWERCASE; -var METHODS; -var MESSAGE_MATCHER_IS_ALREADY_BUILT; -var UnsupportedPathError; -var init_router = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router.js"() { - METHOD_NAME_ALL = "ALL"; - METHOD_NAME_ALL_LOWERCASE = "all"; - METHODS = ["get", "post", "put", "delete", "options", "patch"]; - MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built."; - UnsupportedPathError = class extends Error { - }; - } -}); -var COMPOSED_HANDLER; -var init_constants3 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/constants.js"() { - COMPOSED_HANDLER = "__COMPOSED_HANDLER"; - } -}); -var notFoundHandler; -var errorHandler; -var Hono; -var init_hono_base = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/hono-base.js"() { - init_compose(); - init_context(); - init_router(); - init_constants3(); - init_url(); - notFoundHandler = (c) => { - return c.text("404 Not Found", 404); - }; - errorHandler = (err, c) => { - if ("getResponse" in err) { - const res = err.getResponse(); - return c.newResponse(res.body, res); - } - console.error(err); - return c.text("Internal Server Error", 500); - }; - Hono = class _Hono { - get; - post; - put; - delete; - options; - patch; - all; - on; - use; - /* - This class is like an abstract class and does not have a router. - To use it, inherit the class and implement router in the constructor. - */ - router; - getPath; - // Cannot use `#` because it requires visibility at JavaScript runtime. - _basePath = "/"; - #path = "/"; - routes = []; - constructor(options2 = {}) { - const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE]; - allMethods.forEach((method) => { - this[method] = (args1, ...args) => { - if (typeof args1 === "string") { - this.#path = args1; - } else { - this.#addRoute(method, this.#path, args1); - } - args.forEach((handler) => { - this.#addRoute(method, this.#path, handler); - }); - return this; - }; - }); - this.on = (method, path8, ...handlers) => { - for (const p of [path8].flat()) { - this.#path = p; - for (const m3 of [method].flat()) { - handlers.map((handler) => { - this.#addRoute(m3.toUpperCase(), this.#path, handler); - }); - } - } - return this; - }; - this.use = (arg1, ...handlers) => { - if (typeof arg1 === "string") { - this.#path = arg1; - } else { - this.#path = "*"; - handlers.unshift(arg1); - } - handlers.forEach((handler) => { - this.#addRoute(METHOD_NAME_ALL, this.#path, handler); - }); - return this; - }; - const { strict, ...optionsWithoutStrict } = options2; - Object.assign(this, optionsWithoutStrict); - this.getPath = strict ?? true ? options2.getPath ?? getPath : getPathNoStrict; - } - #clone() { - const clone2 = new _Hono({ - router: this.router, - getPath: this.getPath - }); - clone2.errorHandler = this.errorHandler; - clone2.#notFoundHandler = this.#notFoundHandler; - clone2.routes = this.routes; - return clone2; +var require_Events = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Events.js"(exports2, module14) { + "use strict"; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - #notFoundHandler = notFoundHandler; - // Cannot use `#` because it requires visibility at JavaScript runtime. - errorHandler = errorHandler; - /** - * `.route()` allows grouping other Hono instance in routes. - * - * @see {@link https://hono.dev/docs/api/routing#grouping} - * - * @param {string} path - base Path - * @param {Hono} app - other Hono instance - * @returns {Hono} routed Hono instance - * - * @example - * ```ts - * const app = new Hono() - * const app2 = new Hono() - * - * app2.get("/user", (c) => c.text("user")) - * app.route("/api", app2) // GET /api/user - * ``` - */ - route(path8, app3) { - const subApp = this.basePath(path8); - app3.routes.map((r) => { - let handler; - if (app3.errorHandler === errorHandler) { - handler = r.handler; - } else { - handler = async (c, next) => (await compose([], app3.errorHandler)(c, () => r.handler(c, next))).res; - handler[COMPOSED_HANDLER] = r.handler; + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } - subApp.#addRoute(r.method, r.path, handler); + _next(void 0); }); - return this; - } - /** - * `.basePath()` allows base paths to be specified. - * - * @see {@link https://hono.dev/docs/api/routing#base-path} - * - * @param {string} path - base Path - * @returns {Hono} changed Hono instance - * - * @example - * ```ts - * const api = new Hono().basePath('/api') - * ``` - */ - basePath(path8) { - const subApp = this.#clone(); - subApp._basePath = mergePath(this._basePath, path8); - return subApp; - } - /** - * `.onError()` handles an error and returns a customized Response. - * - * @see {@link https://hono.dev/docs/api/hono#error-handling} - * - * @param {ErrorHandler} handler - request Handler for error - * @returns {Hono} changed Hono instance - * - * @example - * ```ts - * app.onError((err, c) => { - * console.error(`${err}`) - * return c.text('Custom Error Message', 500) - * }) - * ``` - */ - onError = (handler) => { - this.errorHandler = handler; - return this; - }; - /** - * `.notFound()` allows you to customize a Not Found Response. - * - * @see {@link https://hono.dev/docs/api/hono#not-found} - * - * @param {NotFoundHandler} handler - request handler for not-found - * @returns {Hono} changed Hono instance - * - * @example - * ```ts - * app.notFound((c) => { - * return c.text('Custom 404 Message', 404) - * }) - * ``` - */ - notFound = (handler) => { - this.#notFoundHandler = handler; - return this; }; - /** - * `.mount()` allows you to mount applications built with other frameworks into your Hono application. - * - * @see {@link https://hono.dev/docs/api/hono#mount} - * - * @param {string} path - base Path - * @param {Function} applicationHandler - other Request Handler - * @param {MountOptions} [options] - options of `.mount()` - * @returns {Hono} mounted Hono instance - * - * @example - * ```ts - * import { Router as IttyRouter } from 'itty-router' - * import { Hono } from 'hono' - * // Create itty-router application - * const ittyRouter = IttyRouter() - * // GET /itty-router/hello - * ittyRouter.get('/hello', () => new Response('Hello from itty-router')) - * - * const app = new Hono() - * app.mount('/itty-router', ittyRouter.handle) - * ``` - * - * @example - * ```ts - * const app = new Hono() - * // Send the request to another application without modification. - * app.mount('/app', anotherApp, { - * replaceRequest: (req) => req, - * }) - * ``` - */ - mount(path8, applicationHandler, options2) { - let replaceRequest; - let optionHandler; - if (options2) { - if (typeof options2 === "function") { - optionHandler = options2; - } else { - optionHandler = options2.optionHandler; - if (options2.replaceRequest === false) { - replaceRequest = (request) => request; - } else { - replaceRequest = options2.replaceRequest; - } - } + } + var Events2; + Events2 = class Events { + constructor(instance) { + this.instance = instance; + this._events = {}; + if (this.instance.on != null || this.instance.once != null || this.instance.removeAllListeners != null) { + throw new Error("An Emitter already exists for this object"); } - const getOptions = optionHandler ? (c) => { - const options22 = optionHandler(c); - return Array.isArray(options22) ? options22 : [options22]; - } : (c) => { - let executionContext = void 0; - try { - executionContext = c.executionCtx; - } catch { - } - return [c.env, executionContext]; + this.instance.on = (name, cb) => { + return this._addListener(name, "many", cb); }; - replaceRequest ||= (() => { - const mergedPath = mergePath(this._basePath, path8); - const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length; - return (request) => { - const url2 = new URL(request.url); - url2.pathname = url2.pathname.slice(pathPrefixLength) || "/"; - return new Request(url2, request); - }; - })(); - const handler = async (c, next) => { - const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c)); - if (res) { - return res; + this.instance.once = (name, cb) => { + return this._addListener(name, "once", cb); + }; + this.instance.removeAllListeners = (name = null) => { + if (name != null) { + return delete this._events[name]; + } else { + return this._events = {}; } - await next(); }; - this.#addRoute(METHOD_NAME_ALL, mergePath(path8, "*"), handler); - return this; } - #addRoute(method, path8, handler) { - method = method.toUpperCase(); - path8 = mergePath(this._basePath, path8); - const r = { basePath: this._basePath, path: path8, method, handler }; - this.router.add(method, path8, [handler, r]); - this.routes.push(r); - } - #handleError(err, c) { - if (err instanceof Error) { - return this.errorHandler(err, c); + _addListener(name, status, cb) { + var base2; + if ((base2 = this._events)[name] == null) { + base2[name] = []; } - throw err; - } - #dispatch(request, executionCtx, env2, method) { - if (method === "HEAD") { - return (async () => new Response(null, await this.#dispatch(request, executionCtx, env2, "GET")))(); - } - const path8 = this.getPath(request, { env: env2 }); - const matchResult = this.router.match(method, path8); - const c = new Context(request, { - path: path8, - matchResult, - env: env2, - executionCtx, - notFoundHandler: this.#notFoundHandler + this._events[name].push({ + cb, + status }); - if (matchResult[0].length === 1) { - let res; - try { - res = matchResult[0][0][0][0](c, async () => { - c.res = await this.#notFoundHandler(c); - }); - } catch (err) { - return this.#handleError(err, c); - } - return res instanceof Promise ? res.then( - (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c)) - ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c); + return this.instance; + } + listenerCount(name) { + if (this._events[name] != null) { + return this._events[name].length; + } else { + return 0; } - const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler); - return (async () => { - try { - const context = await composed(c); - if (!context.finalized) { - throw new Error( - "Context is not finalized. Did you forget to return a Response object or `await next()`?" - ); - } - return context.res; - } catch (err) { - return this.#handleError(err, c); - } - })(); } - /** - * `.fetch()` will be entry point of your app. - * - * @see {@link https://hono.dev/docs/api/hono#fetch} - * - * @param {Request} request - request Object of request - * @param {Env} Env - env Object - * @param {ExecutionContext} - context of execution - * @returns {Response | Promise} response of request - * - */ - fetch = (request, ...rest) => { - return this.#dispatch(request, rest[1], rest[0], request.method); - }; - /** - * `.request()` is a useful method for testing. - * You can pass a URL or pathname to send a GET request. - * app will return a Response object. - * ```ts - * test('GET /hello is ok', async () => { - * const res = await app.request('/hello') - * expect(res.status).toBe(200) - * }) - * ``` - * @see https://hono.dev/docs/api/hono#request - */ - request = (input, requestInit, Env, executionCtx) => { - if (input instanceof Request) { - return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx); - } - input = input.toString(); - return this.fetch( - new Request( - /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, - requestInit - ), - Env, - executionCtx - ); - }; - /** - * `.fire()` automatically adds a global fetch event listener. - * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers. - * @deprecated - * Use `fire` from `hono/service-worker` instead. - * ```ts - * import { Hono } from 'hono' - * import { fire } from 'hono/service-worker' - * - * const app = new Hono() - * // ... - * fire(app) - * ``` - * @see https://hono.dev/docs/api/hono#fire - * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API - * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/ - */ - fire = () => { - addEventListener("fetch", (event) => { - event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method)); - }); - }; - }; - } -}); -function match(method, path8) { - const matchers = this.buildAllMatchers(); - const match2 = (method2, path22) => { - const matcher = matchers[method2] || matchers[METHOD_NAME_ALL]; - const staticMatch = matcher[2][path22]; - if (staticMatch) { - return staticMatch; - } - const match3 = path22.match(matcher[0]); - if (!match3) { - return [[], emptyParam]; - } - const index = match3.indexOf("", 1); - return [matcher[1][index], match3]; - }; - this.match = match2; - return match2(method, path8); -} -var emptyParam; -var init_matcher = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/matcher.js"() { - init_router(); - emptyParam = []; - } -}); -function compareKey(a, b) { - if (a.length === 1) { - return b.length === 1 ? a < b ? -1 : 1 : -1; - } - if (b.length === 1) { - return 1; - } - if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) { - return 1; - } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) { - return -1; - } - if (a === LABEL_REG_EXP_STR) { - return 1; - } else if (b === LABEL_REG_EXP_STR) { - return -1; - } - return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length; -} -var LABEL_REG_EXP_STR; -var ONLY_WILDCARD_REG_EXP_STR; -var TAIL_WILDCARD_REG_EXP_STR; -var PATH_ERROR; -var regExpMetaChars; -var Node; -var init_node = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/node.js"() { - LABEL_REG_EXP_STR = "[^/]+"; - ONLY_WILDCARD_REG_EXP_STR = ".*"; - TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)"; - PATH_ERROR = /* @__PURE__ */ Symbol(); - regExpMetaChars = new Set(".\\+*[^]$()"); - Node = class _Node { - #index; - #varIndex; - #children = /* @__PURE__ */ Object.create(null); - insert(tokens, index, paramMap, context, pathErrorCheckOnly) { - if (tokens.length === 0) { - if (this.#index !== void 0) { - throw PATH_ERROR; - } - if (pathErrorCheckOnly) { - return; - } - this.#index = index; - return; - } - const [token, ...restTokens] = tokens; - const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); - let node; - if (pattern) { - const name = pattern[1]; - let regexpStr = pattern[2] || LABEL_REG_EXP_STR; - if (name && pattern[2]) { - if (regexpStr === ".*") { - throw PATH_ERROR; - } - regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:"); - if (/\((?!\?:)/.test(regexpStr)) { - throw PATH_ERROR; - } - } - node = this.#children[regexpStr]; - if (!node) { - if (Object.keys(this.#children).some( - (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR - )) { - throw PATH_ERROR; + trigger(name, ...args) { + var _this = this; + return _asyncToGenerator2(function* () { + var e2, promises; + try { + if (name !== "debug") { + _this.trigger("debug", `Event triggered: ${name}`, args); } - if (pathErrorCheckOnly) { + if (_this._events[name] == null) { return; } - node = this.#children[regexpStr] = new _Node(); - if (name !== "") { - node.#varIndex = context.varIndex++; - } - } - if (!pathErrorCheckOnly && name !== "") { - paramMap.push([name, node.#varIndex]); - } - } else { - node = this.#children[token]; - if (!node) { - if (Object.keys(this.#children).some( - (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR - )) { - throw PATH_ERROR; - } - if (pathErrorCheckOnly) { - return; + _this._events[name] = _this._events[name].filter(function(listener) { + return listener.status !== "none"; + }); + promises = _this._events[name].map( + /* @__PURE__ */ function() { + var _ref = _asyncToGenerator2(function* (listener) { + var e3, returned; + if (listener.status === "none") { + return; + } + if (listener.status === "once") { + listener.status = "none"; + } + try { + returned = typeof listener.cb === "function" ? listener.cb(...args) : void 0; + if (typeof (returned != null ? returned.then : void 0) === "function") { + return yield returned; + } else { + return returned; + } + } catch (error2) { + e3 = error2; + if (true) { + _this.trigger("error", e3); + } + return null; + } + }); + return function(_x) { + return _ref.apply(this, arguments); + }; + }() + ); + return (yield Promise.all(promises)).find(function(x3) { + return x3 != null; + }); + } catch (error2) { + e2 = error2; + if (true) { + _this.trigger("error", e2); } - node = this.#children[token] = new _Node(); + return null; } - } - node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly); - } - buildRegExpStr() { - const childKeys = Object.keys(this.#children).sort(compareKey); - const strList = childKeys.map((k) => { - const c = this.#children[k]; - return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr(); - }); - if (typeof this.#index === "number") { - strList.unshift(`#${this.#index}`); - } - if (strList.length === 0) { - return ""; - } - if (strList.length === 1) { - return strList[0]; - } - return "(?:" + strList.join("|") + ")"; + })(); } }; + module14.exports = Events2; } }); -var Trie; -var init_trie = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/trie.js"() { - init_node(); - Trie = class { - #context = { varIndex: 0 }; - #root = new Node(); - insert(path8, index, pathErrorCheckOnly) { - const paramAssoc = []; - const groups = []; - for (let i2 = 0; ; ) { - let replaced = false; - path8 = path8.replace(/\{[^}]+\}/g, (m3) => { - const mark = `@\\${i2}`; - groups[i2] = [mark, m3]; - i2++; - replaced = true; - return mark; - }); - if (!replaced) { - break; +var require_Queues = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Queues.js"(exports2, module14) { + "use strict"; + var DLList; + var Events2; + var Queues; + DLList = require_DLList(); + Events2 = require_Events(); + Queues = class Queues { + constructor(num_priorities) { + var i2; + this.Events = new Events2(this); + this._length = 0; + this._lists = function() { + var j, ref, results; + results = []; + for (i2 = j = 1, ref = num_priorities; 1 <= ref ? j <= ref : j >= ref; i2 = 1 <= ref ? ++j : --j) { + results.push(new DLList(() => { + return this.incr(); + }, () => { + return this.decr(); + })); } + return results; + }.call(this); + } + incr() { + if (this._length++ === 0) { + return this.Events.trigger("leftzero"); } - const tokens = path8.match(/(?::[^\/]+)|(?:\/\*$)|./g) || []; - for (let i2 = groups.length - 1; i2 >= 0; i2--) { - const [mark] = groups[i2]; - for (let j = tokens.length - 1; j >= 0; j--) { - if (tokens[j].indexOf(mark) !== -1) { - tokens[j] = tokens[j].replace(mark, groups[i2][1]); - break; - } - } + } + decr() { + if (--this._length === 0) { + return this.Events.trigger("zero"); } - this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly); - return paramAssoc; } - buildRegExp() { - let regexp = this.#root.buildRegExpStr(); - if (regexp === "") { - return [/^$/, [], []]; + push(job) { + return this._lists[job.options.priority].push(job); + } + queued(priority) { + if (priority != null) { + return this._lists[priority].length; + } else { + return this._length; } - let captureIndex = 0; - const indexReplacementMap = []; - const paramReplacementMap = []; - regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => { - if (handlerIndex !== void 0) { - indexReplacementMap[++captureIndex] = Number(handlerIndex); - return "$()"; - } - if (paramIndex !== void 0) { - paramReplacementMap[Number(paramIndex)] = ++captureIndex; - return ""; - } - return ""; + } + shiftAll(fn) { + return this._lists.forEach(function(list) { + return list.forEachShift(fn); }); - return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap]; + } + getFirst(arr = this._lists) { + var j, len, list; + for (j = 0, len = arr.length; j < len; j++) { + list = arr[j]; + if (list.length > 0) { + return list; + } + } + return []; + } + shiftLastFrom(priority) { + return this.getFirst(this._lists.slice(priority).reverse()).shift(); } }; + module14.exports = Queues; } }); -function buildWildcardRegExp(path8) { - return wildcardRegExpCache[path8] ??= new RegExp( - path8 === "*" ? "" : `^${path8.replace( - /\/\*$|([.\\+*[^\]$()])/g, - (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)" - )}$` - ); -} -function clearWildcardRegExpCache() { - wildcardRegExpCache = /* @__PURE__ */ Object.create(null); -} -function buildMatcherFromPreprocessedRoutes(routes) { - const trie = new Trie(); - const handlerData = []; - if (routes.length === 0) { - return nullMatcher; - } - const routesWithStaticPathFlag = routes.map( - (route) => [!/\*|\/:/.test(route[0]), ...route] - ).sort( - ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length - ); - const staticMap = /* @__PURE__ */ Object.create(null); - for (let i2 = 0, j = -1, len = routesWithStaticPathFlag.length; i2 < len; i2++) { - const [pathErrorCheckOnly, path8, handlers] = routesWithStaticPathFlag[i2]; - if (pathErrorCheckOnly) { - staticMap[path8] = [handlers.map(([h2]) => [h2, /* @__PURE__ */ Object.create(null)]), emptyParam]; - } else { - j++; - } - let paramAssoc; - try { - paramAssoc = trie.insert(path8, j, pathErrorCheckOnly); - } catch (e2) { - throw e2 === PATH_ERROR ? new UnsupportedPathError(path8) : e2; - } - if (pathErrorCheckOnly) { - continue; - } - handlerData[j] = handlers.map(([h2, paramCount]) => { - const paramIndexMap = /* @__PURE__ */ Object.create(null); - paramCount -= 1; - for (; paramCount >= 0; paramCount--) { - const [key, value] = paramAssoc[paramCount]; - paramIndexMap[key] = value; - } - return [h2, paramIndexMap]; - }); +var require_BottleneckError = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/BottleneckError.js"(exports2, module14) { + "use strict"; + var BottleneckError; + BottleneckError = class BottleneckError extends Error { + }; + module14.exports = BottleneckError; } - const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp(); - for (let i2 = 0, len = handlerData.length; i2 < len; i2++) { - for (let j = 0, len2 = handlerData[i2].length; j < len2; j++) { - const map = handlerData[i2][j]?.[1]; - if (!map) { - continue; +}); +var require_Job = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Job.js"(exports2, module14) { + "use strict"; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - const keys = Object.keys(map); - for (let k = 0, len3 = keys.length; k < len3; k++) { - map[keys[k]] = paramReplacementMap[map[keys[k]]]; + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } } - } - const handlerMap = []; - for (const i2 in indexReplacementMap) { - handlerMap[i2] = handlerData[indexReplacementMap[i2]]; - } - return [regexp, handlerMap, staticMap]; -} -function findMiddleware(middleware, path8) { - if (!middleware) { - return void 0; - } - for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) { - if (buildWildcardRegExp(k).test(path8)) { - return [...middleware[k]]; + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; } - } - return void 0; -} -var nullMatcher; -var wildcardRegExpCache; -var RegExpRouter; -var init_router2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/router.js"() { - init_router(); - init_url(); - init_matcher(); - init_node(); - init_trie(); - nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)]; - wildcardRegExpCache = /* @__PURE__ */ Object.create(null); - RegExpRouter = class { - name = "RegExpRouter"; - #middleware; - #routes; - constructor() { - this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; - this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; - } - add(method, path8, handler) { - const middleware = this.#middleware; - const routes = this.#routes; - if (!middleware || !routes) { - throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); - } - if (!middleware[method]) { - ; - [middleware, routes].forEach((handlerMap) => { - handlerMap[method] = /* @__PURE__ */ Object.create(null); - Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => { - handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]]; - }); - }); + var BottleneckError; + var DEFAULT_PRIORITY; + var Job; + var NUM_PRIORITIES; + var parser3; + NUM_PRIORITIES = 10; + DEFAULT_PRIORITY = 5; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + Job = class Job { + constructor(task, args, options2, jobDefaults, rejectOnDrop, Events2, _states, Promise2) { + this.task = task; + this.args = args; + this.rejectOnDrop = rejectOnDrop; + this.Events = Events2; + this._states = _states; + this.Promise = Promise2; + this.options = parser3.load(options2, jobDefaults); + this.options.priority = this._sanitizePriority(this.options.priority); + if (this.options.id === jobDefaults.id) { + this.options.id = `${this.options.id}-${this._randomIndex()}`; } - if (path8 === "/*") { - path8 = "*"; + this.promise = new this.Promise((_resolve, _reject) => { + this._resolve = _resolve; + this._reject = _reject; + }); + this.retryCount = 0; + } + _sanitizePriority(priority) { + var sProperty; + sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; + if (sProperty < 0) { + return 0; + } else if (sProperty > NUM_PRIORITIES - 1) { + return NUM_PRIORITIES - 1; + } else { + return sProperty; } - const paramCount = (path8.match(/\/:/g) || []).length; - if (/\*$/.test(path8)) { - const re = buildWildcardRegExp(path8); - if (method === METHOD_NAME_ALL) { - Object.keys(middleware).forEach((m3) => { - middleware[m3][path8] ||= findMiddleware(middleware[m3], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; - }); - } else { - middleware[method][path8] ||= findMiddleware(middleware[method], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; + } + _randomIndex() { + return Math.random().toString(36).slice(2); + } + doDrop({ + error: error2, + message = "This job has been dropped by Bottleneck" + } = {}) { + if (this._states.remove(this.options.id)) { + if (this.rejectOnDrop) { + this._reject(error2 != null ? error2 : new BottleneckError(message)); } - Object.keys(middleware).forEach((m3) => { - if (method === METHOD_NAME_ALL || method === m3) { - Object.keys(middleware[m3]).forEach((p) => { - re.test(p) && middleware[m3][p].push([handler, paramCount]); - }); - } - }); - Object.keys(routes).forEach((m3) => { - if (method === METHOD_NAME_ALL || method === m3) { - Object.keys(routes[m3]).forEach( - (p) => re.test(p) && routes[m3][p].push([handler, paramCount]) - ); - } + this.Events.trigger("dropped", { + args: this.args, + options: this.options, + task: this.task, + promise: this.promise }); - return; + return true; + } else { + return false; } - const paths = checkOptionalParameter(path8) || [path8]; - for (let i2 = 0, len = paths.length; i2 < len; i2++) { - const path22 = paths[i2]; - Object.keys(routes).forEach((m3) => { - if (method === METHOD_NAME_ALL || method === m3) { - routes[m3][path22] ||= [ - ...findMiddleware(middleware[m3], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || [] - ]; - routes[m3][path22].push([handler, paramCount - len + i2 + 1]); - } - }); + } + _assertStatus(expected) { + var status; + status = this._states.jobStatus(this.options.id); + if (!(status === expected || expected === "DONE" && status === null)) { + throw new BottleneckError(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`); } } - match = match; - buildAllMatchers() { - const matchers = /* @__PURE__ */ Object.create(null); - Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => { - matchers[method] ||= this.#buildMatcher(method); + doReceive() { + this._states.start(this.options.id); + return this.Events.trigger("received", { + args: this.args, + options: this.options }); - this.#middleware = this.#routes = void 0; - clearWildcardRegExpCache(); - return matchers; - } - #buildMatcher(method) { - const routes = []; - let hasOwnRoute = method === METHOD_NAME_ALL; - [this.#middleware, this.#routes].forEach((r) => { - const ownRoute = r[method] ? Object.keys(r[method]).map((path8) => [path8, r[method][path8]]) : []; - if (ownRoute.length !== 0) { - hasOwnRoute ||= true; - routes.push(...ownRoute); - } else if (method !== METHOD_NAME_ALL) { - routes.push( - ...Object.keys(r[METHOD_NAME_ALL]).map((path8) => [path8, r[METHOD_NAME_ALL][path8]]) - ); - } + } + doQueue(reachedHWM, blocked) { + this._assertStatus("RECEIVED"); + this._states.next(this.options.id); + return this.Events.trigger("queued", { + args: this.args, + options: this.options, + reachedHWM, + blocked }); - if (!hasOwnRoute) { - return null; + } + doRun() { + if (this.retryCount === 0) { + this._assertStatus("QUEUED"); + this._states.next(this.options.id); } else { - return buildMatcherFromPreprocessedRoutes(routes); + this._assertStatus("EXECUTING"); } + return this.Events.trigger("scheduled", { + args: this.args, + options: this.options + }); } - }; - } -}); -var init_prepared_router = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/prepared-router.js"() { - init_router(); - init_matcher(); - init_router2(); - } -}); -var init_reg_exp_router = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/reg-exp-router/index.js"() { - init_router2(); - init_prepared_router(); - } -}); -var SmartRouter; -var init_router3 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/smart-router/router.js"() { - init_router(); - SmartRouter = class { - name = "SmartRouter"; - #routers = []; - #routes = []; - constructor(init2) { - this.#routers = init2.routers; + doExecute(chained, clearGlobalState, run2, free) { + var _this = this; + return _asyncToGenerator2(function* () { + var error2, eventInfo, passed; + if (_this.retryCount === 0) { + _this._assertStatus("RUNNING"); + _this._states.next(_this.options.id); + } else { + _this._assertStatus("EXECUTING"); + } + eventInfo = { + args: _this.args, + options: _this.options, + retryCount: _this.retryCount + }; + _this.Events.trigger("executing", eventInfo); + try { + passed = yield chained != null ? chained.schedule(_this.options, _this.task, ..._this.args) : _this.task(..._this.args); + if (clearGlobalState()) { + _this.doDone(eventInfo); + yield free(_this.options, eventInfo); + _this._assertStatus("DONE"); + return _this._resolve(passed); + } + } catch (error1) { + error2 = error1; + return _this._onFailure(error2, eventInfo, clearGlobalState, run2, free); + } + })(); } - add(method, path8, handler) { - if (!this.#routes) { - throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); + doExpire(clearGlobalState, run2, free) { + var error2, eventInfo; + if (this._states.jobStatus(this.options.id === "RUNNING")) { + this._states.next(this.options.id); } - this.#routes.push([method, path8, handler]); + this._assertStatus("EXECUTING"); + eventInfo = { + args: this.args, + options: this.options, + retryCount: this.retryCount + }; + error2 = new BottleneckError(`This job timed out after ${this.options.expiration} ms.`); + return this._onFailure(error2, eventInfo, clearGlobalState, run2, free); } - match(method, path8) { - if (!this.#routes) { - throw new Error("Fatal error"); - } - const routers = this.#routers; - const routes = this.#routes; - const len = routers.length; - let i2 = 0; - let res; - for (; i2 < len; i2++) { - const router = routers[i2]; - try { - for (let i22 = 0, len2 = routes.length; i22 < len2; i22++) { - router.add(...routes[i22]); - } - res = router.match(method, path8); - } catch (e2) { - if (e2 instanceof UnsupportedPathError) { - continue; + _onFailure(error2, eventInfo, clearGlobalState, run2, free) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var retry, retryAfter; + if (clearGlobalState()) { + retry = yield _this2.Events.trigger("failed", error2, eventInfo); + if (retry != null) { + retryAfter = ~~retry; + _this2.Events.trigger("retry", `Retrying ${_this2.options.id} after ${retryAfter} ms`, eventInfo); + _this2.retryCount++; + return run2(retryAfter); + } else { + _this2.doDone(eventInfo); + yield free(_this2.options, eventInfo); + _this2._assertStatus("DONE"); + return _this2._reject(error2); } - throw e2; } - this.match = router.match.bind(router); - this.#routers = [router]; - this.#routes = void 0; - break; - } - if (i2 === len) { - throw new Error("Fatal error"); - } - this.name = `SmartRouter + ${this.activeRouter.name}`; - return res; + })(); } - get activeRouter() { - if (this.#routes || this.#routers.length !== 1) { - throw new Error("No active router has been determined yet."); - } - return this.#routers[0]; + doDone(eventInfo) { + this._assertStatus("EXECUTING"); + this._states.next(this.options.id); + return this.Events.trigger("done", eventInfo); } }; + module14.exports = Job; } }); -var init_smart_router = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/smart-router/index.js"() { - init_router3(); - } -}); -var emptyParams; -var hasChildren; -var Node2; -var init_node2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/node.js"() { - init_router(); - init_url(); - emptyParams = /* @__PURE__ */ Object.create(null); - hasChildren = (children) => { - for (const _ in children) { - return true; +var require_LocalDatastore = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/LocalDatastore.js"(exports2, module14) { + "use strict"; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - return false; - }; - Node2 = class _Node2 { - #methods; - #children; - #patterns; - #order = 0; - #params = emptyParams; - constructor(method, handler, children) { - this.#children = children || /* @__PURE__ */ Object.create(null); - this.#methods = []; - if (method && handler) { - const m3 = /* @__PURE__ */ Object.create(null); - m3[method] = { handler, possibleKeys: [], score: 0 }; - this.#methods = [m3]; - } - this.#patterns = []; - } - insert(method, path8, handler) { - this.#order = ++this.#order; - let curNode = this; - const parts = splitRoutingPath(path8); - const possibleKeys = []; - for (let i2 = 0, len = parts.length; i2 < len; i2++) { - const p = parts[i2]; - const nextP = parts[i2 + 1]; - const pattern = getPattern(p, nextP); - const key = Array.isArray(pattern) ? pattern[0] : p; - if (key in curNode.#children) { - curNode = curNode.#children[key]; - if (pattern) { - possibleKeys.push(pattern[1]); - } - continue; - } - curNode.#children[key] = new _Node2(); - if (pattern) { - curNode.#patterns.push(pattern); - possibleKeys.push(pattern[1]); + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - curNode = curNode.#children[key]; - } - curNode.#methods.push({ - [method]: { - handler, - possibleKeys: possibleKeys.filter((v2, i2, a) => a.indexOf(v2) === i2), - score: this.#order + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } + _next(void 0); }); - return curNode; - } - #pushHandlerSets(handlerSets, node, method, nodeParams, params) { - for (let i2 = 0, len = node.#methods.length; i2 < len; i2++) { - const m3 = node.#methods[i2]; - const handlerSet = m3[method] || m3[METHOD_NAME_ALL]; - const processedSet = {}; - if (handlerSet !== void 0) { - handlerSet.params = /* @__PURE__ */ Object.create(null); - handlerSets.push(handlerSet); - if (nodeParams !== emptyParams || params && params !== emptyParams) { - for (let i22 = 0, len2 = handlerSet.possibleKeys.length; i22 < len2; i22++) { - const key = handlerSet.possibleKeys[i22]; - const processed = processedSet[handlerSet.score]; - handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]; - processedSet[handlerSet.score] = true; - } - } - } - } + }; + } + var BottleneckError; + var LocalDatastore; + var parser3; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + LocalDatastore = class LocalDatastore { + constructor(instance, storeOptions, storeInstanceOptions) { + this.instance = instance; + this.storeOptions = storeOptions; + this.clientId = this.instance._randomIndex(); + parser3.load(storeInstanceOptions, storeInstanceOptions, this); + this._nextRequest = this._lastReservoirRefresh = this._lastReservoirIncrease = Date.now(); + this._running = 0; + this._done = 0; + this._unblockTime = 0; + this.ready = this.Promise.resolve(); + this.clients = {}; + this._startHeartbeat(); } - search(method, path8) { - const handlerSets = []; - this.#params = emptyParams; - const curNode = this; - let curNodes = [curNode]; - const parts = splitPath(path8); - const curNodesQueue = []; - const len = parts.length; - let partOffsets = null; - for (let i2 = 0; i2 < len; i2++) { - const part = parts[i2]; - const isLast = i2 === len - 1; - const tempNodes = []; - for (let j = 0, len2 = curNodes.length; j < len2; j++) { - const node = curNodes[j]; - const nextNode = node.#children[part]; - if (nextNode) { - nextNode.#params = node.#params; - if (isLast) { - if (nextNode.#children["*"]) { - this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params); - } - this.#pushHandlerSets(handlerSets, nextNode, method, node.#params); - } else { - tempNodes.push(nextNode); - } + _startHeartbeat() { + var base2; + if (this.heartbeat == null && (this.storeOptions.reservoirRefreshInterval != null && this.storeOptions.reservoirRefreshAmount != null || this.storeOptions.reservoirIncreaseInterval != null && this.storeOptions.reservoirIncreaseAmount != null)) { + return typeof (base2 = this.heartbeat = setInterval(() => { + var amount, incr, maximum, now, reservoir; + now = Date.now(); + if (this.storeOptions.reservoirRefreshInterval != null && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { + this._lastReservoirRefresh = now; + this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; + this.instance._drainAll(this.computeCapacity()); } - for (let k = 0, len3 = node.#patterns.length; k < len3; k++) { - const pattern = node.#patterns[k]; - const params = node.#params === emptyParams ? {} : { ...node.#params }; - if (pattern === "*") { - const astNode = node.#children["*"]; - if (astNode) { - this.#pushHandlerSets(handlerSets, astNode, method, node.#params); - astNode.#params = params; - tempNodes.push(astNode); - } - continue; - } - const [key, name, matcher] = pattern; - if (!part && !(matcher instanceof RegExp)) { - continue; - } - const child = node.#children[key]; - if (matcher instanceof RegExp) { - if (partOffsets === null) { - partOffsets = new Array(len); - let offset = path8[0] === "/" ? 1 : 0; - for (let p = 0; p < len; p++) { - partOffsets[p] = offset; - offset += parts[p].length + 1; - } - } - const restPathString = path8.substring(partOffsets[i2]); - const m3 = matcher.exec(restPathString); - if (m3) { - params[name] = m3[0]; - this.#pushHandlerSets(handlerSets, child, method, node.#params, params); - if (hasChildren(child.#children)) { - child.#params = params; - const componentCount = m3[0].match(/\//)?.length ?? 0; - const targetCurNodes = curNodesQueue[componentCount] ||= []; - targetCurNodes.push(child); - } - continue; - } - } - if (matcher === true || matcher.test(part)) { - params[name] = part; - if (isLast) { - this.#pushHandlerSets(handlerSets, child, method, params, node.#params); - if (child.#children["*"]) { - this.#pushHandlerSets( - handlerSets, - child.#children["*"], - method, - params, - node.#params - ); - } - } else { - child.#params = params; - tempNodes.push(child); - } + if (this.storeOptions.reservoirIncreaseInterval != null && now >= this._lastReservoirIncrease + this.storeOptions.reservoirIncreaseInterval) { + var _this$storeOptions = this.storeOptions; + amount = _this$storeOptions.reservoirIncreaseAmount; + maximum = _this$storeOptions.reservoirIncreaseMaximum; + reservoir = _this$storeOptions.reservoir; + this._lastReservoirIncrease = now; + incr = maximum != null ? Math.min(amount, maximum - reservoir) : amount; + if (incr > 0) { + this.storeOptions.reservoir += incr; + return this.instance._drainAll(this.computeCapacity()); } } - } - const shifted = curNodesQueue.shift(); - curNodes = shifted ? tempNodes.concat(shifted) : tempNodes; - } - if (handlerSets.length > 1) { - handlerSets.sort((a, b) => { - return a.score - b.score; - }); + }, this.heartbeatInterval)).unref === "function" ? base2.unref() : void 0; + } else { + return clearInterval(this.heartbeat); } - return [handlerSets.map(({ handler, params }) => [handler, params])]; - } - }; - } -}); -var TrieRouter; -var init_router4 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/router.js"() { - init_url(); - init_node2(); - TrieRouter = class { - name = "TrieRouter"; - #node; - constructor() { - this.#node = new Node2(); } - add(method, path8, handler) { - const results = checkOptionalParameter(path8); - if (results) { - for (let i2 = 0, len = results.length; i2 < len; i2++) { - this.#node.insert(method, results[i2], handler); - } - return; - } - this.#node.insert(method, path8, handler); + __publish__(message) { + var _this = this; + return _asyncToGenerator2(function* () { + yield _this.yieldLoop(); + return _this.instance.Events.trigger("message", message.toString()); + })(); } - match(method, path8) { - return this.#node.search(method, path8); + __disconnect__(flush) { + var _this2 = this; + return _asyncToGenerator2(function* () { + yield _this2.yieldLoop(); + clearInterval(_this2.heartbeat); + return _this2.Promise.resolve(); + })(); } - }; - } -}); -var init_trie_router = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/router/trie-router/index.js"() { - init_router4(); - } -}); -var Hono2; -var init_hono = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/hono.js"() { - init_hono_base(); - init_reg_exp_router(); - init_smart_router(); - init_trie_router(); - Hono2 = class extends Hono { - /** - * Creates an instance of the Hono class. - * - * @param options - Optional configuration options for the Hono instance. - */ - constructor(options2 = {}) { - super(options2); - this.router = options2.router ?? new SmartRouter({ - routers: [new RegExpRouter(), new TrieRouter()] + yieldLoop(t = 0) { + return new this.Promise(function(resolve82, reject) { + return setTimeout(resolve82, t); }); } - }; - } -}); -var init_dist = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/index.js"() { - init_hono(); - } -}); -var COMPRESSIBLE_CONTENT_TYPE_REGEX; -var init_compress = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/compress.js"() { - COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; - } -}); -var getMimeType; -var _baseMimes; -var baseMimes; -var init_mime = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/mime.js"() { - getMimeType = (filename, mimes = baseMimes) => { - const regexp = /\.([a-zA-Z0-9]+?)$/; - const match2 = filename.match(regexp); - if (!match2) { - return; - } - let mimeType = mimes[match2[1].toLowerCase()]; - if (mimeType && mimeType.startsWith("text")) { - mimeType += "; charset=utf-8"; - } - return mimeType; - }; - _baseMimes = { - aac: "audio/aac", - avi: "video/x-msvideo", - avif: "image/avif", - av1: "video/av1", - bin: "application/octet-stream", - bmp: "image/bmp", - css: "text/css", - csv: "text/csv", - eot: "application/vnd.ms-fontobject", - epub: "application/epub+zip", - gif: "image/gif", - gz: "application/gzip", - htm: "text/html", - html: "text/html", - ico: "image/x-icon", - ics: "text/calendar", - jpeg: "image/jpeg", - jpg: "image/jpeg", - js: "text/javascript", - json: "application/json", - jsonld: "application/ld+json", - map: "application/json", - mid: "audio/x-midi", - midi: "audio/x-midi", - mjs: "text/javascript", - mp3: "audio/mpeg", - mp4: "video/mp4", - mpeg: "video/mpeg", - oga: "audio/ogg", - ogv: "video/ogg", - ogx: "application/ogg", - opus: "audio/opus", - otf: "font/otf", - pdf: "application/pdf", - png: "image/png", - rtf: "application/rtf", - svg: "image/svg+xml", - tif: "image/tiff", - tiff: "image/tiff", - ts: "video/mp2t", - ttf: "font/ttf", - txt: "text/plain", - wasm: "application/wasm", - webm: "video/webm", - weba: "audio/webm", - webmanifest: "application/manifest+json", - webp: "image/webp", - woff: "font/woff", - woff2: "font/woff2", - xhtml: "application/xhtml+xml", - xml: "application/xml", - zip: "application/zip", - "3gp": "video/3gpp", - "3g2": "video/3gpp2", - gltf: "model/gltf+json", - glb: "model/gltf-binary" - }; - baseMimes = _baseMimes; - } -}); -var defaultJoin; -var init_path = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/serve-static/path.js"() { - defaultJoin = (...paths) => { - let result = paths.filter((p) => p !== "").join("/"); - result = result.replace(/(?<=\/)\/+/g, ""); - const segments = result.split("/"); - const resolved = []; - for (const segment of segments) { - if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { - resolved.pop(); - } else if (segment !== ".") { - resolved.push(segment); - } - } - return resolved.join("/") || "."; - }; - } -}); -var ENCODINGS; -var ENCODINGS_ORDERED_KEYS; -var DEFAULT_DOCUMENT; -var serveStatic; -var init_serve_static = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/serve-static/index.js"() { - init_compress(); - init_mime(); - init_url(); - init_path(); - ENCODINGS = { - br: ".br", - zstd: ".zst", - gzip: ".gz" - }; - ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); - DEFAULT_DOCUMENT = "index.html"; - serveStatic = (options2) => { - const root = options2.root ?? "./"; - const optionPath = options2.path; - const join10 = options2.join ?? defaultJoin; - return async (c, next) => { - if (c.finalized) { - return next(); - } - let filename; - if (options2.path) { - filename = options2.path; - } else { - try { - filename = tryDecodeURI(c.req.path); - if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { - throw new Error(); - } - } catch { - await options2.onNotFound?.(c.req.path, c); - return next(); - } - } - let path8 = join10( - root, - !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename - ); - if (options2.isDir && await options2.isDir(path8)) { - path8 = join10(path8, DEFAULT_DOCUMENT); - } - const getContent = options2.getContent; - let content = await getContent(path8, c); - if (content instanceof Response) { - return c.newResponse(content.body, content); - } - if (content) { - const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); - c.header("Content-Type", mimeType || "application/octet-stream"); - if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { - const acceptEncodingSet = new Set( - c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) - ); - for (const encoding of ENCODINGS_ORDERED_KEYS) { - if (!acceptEncodingSet.has(encoding)) { - continue; - } - const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); - if (compressedContent) { - content = compressedContent; - c.header("Content-Encoding", encoding); - c.header("Vary", "Accept-Encoding", { append: true }); - break; - } - } - } - await options2.onFound?.(path8, c); - return c.body(content); - } - await options2.onNotFound?.(path8, c); - await next(); - return; - }; - }; - } -}); -var open; -var lstatSync; -var errors; -var serveStatic2; -var init_serve_static2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/serve-static.js"() { - init_serve_static(); - ({ open, lstatSync, errors } = Deno); - serveStatic2 = (options2) => { - return async function serveStatic22(c, next) { - const getContent = async (path8) => { - try { - if (isDir(path8)) { - return null; - } - const file = await open(path8); - return file.readable; - } catch (e2) { - if (!(e2 instanceof errors.NotFound)) { - console.warn(`${e2}`); - } - return null; - } - }; - const isDir = (path8) => { - let isDir2; - try { - const stat = lstatSync(path8); - isDir2 = stat.isDirectory; - } catch { - } - return isDir2; - }; - return serveStatic({ - ...options2, - getContent, - join: join72, - isDir - })(c, next); - }; - }; - } -}); -var init_fetch_result_please = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/client/fetch-result-please.js"() { - } -}); -var init_utils2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/client/utils.js"() { - init_fetch_result_please(); - } -}); -var init_concurrent = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/concurrent.js"() { - } -}); -var init_handler = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/handler.js"() { - init_constants3(); - } -}); -var init_utils3 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/utils.js"() { - init_router(); - init_handler(); - } -}); -var X_HONO_DISABLE_SSG_HEADER_KEY; -var SSG_DISABLED_RESPONSE; -var init_middleware = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/middleware.js"() { - init_utils3(); - X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; - SSG_DISABLED_RESPONSE = (() => { - try { - return new Response("SSG is disabled", { - status: 404, - headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } - }); - } catch { - return null; + computePenalty() { + var ref; + return (ref = this.storeOptions.penalty) != null ? ref : 15 * this.storeOptions.minTime || 5e3; } - })(); - } -}); -var init_html2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/html/index.js"() { - init_html(); - } -}); -var init_plugins = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/plugins.js"() { - init_html2(); - } -}); -var init_ssg = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/ssg.js"() { - init_utils2(); - init_concurrent(); - init_mime(); - init_middleware(); - init_plugins(); - init_utils3(); - } -}); -var init_ssg2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/ssg/index.js"() { - init_ssg(); - init_middleware(); - init_plugins(); - } -}); -var init_ssg3 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/ssg.js"() { - init_ssg2(); - } -}); -var WSContext; -var defineWebSocketHelper; -var init_websocket = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/websocket/index.js"() { - WSContext = class { - #init; - constructor(init2) { - this.#init = init2; - this.raw = init2.raw; - this.url = init2.url ? new URL(init2.url) : null; - this.protocol = init2.protocol ?? null; + __updateSettings__(options2) { + var _this3 = this; + return _asyncToGenerator2(function* () { + yield _this3.yieldLoop(); + parser3.overwrite(options2, options2, _this3.storeOptions); + _this3._startHeartbeat(); + _this3.instance._drainAll(_this3.computeCapacity()); + return true; + })(); } - send(source, options2) { - this.#init.send(source, options2 ?? {}); + __running__() { + var _this4 = this; + return _asyncToGenerator2(function* () { + yield _this4.yieldLoop(); + return _this4._running; + })(); } - raw; - binaryType = "arraybuffer"; - get readyState() { - return this.#init.readyState; + __queued__() { + var _this5 = this; + return _asyncToGenerator2(function* () { + yield _this5.yieldLoop(); + return _this5.instance.queued(); + })(); } - url; - protocol; - close(code2, reason) { - this.#init.close(code2, reason); - } - }; - defineWebSocketHelper = (handler) => { - return (...args) => { - if (typeof args[0] === "function") { - const [createEvents, options2] = args; - return async function upgradeWebSocket2(c, next) { - const events = await createEvents(c); - const result = await handler(c, events, options2); - if (result) { - return result; - } - await next(); - }; - } else { - const [c, events, options2] = args; - return (async () => { - const upgraded = await handler(c, events, options2); - if (!upgraded) { - throw new Error("Failed to upgrade WebSocket"); - } - return upgraded; - })(); - } - }; - }; - } -}); -var upgradeWebSocket; -var init_websocket2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/websocket.js"() { - init_websocket(); - upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { - if (c.req.header("upgrade") !== "websocket") { - return; + __done__() { + var _this6 = this; + return _asyncToGenerator2(function* () { + yield _this6.yieldLoop(); + return _this6._done; + })(); } - const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); - const wsContext = new WSContext({ - close: (code2, reason) => socket.close(code2, reason), - get protocol() { - return socket.protocol; - }, - raw: socket, - get readyState() { - return socket.readyState; - }, - url: socket.url ? new URL(socket.url) : null, - send: (source) => socket.send(source) - }); - socket.onopen = (evt) => events.onOpen?.(evt, wsContext); - socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); - socket.onclose = (evt) => events.onClose?.(evt, wsContext); - socket.onerror = (evt) => events.onError?.(evt, wsContext); - return response; - }); - } -}); -var init_conninfo = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/conninfo.js"() { - } -}); -var init_deno = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/adapter/deno/index.js"() { - init_serve_static2(); - init_ssg3(); - init_websocket2(); - init_conninfo(); - } -}); -var dashboard_server_exports = {}; -__export(dashboard_server_exports, { - default: () => dashboard_server_default, - startDashboard: () => startDashboard -}); -async function startDashboard() { - const port = import_npm_nconf4.default.get("server:dashboardPort"); - const host = import_npm_nconf4.default.get("server:host") || "0.0.0.0"; - const dashboardRoot = getDashboardPath(); - const app3 = new Hono2(); - app3.get("/assets/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); - app3.get("/dashboard", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); - app3.get("/dashboard/", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); - app3.get("/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); - app3.get("/*", serveStatic2({ path: path5.join(dashboardRoot, "index.html") })); - await new Promise((resolve82) => { - Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app3.fetch); - }); -} -var import_npm_nconf4; -var getDashboardPath; -var dashboard_server_default; -var init_dashboard_server = __esm({ - "src/serve/dashboard-server.ts"() { - "use strict"; - init_dist(); - init_deno(); - import_npm_nconf4 = __toESM(require_nconf()); - getDashboardPath = () => { - return path5.resolve(import.meta.dirname || process5.cwd(), "dist-dashboard"); - }; - dashboard_server_default = startDashboard; - } -}); -var isEventQueueSbpEvent2; -var esm_default5; -var init_esm9 = __esm({ - "node_modules/.deno/@sbp+okturtles.eventqueue@1.2.0/node_modules/@sbp/okturtles.eventqueue/dist/esm/index.js"() { - init_esm(); - isEventQueueSbpEvent2 = (e2) => { - return Object.prototype.hasOwnProperty.call(e2, "sbpInvocation"); - }; - esm_default5 = esm_default("sbp/selectors/register", { - "okTurtles.eventQueue/_init": function() { - this.eventQueues = /* @__PURE__ */ Object.create(null); - }, - "okTurtles.eventQueue/isWaiting": function(name) { - var _a2; - return !!((_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.length); - }, - "okTurtles.eventQueue/queuedInvocations": function(name) { - var _a2, _b; - if (name == null) { - return Object.fromEntries(Object.entries(this.eventQueues).map(([name2, events]) => [name2, events.map((event) => { - if (isEventQueueSbpEvent2(event)) { - return event.sbpInvocation; - } else { - return event.fn; - } - })])); - } - return (_b = (_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.map((event) => { - if (isEventQueueSbpEvent2(event)) { - return event.sbpInvocation; - } else { - return event.fn; - } - })) !== null && _b !== void 0 ? _b : []; - }, - "okTurtles.eventQueue/queueEvent": async function(name, invocation) { - if (!Object.prototype.hasOwnProperty.call(this.eventQueues, name)) { - this.eventQueues[name] = []; - } - const events = this.eventQueues[name]; - let accept; - const promise = new Promise((resolve82) => { - accept = resolve82; - }); - const thisEvent = typeof invocation === "function" ? { - fn: invocation, - promise - } : { - sbpInvocation: invocation, - promise - }; - events.push(thisEvent); - while (events.length > 0) { - const event = events[0]; - if (event === thisEvent) { - try { - if (typeof invocation === "function") { - return await invocation(); - } else { - return await esm_default(...invocation); - } - } finally { - accept(); - events.shift(); - } - } else { - await event.promise; - } - } + __groupCheck__(time3) { + var _this7 = this; + return _asyncToGenerator2(function* () { + yield _this7.yieldLoop(); + return _this7._nextRequest + _this7.timeout < time3; + })(); } - }); - } -}); -var listenKey2; -var esm_default6; -var init_esm10 = __esm({ - "node_modules/.deno/@sbp+okturtles.events@1.0.0/node_modules/@sbp/okturtles.events/dist/esm/index.js"() { - init_esm(); - init_esm3(); - listenKey2 = (evt) => `events/${evt}/listeners`; - esm_default6 = esm_default("sbp/selectors/register", { - "okTurtles.events/_init": function() { - this.errorHandler = (event, e2) => { - console.error(`[okTurtles.events] Error at handler for ${event}`, e2); - }; - }, - "okTurtles.events/on": function(event, handler) { - esm_default("okTurtles.data/add", listenKey2(event), handler); - return () => esm_default("okTurtles.events/off", event, handler); - }, - "okTurtles.events/once": function(event, handler) { - const cbWithOff = (...args) => { - handler(...args); - esm_default("okTurtles.events/off", event, cbWithOff); - }; - return esm_default("okTurtles.events/on", event, cbWithOff); - }, - "okTurtles.events/emit": function(event, ...data) { - var _a2; - for (const listener of esm_default("okTurtles.data/get", listenKey2(event)) || []) { - try { - listener(...data); - } catch (e2) { - (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); - } - } - }, - // almost identical to Vue.prototype.$off, except we require `event` argument - "okTurtles.events/off": function(event, handler) { - if (handler) { - esm_default("okTurtles.data/remove", listenKey2(event), handler); + computeCapacity() { + var maxConcurrent, reservoir; + var _this$storeOptions2 = this.storeOptions; + maxConcurrent = _this$storeOptions2.maxConcurrent; + reservoir = _this$storeOptions2.reservoir; + if (maxConcurrent != null && reservoir != null) { + return Math.min(maxConcurrent - this._running, reservoir); + } else if (maxConcurrent != null) { + return maxConcurrent - this._running; + } else if (reservoir != null) { + return reservoir; } else { - esm_default("okTurtles.data/delete", listenKey2(event)); + return null; } - }, - "okTurtles.events/setErrorHandler": function(errorHandler2) { - this.errorHandler = errorHandler2; - } - }); - } -}); -var require_has_flag = __commonJS({ - "node_modules/.deno/has-flag@4.0.0/node_modules/has-flag/index.js"(exports2, module14) { - "use strict"; - module14.exports = (flag, argv = process.argv) => { - const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--"; - const position = argv.indexOf(prefix + flag); - const terminatorPosition = argv.indexOf("--"); - return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition); - }; - } -}); -var require_supports_color = __commonJS({ - "node_modules/.deno/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module14) { - "use strict"; - var os = __require2("os"); - var tty = __require2("tty"); - var hasFlag = require_has_flag(); - var { env: env2 } = process; - var forceColor; - if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) { - forceColor = 0; - } else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) { - forceColor = 1; - } - if ("FORCE_COLOR" in env2) { - if (env2.FORCE_COLOR === "true") { - forceColor = 1; - } else if (env2.FORCE_COLOR === "false") { - forceColor = 0; - } else { - forceColor = env2.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env2.FORCE_COLOR, 10), 3); - } - } - function translateLevel(level) { - if (level === 0) { - return false; } - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; - } - function supportsColor(haveStream, streamIsTTY) { - if (forceColor === 0) { - return 0; + conditionsCheck(weight) { + var capacity; + capacity = this.computeCapacity(); + return capacity == null || weight <= capacity; } - if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) { - return 3; + __incrementReservoir__(incr) { + var _this8 = this; + return _asyncToGenerator2(function* () { + var reservoir; + yield _this8.yieldLoop(); + reservoir = _this8.storeOptions.reservoir += incr; + _this8.instance._drainAll(_this8.computeCapacity()); + return reservoir; + })(); } - if (hasFlag("color=256")) { - return 2; + __currentReservoir__() { + var _this9 = this; + return _asyncToGenerator2(function* () { + yield _this9.yieldLoop(); + return _this9.storeOptions.reservoir; + })(); } - if (haveStream && !streamIsTTY && forceColor === void 0) { - return 0; + isBlocked(now) { + return this._unblockTime >= now; } - const min = forceColor || 0; - if (env2.TERM === "dumb") { - return min; + check(weight, now) { + return this.conditionsCheck(weight) && this._nextRequest - now <= 0; } - if (process.platform === "win32") { - const osRelease = os.release().split("."); - if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { - return Number(osRelease[2]) >= 14931 ? 3 : 2; - } - return 1; + __check__(weight) { + var _this10 = this; + return _asyncToGenerator2(function* () { + var now; + yield _this10.yieldLoop(); + now = Date.now(); + return _this10.check(weight, now); + })(); } - if ("CI" in env2) { - if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign2) => sign2 in env2) || env2.CI_NAME === "codeship") { - return 1; - } - return min; + __register__(index, weight, expiration) { + var _this11 = this; + return _asyncToGenerator2(function* () { + var now, wait; + yield _this11.yieldLoop(); + now = Date.now(); + if (_this11.conditionsCheck(weight)) { + _this11._running += weight; + if (_this11.storeOptions.reservoir != null) { + _this11.storeOptions.reservoir -= weight; + } + wait = Math.max(_this11._nextRequest - now, 0); + _this11._nextRequest = now + wait + _this11.storeOptions.minTime; + return { + success: true, + wait, + reservoir: _this11.storeOptions.reservoir + }; + } else { + return { + success: false + }; + } + })(); } - if ("TEAMCITY_VERSION" in env2) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env2.TEAMCITY_VERSION) ? 1 : 0; + strategyIsBlock() { + return this.storeOptions.strategy === 3; } - if (env2.COLORTERM === "truecolor") { - return 3; + __submit__(queueLength, weight) { + var _this12 = this; + return _asyncToGenerator2(function* () { + var blocked, now, reachedHWM; + yield _this12.yieldLoop(); + if (_this12.storeOptions.maxConcurrent != null && weight > _this12.storeOptions.maxConcurrent) { + throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${_this12.storeOptions.maxConcurrent}`); + } + now = Date.now(); + reachedHWM = _this12.storeOptions.highWater != null && queueLength === _this12.storeOptions.highWater && !_this12.check(weight, now); + blocked = _this12.strategyIsBlock() && (reachedHWM || _this12.isBlocked(now)); + if (blocked) { + _this12._unblockTime = now + _this12.computePenalty(); + _this12._nextRequest = _this12._unblockTime + _this12.storeOptions.minTime; + _this12.instance._dropAllQueued(); + } + return { + reachedHWM, + blocked, + strategy: _this12.storeOptions.strategy + }; + })(); } - if ("TERM_PROGRAM" in env2) { - const version3 = parseInt((env2.TERM_PROGRAM_VERSION || "").split(".")[0], 10); - switch (env2.TERM_PROGRAM) { - case "iTerm.app": - return version3 >= 3 ? 3 : 2; - case "Apple_Terminal": - return 2; - } - } - if (/-256(color)?$/i.test(env2.TERM)) { - return 2; - } - if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env2.TERM)) { - return 1; - } - if ("COLORTERM" in env2) { - return 1; + __free__(index, weight) { + var _this13 = this; + return _asyncToGenerator2(function* () { + yield _this13.yieldLoop(); + _this13._running -= weight; + _this13._done += weight; + _this13.instance._drainAll(_this13.computeCapacity()); + return { + running: _this13._running + }; + })(); } - return min; - } - function getSupportLevel(stream) { - const level = supportsColor(stream, stream && stream.isTTY); - return translateLevel(level); - } + }; + module14.exports = LocalDatastore; + } +}); +var require_lua = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/lua.json"(exports2, module14) { module14.exports = { - supportsColor: getSupportLevel, - stdout: translateLevel(supportsColor(true, tty.isatty(1))), - stderr: translateLevel(supportsColor(true, tty.isatty(2))) + "blacklist_client.lua": "local blacklist = ARGV[num_static_argv + 1]\n\nif redis.call('zscore', client_last_seen_key, blacklist) then\n redis.call('zadd', client_last_seen_key, 0, blacklist)\nend\n\n\nreturn {}\n", + "check.lua": "local weight = tonumber(ARGV[num_static_argv + 1])\n\nlocal capacity = process_tick(now, false)['capacity']\nlocal nextRequest = tonumber(redis.call('hget', settings_key, 'nextRequest'))\n\nreturn conditions_check(capacity, weight) and nextRequest - now <= 0\n", + "conditions_check.lua": "local conditions_check = function (capacity, weight)\n return capacity == nil or weight <= capacity\nend\n", + "current_reservoir.lua": "return process_tick(now, false)['reservoir']\n", + "done.lua": "process_tick(now, false)\n\nreturn tonumber(redis.call('hget', settings_key, 'done'))\n", + "free.lua": "local index = ARGV[num_static_argv + 1]\n\nredis.call('zadd', job_expirations_key, 0, index)\n\nreturn process_tick(now, false)['running']\n", + "get_time.lua": "redis.replicate_commands()\n\nlocal get_time = function ()\n local time = redis.call('time')\n\n return tonumber(time[1]..string.sub(time[2], 1, 3))\nend\n", + "group_check.lua": "return not (redis.call('exists', settings_key) == 1)\n", + "heartbeat.lua": "process_tick(now, true)\n", + "increment_reservoir.lua": "local incr = tonumber(ARGV[num_static_argv + 1])\n\nredis.call('hincrby', settings_key, 'reservoir', incr)\n\nlocal reservoir = process_tick(now, true)['reservoir']\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn reservoir\n", + "init.lua": `local clear = tonumber(ARGV[num_static_argv + 1]) +local limiter_version = ARGV[num_static_argv + 2] +local num_local_argv = num_static_argv + 2 + +if clear == 1 then + redis.call('del', unpack(KEYS)) +end + +if redis.call('exists', settings_key) == 0 then + -- Create + local args = {'hmset', settings_key} + + for i = num_local_argv + 1, #ARGV do + table.insert(args, ARGV[i]) + end + + redis.call(unpack(args)) + redis.call('hmset', settings_key, + 'nextRequest', now, + 'lastReservoirRefresh', now, + 'lastReservoirIncrease', now, + 'running', 0, + 'done', 0, + 'unblockTime', 0, + 'capacityPriorityCounter', 0 + ) + +else + -- Apply migrations + local settings = redis.call('hmget', settings_key, + 'id', + 'version' + ) + local id = settings[1] + local current_version = settings[2] + + if current_version ~= limiter_version then + local version_digits = {} + for k, v in string.gmatch(current_version, "([^.]+)") do + table.insert(version_digits, tonumber(k)) + end + + -- 2.10.0 + if version_digits[2] < 10 then + redis.call('hsetnx', settings_key, 'reservoirRefreshInterval', '') + redis.call('hsetnx', settings_key, 'reservoirRefreshAmount', '') + redis.call('hsetnx', settings_key, 'lastReservoirRefresh', '') + redis.call('hsetnx', settings_key, 'done', 0) + redis.call('hset', settings_key, 'version', '2.10.0') + end + + -- 2.11.1 + if version_digits[2] < 11 or (version_digits[2] == 11 and version_digits[3] < 1) then + if redis.call('hstrlen', settings_key, 'lastReservoirRefresh') == 0 then + redis.call('hmset', settings_key, + 'lastReservoirRefresh', now, + 'version', '2.11.1' + ) + end + end + + -- 2.14.0 + if version_digits[2] < 14 then + local old_running_key = 'b_'..id..'_running' + local old_executing_key = 'b_'..id..'_executing' + + if redis.call('exists', old_running_key) == 1 then + redis.call('rename', old_running_key, job_weights_key) + end + if redis.call('exists', old_executing_key) == 1 then + redis.call('rename', old_executing_key, job_expirations_key) + end + redis.call('hset', settings_key, 'version', '2.14.0') + end + + -- 2.15.2 + if version_digits[2] < 15 or (version_digits[2] == 15 and version_digits[3] < 2) then + redis.call('hsetnx', settings_key, 'capacityPriorityCounter', 0) + redis.call('hset', settings_key, 'version', '2.15.2') + end + + -- 2.17.0 + if version_digits[2] < 17 then + redis.call('hsetnx', settings_key, 'clientTimeout', 10000) + redis.call('hset', settings_key, 'version', '2.17.0') + end + + -- 2.18.0 + if version_digits[2] < 18 then + redis.call('hsetnx', settings_key, 'reservoirIncreaseInterval', '') + redis.call('hsetnx', settings_key, 'reservoirIncreaseAmount', '') + redis.call('hsetnx', settings_key, 'reservoirIncreaseMaximum', '') + redis.call('hsetnx', settings_key, 'lastReservoirIncrease', now) + redis.call('hset', settings_key, 'version', '2.18.0') + end + + end + + process_tick(now, false) +end + +local groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout')) +refresh_expiration(0, 0, groupTimeout) + +return {} +`, + "process_tick.lua": "local process_tick = function (now, always_publish)\n\n local compute_capacity = function (maxConcurrent, running, reservoir)\n if maxConcurrent ~= nil and reservoir ~= nil then\n return math.min((maxConcurrent - running), reservoir)\n elseif maxConcurrent ~= nil then\n return maxConcurrent - running\n elseif reservoir ~= nil then\n return reservoir\n else\n return nil\n end\n end\n\n local settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'running',\n 'reservoir',\n 'reservoirRefreshInterval',\n 'reservoirRefreshAmount',\n 'lastReservoirRefresh',\n 'reservoirIncreaseInterval',\n 'reservoirIncreaseAmount',\n 'reservoirIncreaseMaximum',\n 'lastReservoirIncrease',\n 'capacityPriorityCounter',\n 'clientTimeout'\n )\n local id = settings[1]\n local maxConcurrent = tonumber(settings[2])\n local running = tonumber(settings[3])\n local reservoir = tonumber(settings[4])\n local reservoirRefreshInterval = tonumber(settings[5])\n local reservoirRefreshAmount = tonumber(settings[6])\n local lastReservoirRefresh = tonumber(settings[7])\n local reservoirIncreaseInterval = tonumber(settings[8])\n local reservoirIncreaseAmount = tonumber(settings[9])\n local reservoirIncreaseMaximum = tonumber(settings[10])\n local lastReservoirIncrease = tonumber(settings[11])\n local capacityPriorityCounter = tonumber(settings[12])\n local clientTimeout = tonumber(settings[13])\n\n local initial_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n --\n -- Process 'running' changes\n --\n local expired = redis.call('zrangebyscore', job_expirations_key, '-inf', '('..now)\n\n if #expired > 0 then\n redis.call('zremrangebyscore', job_expirations_key, '-inf', '('..now)\n\n local flush_batch = function (batch, acc)\n local weights = redis.call('hmget', job_weights_key, unpack(batch))\n redis.call('hdel', job_weights_key, unpack(batch))\n local clients = redis.call('hmget', job_clients_key, unpack(batch))\n redis.call('hdel', job_clients_key, unpack(batch))\n\n -- Calculate sum of removed weights\n for i = 1, #weights do\n acc['total'] = acc['total'] + (tonumber(weights[i]) or 0)\n end\n\n -- Calculate sum of removed weights by client\n local client_weights = {}\n for i = 1, #clients do\n local removed = tonumber(weights[i]) or 0\n if removed > 0 then\n acc['client_weights'][clients[i]] = (acc['client_weights'][clients[i]] or 0) + removed\n end\n end\n end\n\n local acc = {\n ['total'] = 0,\n ['client_weights'] = {}\n }\n local batch_size = 1000\n\n -- Compute changes to Zsets and apply changes to Hashes\n for i = 1, #expired, batch_size do\n local batch = {}\n for j = i, math.min(i + batch_size - 1, #expired) do\n table.insert(batch, expired[j])\n end\n\n flush_batch(batch, acc)\n end\n\n -- Apply changes to Zsets\n if acc['total'] > 0 then\n redis.call('hincrby', settings_key, 'done', acc['total'])\n running = tonumber(redis.call('hincrby', settings_key, 'running', -acc['total']))\n end\n\n for client, weight in pairs(acc['client_weights']) do\n redis.call('zincrby', client_running_key, -weight, client)\n end\n end\n\n --\n -- Process 'reservoir' changes\n --\n local reservoirRefreshActive = reservoirRefreshInterval ~= nil and reservoirRefreshAmount ~= nil\n if reservoirRefreshActive and now >= lastReservoirRefresh + reservoirRefreshInterval then\n reservoir = reservoirRefreshAmount\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirRefresh', now\n )\n end\n\n local reservoirIncreaseActive = reservoirIncreaseInterval ~= nil and reservoirIncreaseAmount ~= nil\n if reservoirIncreaseActive and now >= lastReservoirIncrease + reservoirIncreaseInterval then\n local num_intervals = math.floor((now - lastReservoirIncrease) / reservoirIncreaseInterval)\n local incr = reservoirIncreaseAmount * num_intervals\n if reservoirIncreaseMaximum ~= nil then\n incr = math.min(incr, reservoirIncreaseMaximum - (reservoir or 0))\n end\n if incr > 0 then\n reservoir = (reservoir or 0) + incr\n end\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirIncrease', lastReservoirIncrease + (num_intervals * reservoirIncreaseInterval)\n )\n end\n\n --\n -- Clear unresponsive clients\n --\n local unresponsive = redis.call('zrangebyscore', client_last_seen_key, '-inf', (now - clientTimeout))\n local unresponsive_lookup = {}\n local terminated_clients = {}\n for i = 1, #unresponsive do\n unresponsive_lookup[unresponsive[i]] = true\n if tonumber(redis.call('zscore', client_running_key, unresponsive[i])) == 0 then\n table.insert(terminated_clients, unresponsive[i])\n end\n end\n if #terminated_clients > 0 then\n redis.call('zrem', client_running_key, unpack(terminated_clients))\n redis.call('hdel', client_num_queued_key, unpack(terminated_clients))\n redis.call('zrem', client_last_registered_key, unpack(terminated_clients))\n redis.call('zrem', client_last_seen_key, unpack(terminated_clients))\n end\n\n --\n -- Broadcast capacity changes\n --\n local final_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n if always_publish or (initial_capacity ~= nil and final_capacity == nil) then\n -- always_publish or was not unlimited, now unlimited\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n\n elseif initial_capacity ~= nil and final_capacity ~= nil and final_capacity > initial_capacity then\n -- capacity was increased\n -- send the capacity message to the limiter having the lowest number of running jobs\n -- the tiebreaker is the limiter having not registered a job in the longest time\n\n local lowest_concurrency_value = nil\n local lowest_concurrency_clients = {}\n local lowest_concurrency_last_registered = {}\n local client_concurrencies = redis.call('zrange', client_running_key, 0, -1, 'withscores')\n\n for i = 1, #client_concurrencies, 2 do\n local client = client_concurrencies[i]\n local concurrency = tonumber(client_concurrencies[i+1])\n\n if (\n lowest_concurrency_value == nil or lowest_concurrency_value == concurrency\n ) and (\n not unresponsive_lookup[client]\n ) and (\n tonumber(redis.call('hget', client_num_queued_key, client)) > 0\n ) then\n lowest_concurrency_value = concurrency\n table.insert(lowest_concurrency_clients, client)\n local last_registered = tonumber(redis.call('zscore', client_last_registered_key, client))\n table.insert(lowest_concurrency_last_registered, last_registered)\n end\n end\n\n if #lowest_concurrency_clients > 0 then\n local position = 1\n local earliest = lowest_concurrency_last_registered[1]\n\n for i,v in ipairs(lowest_concurrency_last_registered) do\n if v < earliest then\n position = i\n earliest = v\n end\n end\n\n local next_client = lowest_concurrency_clients[position]\n redis.call('publish', 'b_'..id,\n 'capacity-priority:'..(final_capacity or '')..\n ':'..next_client..\n ':'..capacityPriorityCounter\n )\n redis.call('hincrby', settings_key, 'capacityPriorityCounter', '1')\n else\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n end\n end\n\n return {\n ['capacity'] = final_capacity,\n ['running'] = running,\n ['reservoir'] = reservoir\n }\nend\n", + "queued.lua": "local clientTimeout = tonumber(redis.call('hget', settings_key, 'clientTimeout'))\nlocal valid_clients = redis.call('zrangebyscore', client_last_seen_key, (now - clientTimeout), 'inf')\nlocal client_queued = redis.call('hmget', client_num_queued_key, unpack(valid_clients))\n\nlocal sum = 0\nfor i = 1, #client_queued do\n sum = sum + tonumber(client_queued[i])\nend\n\nreturn sum\n", + "refresh_expiration.lua": "local refresh_expiration = function (now, nextRequest, groupTimeout)\n\n if groupTimeout ~= nil then\n local ttl = (nextRequest + groupTimeout) - now\n\n for i = 1, #KEYS do\n redis.call('pexpire', KEYS[i], ttl)\n end\n end\n\nend\n", + "refs.lua": "local settings_key = KEYS[1]\nlocal job_weights_key = KEYS[2]\nlocal job_expirations_key = KEYS[3]\nlocal job_clients_key = KEYS[4]\nlocal client_running_key = KEYS[5]\nlocal client_num_queued_key = KEYS[6]\nlocal client_last_registered_key = KEYS[7]\nlocal client_last_seen_key = KEYS[8]\n\nlocal now = tonumber(ARGV[1])\nlocal client = ARGV[2]\n\nlocal num_static_argv = 2\n", + "register.lua": "local index = ARGV[num_static_argv + 1]\nlocal weight = tonumber(ARGV[num_static_argv + 2])\nlocal expiration = tonumber(ARGV[num_static_argv + 3])\n\nlocal state = process_tick(now, false)\nlocal capacity = state['capacity']\nlocal reservoir = state['reservoir']\n\nlocal settings = redis.call('hmget', settings_key,\n 'nextRequest',\n 'minTime',\n 'groupTimeout'\n)\nlocal nextRequest = tonumber(settings[1])\nlocal minTime = tonumber(settings[2])\nlocal groupTimeout = tonumber(settings[3])\n\nif conditions_check(capacity, weight) then\n\n redis.call('hincrby', settings_key, 'running', weight)\n redis.call('hset', job_weights_key, index, weight)\n if expiration ~= nil then\n redis.call('zadd', job_expirations_key, now + expiration, index)\n end\n redis.call('hset', job_clients_key, index, client)\n redis.call('zincrby', client_running_key, weight, client)\n redis.call('hincrby', client_num_queued_key, client, -1)\n redis.call('zadd', client_last_registered_key, now, client)\n\n local wait = math.max(nextRequest - now, 0)\n local newNextRequest = now + wait + minTime\n\n if reservoir == nil then\n redis.call('hset', settings_key,\n 'nextRequest', newNextRequest\n )\n else\n reservoir = reservoir - weight\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'nextRequest', newNextRequest\n )\n end\n\n refresh_expiration(now, newNextRequest, groupTimeout)\n\n return {true, wait, reservoir}\n\nelse\n return {false}\nend\n", + "register_client.lua": "local queued = tonumber(ARGV[num_static_argv + 1])\n\n-- Could have been re-registered concurrently\nif not redis.call('zscore', client_last_seen_key, client) then\n redis.call('zadd', client_running_key, 0, client)\n redis.call('hset', client_num_queued_key, client, queued)\n redis.call('zadd', client_last_registered_key, 0, client)\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n\nreturn {}\n", + "running.lua": "return process_tick(now, false)['running']\n", + "submit.lua": "local queueLength = tonumber(ARGV[num_static_argv + 1])\nlocal weight = tonumber(ARGV[num_static_argv + 2])\n\nlocal capacity = process_tick(now, false)['capacity']\n\nlocal settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'highWater',\n 'nextRequest',\n 'strategy',\n 'unblockTime',\n 'penalty',\n 'minTime',\n 'groupTimeout'\n)\nlocal id = settings[1]\nlocal maxConcurrent = tonumber(settings[2])\nlocal highWater = tonumber(settings[3])\nlocal nextRequest = tonumber(settings[4])\nlocal strategy = tonumber(settings[5])\nlocal unblockTime = tonumber(settings[6])\nlocal penalty = tonumber(settings[7])\nlocal minTime = tonumber(settings[8])\nlocal groupTimeout = tonumber(settings[9])\n\nif maxConcurrent ~= nil and weight > maxConcurrent then\n return redis.error_reply('OVERWEIGHT:'..weight..':'..maxConcurrent)\nend\n\nlocal reachedHWM = (highWater ~= nil and queueLength == highWater\n and not (\n conditions_check(capacity, weight)\n and nextRequest - now <= 0\n )\n)\n\nlocal blocked = strategy == 3 and (reachedHWM or unblockTime >= now)\n\nif blocked then\n local computedPenalty = penalty\n if computedPenalty == nil then\n if minTime == 0 then\n computedPenalty = 5000\n else\n computedPenalty = 15 * minTime\n end\n end\n\n local newNextRequest = now + computedPenalty + minTime\n\n redis.call('hmset', settings_key,\n 'unblockTime', now + computedPenalty,\n 'nextRequest', newNextRequest\n )\n\n local clients_queued_reset = redis.call('hkeys', client_num_queued_key)\n local queued_reset = {}\n for i = 1, #clients_queued_reset do\n table.insert(queued_reset, clients_queued_reset[i])\n table.insert(queued_reset, 0)\n end\n redis.call('hmset', client_num_queued_key, unpack(queued_reset))\n\n redis.call('publish', 'b_'..id, 'blocked:')\n\n refresh_expiration(now, newNextRequest, groupTimeout)\nend\n\nif not blocked and not reachedHWM then\n redis.call('hincrby', client_num_queued_key, client, 1)\nend\n\nreturn {reachedHWM, blocked, strategy}\n", + "update_settings.lua": "local args = {'hmset', settings_key}\n\nfor i = num_static_argv + 1, #ARGV do\n table.insert(args, ARGV[i])\nend\n\nredis.call(unpack(args))\n\nprocess_tick(now, true)\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn {}\n", + "validate_client.lua": "if not redis.call('zscore', client_last_seen_key, client) then\n return redis.error_reply('UNKNOWN_CLIENT')\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n", + "validate_keys.lua": "if not (redis.call('exists', settings_key) == 1) then\n return redis.error_reply('SETTINGS_KEY_NOT_FOUND')\nend\n" }; } }); -var require_util2 = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/util.js"(exports2, module14) { +var require_Scripts = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Scripts.js"(exports2) { "use strict"; - var stringReplaceAll = (string3, substring, replacer) => { - let index = string3.indexOf(substring); - if (index === -1) { - return string3; + var headers; + var lua; + var templates; + lua = require_lua(); + headers = { + refs: lua["refs.lua"], + validate_keys: lua["validate_keys.lua"], + validate_client: lua["validate_client.lua"], + refresh_expiration: lua["refresh_expiration.lua"], + process_tick: lua["process_tick.lua"], + conditions_check: lua["conditions_check.lua"], + get_time: lua["get_time.lua"] + }; + exports2.allKeys = function(id) { + return [ + /* + HASH + */ + `b_${id}_settings`, + /* + HASH + job index -> weight + */ + `b_${id}_job_weights`, + /* + ZSET + job index -> expiration + */ + `b_${id}_job_expirations`, + /* + HASH + job index -> client + */ + `b_${id}_job_clients`, + /* + ZSET + client -> sum running + */ + `b_${id}_client_running`, + /* + HASH + client -> num queued + */ + `b_${id}_client_num_queued`, + /* + ZSET + client -> last job registered + */ + `b_${id}_client_last_registered`, + /* + ZSET + client -> last seen + */ + `b_${id}_client_last_seen` + ]; + }; + templates = { + init: { + keys: exports2.allKeys, + headers: ["process_tick"], + refresh_expiration: true, + code: lua["init.lua"] + }, + group_check: { + keys: exports2.allKeys, + headers: [], + refresh_expiration: false, + code: lua["group_check.lua"] + }, + register_client: { + keys: exports2.allKeys, + headers: ["validate_keys"], + refresh_expiration: false, + code: lua["register_client.lua"] + }, + blacklist_client: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client"], + refresh_expiration: false, + code: lua["blacklist_client.lua"] + }, + heartbeat: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["heartbeat.lua"] + }, + update_settings: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["update_settings.lua"] + }, + running: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["running.lua"] + }, + queued: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client"], + refresh_expiration: false, + code: lua["queued.lua"] + }, + done: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["done.lua"] + }, + check: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: false, + code: lua["check.lua"] + }, + submit: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: true, + code: lua["submit.lua"] + }, + register: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], + refresh_expiration: true, + code: lua["register.lua"] + }, + free: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["free.lua"] + }, + current_reservoir: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: false, + code: lua["current_reservoir.lua"] + }, + increment_reservoir: { + keys: exports2.allKeys, + headers: ["validate_keys", "validate_client", "process_tick"], + refresh_expiration: true, + code: lua["increment_reservoir.lua"] } - const substringLength = substring.length; - let endIndex = 0; - let returnValue = ""; - do { - returnValue += string3.substr(endIndex, index - endIndex) + substring + replacer; - endIndex = index + substringLength; - index = string3.indexOf(substring, endIndex); - } while (index !== -1); - returnValue += string3.substr(endIndex); - return returnValue; }; - var stringEncaseCRLFWithFirstIndex = (string3, prefix, postfix, index) => { - let endIndex = 0; - let returnValue = ""; - do { - const gotCR = string3[index - 1] === "\r"; - returnValue += string3.substr(endIndex, (gotCR ? index - 1 : index) - endIndex) + prefix + (gotCR ? "\r\n" : "\n") + postfix; - endIndex = index + 1; - index = string3.indexOf("\n", endIndex); - } while (index !== -1); - returnValue += string3.substr(endIndex); - return returnValue; + exports2.names = Object.keys(templates); + exports2.keys = function(name, id) { + return templates[name].keys(id); }; - module14.exports = { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex + exports2.payload = function(name) { + var template; + template = templates[name]; + return Array.prototype.concat(headers.refs, template.headers.map(function(h2) { + return headers[h2]; + }), template.refresh_expiration ? headers.refresh_expiration : "", template.code).join("\n"); }; } }); -var require_templates = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/templates.js"(exports2, module14) { +var require_RedisConnection = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisConnection.js"(exports, module) { "use strict"; - var TEMPLATE_REGEX = /(?:\\(u(?:[a-f\d]{4}|\{[a-f\d]{1,6}\})|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi; - var STYLE_REGEX = /(?:^|\.)(\w+)(?:\(([^)]*)\))?/g; - var STRING_REGEX = /^(['"])((?:\\.|(?!\1)[^\\])*)\1$/; - var ESCAPE_REGEX2 = /\\(u(?:[a-f\d]{4}|{[a-f\d]{1,6}})|x[a-f\d]{2}|.)|([^\\])/gi; - var ESCAPES = /* @__PURE__ */ new Map([ - ["n", "\n"], - ["r", "\r"], - ["t", " "], - ["b", "\b"], - ["f", "\f"], - ["v", "\v"], - ["0", "\0"], - ["\\", "\\"], - ["e", "\x1B"], - ["a", "\x07"] - ]); - function unescape(c) { - const u2 = c[0] === "u"; - const bracket = c[1] === "{"; - if (u2 && !bracket && c.length === 5 || c[0] === "x" && c.length === 3) { - return String.fromCharCode(parseInt(c.slice(1), 16)); + function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - if (u2 && bracket) { - return String.fromCodePoint(parseInt(c.slice(2, -1), 16)); + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } - return ESCAPES.get(c) || c; } - function parseArguments(name, arguments_) { - const results = []; - const chunks = arguments_.trim().split(/\s*,\s*/g); - let matches; - for (const chunk of chunks) { - const number3 = Number(chunk); - if (!Number.isNaN(number3)) { - results.push(number3); - } else if (matches = chunk.match(STRING_REGEX)) { - results.push(matches[2].replace(ESCAPE_REGEX2, (m3, escape, character) => escape ? unescape(escape) : character)); - } else { - throw new Error(`Invalid Chalk template style argument: ${chunk} (in style '${name}')`); - } - } - return results; + function _asyncToGenerator(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; } - function parseStyle(style) { - STYLE_REGEX.lastIndex = 0; - const results = []; - let matches; - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); + var Events; + var RedisConnection; + var Scripts; + var parser; + parser = require_parser2(); + Events = require_Events(); + Scripts = require_Scripts(); + RedisConnection = function() { + class RedisConnection { + constructor(options = {}) { + parser.load(options, this.defaults, this); + if (this.Redis == null) { + this.Redis = eval("require")("redis"); + } + if (this.Events == null) { + this.Events = new Events(this); + } + this.terminated = false; + if (this.client == null) { + this.client = this.Redis.createClient(this.clientOptions); + } + this.subscriber = this.client.duplicate(); + this.limiters = {}; + this.shas = {}; + this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { + return this._loadScripts(); + }).then(() => { + return { + client: this.client, + subscriber: this.subscriber + }; + }); } - } - return results; - } - function buildStyle(chalk5, styles) { - const enabled2 = {}; - for (const layer of styles) { - for (const style of layer.styles) { - enabled2[style[0]] = layer.inverse ? null : style.slice(1); + _setup(client, sub) { + client.setMaxListeners(0); + return new this.Promise((resolve82, reject) => { + client.on("error", (e2) => { + return this.Events.trigger("error", e2); + }); + if (sub) { + client.on("message", (channel, message) => { + var ref; + return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; + }); + } + if (client.ready) { + return resolve82(); + } else { + return client.once("ready", resolve82); + } + }); } - } - let current = chalk5; - for (const [styleName, styles2] of Object.entries(enabled2)) { - if (!Array.isArray(styles2)) { - continue; + _loadScript(name) { + return new this.Promise((resolve82, reject) => { + var payload; + payload = Scripts.payload(name); + return this.client.multi([["script", "load", payload]]).exec((err, replies) => { + if (err != null) { + return reject(err); + } + this.shas[name] = replies[0]; + return resolve82(replies[0]); + }); + }); } - if (!(styleName in current)) { - throw new Error(`Unknown Chalk style: ${styleName}`); + _loadScripts() { + return this.Promise.all(Scripts.names.map((k) => { + return this._loadScript(k); + })); } - current = styles2.length > 0 ? current[styleName](...styles2) : current[styleName]; - } - return current; - } - module14.exports = (chalk5, temporary) => { - const styles = []; - const chunks = []; - let chunk = []; - temporary.replace(TEMPLATE_REGEX, (m3, escapeCharacter, inverse, style, close, character) => { - if (escapeCharacter) { - chunk.push(unescape(escapeCharacter)); - } else if (style) { - const string3 = chunk.join(""); - chunk = []; - chunks.push(styles.length === 0 ? string3 : buildStyle(chalk5, styles)(string3)); - styles.push({ inverse, styles: parseStyle(style) }); - } else if (close) { - if (styles.length === 0) { - throw new Error("Found extraneous } in Chalk template literal"); + __runCommand__(cmd) { + var _this = this; + return _asyncToGenerator(function* () { + yield _this.ready; + return new _this.Promise((resolve82, reject) => { + return _this.client.multi([cmd]).exec_atomic(function(err, replies) { + if (err != null) { + return reject(err); + } else { + return resolve82(replies[0]); + } + }); + }); + })(); + } + __addLimiter__(instance) { + return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { + return new this.Promise((resolve82, reject) => { + var handler; + handler = (chan) => { + if (chan === channel) { + this.subscriber.removeListener("subscribe", handler); + this.limiters[channel] = instance; + return resolve82(); + } + }; + this.subscriber.on("subscribe", handler); + return this.subscriber.subscribe(channel); + }); + })); + } + __removeLimiter__(instance) { + var _this2 = this; + return this.Promise.all([instance.channel(), instance.channel_client()].map( + /* @__PURE__ */ function() { + var _ref = _asyncToGenerator(function* (channel) { + if (!_this2.terminated) { + yield new _this2.Promise((resolve82, reject) => { + return _this2.subscriber.unsubscribe(channel, function(err, chan) { + if (err != null) { + return reject(err); + } + if (chan === channel) { + return resolve82(); + } + }); + }); + } + return delete _this2.limiters[channel]; + }); + return function(_x) { + return _ref.apply(this, arguments); + }; + }() + )); + } + __scriptArgs__(name, id, args, cb) { + var keys; + keys = Scripts.keys(name, id); + return [this.shas[name], keys.length].concat(keys, args, cb); + } + __scriptFn__(name) { + return this.client.evalsha.bind(this.client); + } + disconnect(flush = true) { + var i2, k, len, ref; + ref = Object.keys(this.limiters); + for (i2 = 0, len = ref.length; i2 < len; i2++) { + k = ref[i2]; + clearInterval(this.limiters[k]._store.heartbeat); } - chunks.push(buildStyle(chalk5, styles)(chunk.join(""))); - chunk = []; - styles.pop(); - } else { - chunk.push(character); + this.limiters = {}; + this.terminated = true; + this.client.end(flush); + this.subscriber.end(flush); + return this.Promise.resolve(); } - }); - chunks.push(chunk.join("")); - if (styles.length > 0) { - const errMessage = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? "" : "s"} (\`}\`)`; - throw new Error(errMessage); } - return chunks.join(""); - }; + ; + RedisConnection.prototype.datastore = "redis"; + RedisConnection.prototype.defaults = { + Redis: null, + clientOptions: {}, + client: null, + Promise, + Events: null + }; + return RedisConnection; + }.call(void 0); + module.exports = RedisConnection; } }); -var require_source = __commonJS({ - "node_modules/.deno/chalk@4.1.0/node_modules/chalk/source/index.js"(exports2, module14) { +var require_IORedisConnection = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/IORedisConnection.js"(exports, module) { "use strict"; - var ansiStyles = require_ansi_styles(); - var { stdout: stdoutColor, stderr: stderrColor } = require_supports_color(); - var { - stringReplaceAll, - stringEncaseCRLFWithFirstIndex - } = require_util2(); - var { isArray } = Array; - var levelMapping = [ - "ansi", - "ansi", - "ansi256", - "ansi16m" - ]; - var styles = /* @__PURE__ */ Object.create(null); - var applyOptions = (object2, options2 = {}) => { - if (options2.level && !(Number.isInteger(options2.level) && options2.level >= 0 && options2.level <= 3)) { - throw new Error("The `level` option should be an integer from 0 to 3"); - } - const colorLevel = stdoutColor ? stdoutColor.level : 0; - object2.level = options2.level === void 0 ? colorLevel : options2.level; - }; - var ChalkClass = class { - constructor(options2) { - return chalkFactory(options2); - } - }; - var chalkFactory = (options2) => { - const chalk6 = {}; - applyOptions(chalk6, options2); - chalk6.template = (...arguments_) => chalkTag(chalk6.template, ...arguments_); - Object.setPrototypeOf(chalk6, Chalk.prototype); - Object.setPrototypeOf(chalk6.template, chalk6); - chalk6.template.constructor = () => { - throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead."); - }; - chalk6.template.Instance = ChalkClass; - return chalk6.template; - }; - function Chalk(options2) { - return chalkFactory(options2); + function _slicedToArray(arr, i2) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i2) || _nonIterableRest(); } - for (const [styleName, style] of Object.entries(ansiStyles)) { - styles[styleName] = { - get() { - const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty); - Object.defineProperty(this, styleName, { value: builder }); - return builder; - } - }; + function _nonIterableRest() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - styles.visible = { - get() { - const builder = createBuilder(this, this._styler, true); - Object.defineProperty(this, "visible", { value: builder }); - return builder; - } - }; - var usedModels = ["rgb", "hex", "keyword", "hsl", "hsv", "hwb", "ansi", "ansi256"]; - for (const model of usedModels) { - styles[model] = { - get() { - const { level } = this; - return function(...arguments_) { - const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; + function _iterableToArrayLimit(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; } - }; - } - for (const model of usedModels) { - const bgModel = "bg" + model[0].toUpperCase() + model.slice(1); - styles[bgModel] = { - get() { - const { level } = this; - return function(...arguments_) { - const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler); - return createBuilder(this, styler, this._isEmpty); - }; + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } - }; + } + return _arr; } - var proto3 = Object.defineProperties(() => { - }, { - ...styles, - level: { - enumerable: true, - get() { - return this._generator.level; - }, - set(level) { - this._generator.level = level; - } + function _arrayWithHoles(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - }); - var createStyler = (open2, close, parent) => { - let openAll; - let closeAll; - if (parent === void 0) { - openAll = open2; - closeAll = close; + if (info.done) { + resolve82(value); } else { - openAll = parent.openAll + open2; - closeAll = close + parent.closeAll; + Promise.resolve(value).then(_next, _throw); } - return { - open: open2, - close, - openAll, - closeAll, - parent + } + function _asyncToGenerator(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); }; - }; - var createBuilder = (self2, _styler, _isEmpty) => { - const builder = (...arguments_) => { - if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) { - return applyStyle(builder, chalkTag(builder, ...arguments_)); + } + var Events; + var IORedisConnection; + var Scripts; + var parser; + parser = require_parser2(); + Events = require_Events(); + Scripts = require_Scripts(); + IORedisConnection = function() { + class IORedisConnection { + constructor(options = {}) { + parser.load(options, this.defaults, this); + if (this.Redis == null) { + this.Redis = eval("require")("ioredis"); + } + if (this.Events == null) { + this.Events = new Events(this); + } + this.terminated = false; + if (this.clusterNodes != null) { + this.client = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); + this.subscriber = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); + } else if (this.client != null && this.client.duplicate == null) { + this.subscriber = new this.Redis.Cluster(this.client.startupNodes, this.client.options); + } else { + if (this.client == null) { + this.client = new this.Redis(this.clientOptions); + } + this.subscriber = this.client.duplicate(); + } + this.limiters = {}; + this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { + this._loadScripts(); + return { + client: this.client, + subscriber: this.subscriber + }; + }); } - return applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" ")); - }; - Object.setPrototypeOf(builder, proto3); - builder._generator = self2; - builder._styler = _styler; - builder._isEmpty = _isEmpty; - return builder; - }; - var applyStyle = (self2, string3) => { - if (self2.level <= 0 || !string3) { - return self2._isEmpty ? "" : string3; - } - let styler = self2._styler; - if (styler === void 0) { - return string3; - } - const { openAll, closeAll } = styler; - if (string3.indexOf("\x1B") !== -1) { - while (styler !== void 0) { - string3 = stringReplaceAll(string3, styler.close, styler.open); - styler = styler.parent; + _setup(client, sub) { + client.setMaxListeners(0); + return new this.Promise((resolve82, reject) => { + client.on("error", (e2) => { + return this.Events.trigger("error", e2); + }); + if (sub) { + client.on("message", (channel, message) => { + var ref; + return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; + }); + } + if (client.status === "ready") { + return resolve82(); + } else { + return client.once("ready", resolve82); + } + }); + } + _loadScripts() { + return Scripts.names.forEach((name) => { + return this.client.defineCommand(name, { + lua: Scripts.payload(name) + }); + }); + } + __runCommand__(cmd) { + var _this = this; + return _asyncToGenerator(function* () { + var _, deleted; + yield _this.ready; + var _ref = yield _this.client.pipeline([cmd]).exec(); + var _ref2 = _slicedToArray(_ref, 1); + var _ref2$ = _slicedToArray(_ref2[0], 2); + _ = _ref2$[0]; + deleted = _ref2$[1]; + return deleted; + })(); + } + __addLimiter__(instance) { + return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { + return new this.Promise((resolve82, reject) => { + return this.subscriber.subscribe(channel, () => { + this.limiters[channel] = instance; + return resolve82(); + }); + }); + })); + } + __removeLimiter__(instance) { + var _this2 = this; + return [instance.channel(), instance.channel_client()].forEach( + /* @__PURE__ */ function() { + var _ref3 = _asyncToGenerator(function* (channel) { + if (!_this2.terminated) { + yield _this2.subscriber.unsubscribe(channel); + } + return delete _this2.limiters[channel]; + }); + return function(_x) { + return _ref3.apply(this, arguments); + }; + }() + ); + } + __scriptArgs__(name, id, args, cb) { + var keys; + keys = Scripts.keys(name, id); + return [keys.length].concat(keys, args, cb); + } + __scriptFn__(name) { + return this.client[name].bind(this.client); + } + disconnect(flush = true) { + var i2, k, len, ref; + ref = Object.keys(this.limiters); + for (i2 = 0, len = ref.length; i2 < len; i2++) { + k = ref[i2]; + clearInterval(this.limiters[k]._store.heartbeat); + } + this.limiters = {}; + this.terminated = true; + if (flush) { + return this.Promise.all([this.client.quit(), this.subscriber.quit()]); + } else { + this.client.disconnect(); + this.subscriber.disconnect(); + return this.Promise.resolve(); + } } } - const lfIndex = string3.indexOf("\n"); - if (lfIndex !== -1) { - string3 = stringEncaseCRLFWithFirstIndex(string3, closeAll, openAll, lfIndex); - } - return openAll + string3 + closeAll; - }; - var template; - var chalkTag = (chalk6, ...strings) => { - const [firstString] = strings; - if (!isArray(firstString) || !isArray(firstString.raw)) { - return strings.join(" "); - } - const arguments_ = strings.slice(1); - const parts = [firstString.raw[0]]; - for (let i2 = 1; i2 < firstString.length; i2++) { - parts.push( - String(arguments_[i2 - 1]).replace(/[{}\\]/g, "\\$&"), - String(firstString.raw[i2]) - ); - } - if (template === void 0) { - template = require_templates(); - } - return template(chalk6, parts.join("")); - }; - Object.defineProperties(Chalk.prototype, styles); - var chalk5 = Chalk(); - chalk5.supportsColor = stdoutColor; - chalk5.stderr = Chalk({ level: stderrColor ? stderrColor.level : 0 }); - chalk5.stderr.supportsColor = stderrColor; - module14.exports = chalk5; - } -}); -var SERVER_INSTANCE; -var PUBSUB_INSTANCE; -var init_instance_keys = __esm({ - "src/serve/instance-keys.ts"() { - "use strict"; - SERVER_INSTANCE = "@instance/server"; - PUBSUB_INSTANCE = "@instance/pubsub"; + ; + IORedisConnection.prototype.datastore = "ioredis"; + IORedisConnection.prototype.defaults = { + Redis: null, + clientOptions: {}, + clusterNodes: null, + client: null, + Promise, + Events: null + }; + return IORedisConnection; + }.call(void 0); + module.exports = IORedisConnection; } }); -var require_err_helpers = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-helpers.js"(exports2, module14) { +var require_RedisDatastore = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisDatastore.js"(exports2, module14) { "use strict"; - var isErrorLike = (err) => { - return err && typeof err.message === "string"; - }; - var getErrorCause = (err) => { - if (!err) return; - const cause = err.cause; - if (typeof cause === "function") { - const causeResult = err.cause(); - return isErrorLike(causeResult) ? causeResult : void 0; - } else { - return isErrorLike(cause) ? cause : void 0; - } - }; - var _stackWithCauses = (err, seen) => { - if (!isErrorLike(err)) return ""; - const stack = err.stack || ""; - if (seen.has(err)) { - return stack + "\ncauses have become circular..."; - } - const cause = getErrorCause(err); - if (cause) { - seen.add(err); - return stack + "\ncaused by: " + _stackWithCauses(cause, seen); - } else { - return stack; - } - }; - var stackWithCauses = (err) => _stackWithCauses(err, /* @__PURE__ */ new Set()); - var _messageWithCauses = (err, seen, skip) => { - if (!isErrorLike(err)) return ""; - const message = skip ? "" : err.message || ""; - if (seen.has(err)) { - return message + ": ..."; + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + } + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; + } } - const cause = getErrorCause(err); - if (cause) { - seen.add(err); - const skipIfVErrorStyleCause = typeof err.cause === "function"; - return message + (skipIfVErrorStyleCause ? "" : ": ") + _messageWithCauses(cause, seen, skipIfVErrorStyleCause); + return _arr; + } + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; + } + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; + } + if (info.done) { + resolve82(value); } else { - return message; + Promise.resolve(value).then(_next, _throw); } - }; - var messageWithCauses = (err) => _messageWithCauses(err, /* @__PURE__ */ new Set()); - module14.exports = { - isErrorLike, - getErrorCause, - stackWithCauses, - messageWithCauses - }; - } -}); -var require_err_proto = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-proto.js"(exports2, module14) { - "use strict"; - var seen = Symbol("circular-ref-tag"); - var rawSymbol = Symbol("pino-raw-err-ref"); - var pinoErrProto = Object.create({}, { - type: { - enumerable: true, - writable: true, - value: void 0 - }, - message: { - enumerable: true, - writable: true, - value: void 0 - }, - stack: { - enumerable: true, - writable: true, - value: void 0 - }, - aggregateErrors: { - enumerable: true, - writable: true, - value: void 0 - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; + } + var BottleneckError; + var IORedisConnection2; + var RedisConnection2; + var RedisDatastore; + var parser3; + parser3 = require_parser2(); + BottleneckError = require_BottleneckError(); + RedisConnection2 = require_RedisConnection(); + IORedisConnection2 = require_IORedisConnection(); + RedisDatastore = class RedisDatastore { + constructor(instance, storeOptions, storeInstanceOptions) { + this.instance = instance; + this.storeOptions = storeOptions; + this.originalId = this.instance.id; + this.clientId = this.instance._randomIndex(); + parser3.load(storeInstanceOptions, storeInstanceOptions, this); + this.clients = {}; + this.capacityPriorityCounters = {}; + this.sharedConnection = this.connection != null; + if (this.connection == null) { + this.connection = this.instance.datastore === "redis" ? new RedisConnection2({ + Redis: this.Redis, + clientOptions: this.clientOptions, + Promise: this.Promise, + Events: this.instance.Events + }) : this.instance.datastore === "ioredis" ? new IORedisConnection2({ + Redis: this.Redis, + clientOptions: this.clientOptions, + clusterNodes: this.clusterNodes, + Promise: this.Promise, + Events: this.instance.Events + }) : void 0; } + this.instance.connection = this.connection; + this.instance.datastore = this.connection.datastore; + this.ready = this.connection.ready.then((clients) => { + this.clients = clients; + return this.runScript("init", this.prepareInitSettings(this.clearDatastore)); + }).then(() => { + return this.connection.__addLimiter__(this.instance); + }).then(() => { + return this.runScript("register_client", [this.instance.queued()]); + }).then(() => { + var base2; + if (typeof (base2 = this.heartbeat = setInterval(() => { + return this.runScript("heartbeat", []).catch((e2) => { + return this.instance.Events.trigger("error", e2); + }); + }, this.heartbeatInterval)).unref === "function") { + base2.unref(); + } + return this.clients; + }); } - }); - Object.defineProperty(pinoErrProto, rawSymbol, { - writable: true, - value: {} - }); - module14.exports = { - pinoErrProto, - pinoErrorSymbols: { - seen, - rawSymbol + __publish__(message) { + var _this = this; + return _asyncToGenerator2(function* () { + var client; + var _ref = yield _this.ready; + client = _ref.client; + return client.publish(_this.instance.channel(), `message:${message.toString()}`); + })(); } - }; - } -}); -var require_err = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err.js"(exports2, module14) { - "use strict"; - module14.exports = errSerializer; - var { messageWithCauses, stackWithCauses, isErrorLike } = require_err_helpers(); - var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); - var { seen } = pinoErrorSymbols; - var { toString } = Object.prototype; - function errSerializer(err) { - if (!isErrorLike(err)) { - return err; + onMessage(channel, message) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var capacity, counter, data, drained, e2, newCapacity, pos, priorityClient, rawCapacity, type; + try { + pos = message.indexOf(":"); + var _ref2 = [message.slice(0, pos), message.slice(pos + 1)]; + type = _ref2[0]; + data = _ref2[1]; + if (type === "capacity") { + return yield _this2.instance._drainAll(data.length > 0 ? ~~data : void 0); + } else if (type === "capacity-priority") { + var _data$split = data.split(":"); + var _data$split2 = _slicedToArray2(_data$split, 3); + rawCapacity = _data$split2[0]; + priorityClient = _data$split2[1]; + counter = _data$split2[2]; + capacity = rawCapacity.length > 0 ? ~~rawCapacity : void 0; + if (priorityClient === _this2.clientId) { + drained = yield _this2.instance._drainAll(capacity); + newCapacity = capacity != null ? capacity - (drained || 0) : ""; + return yield _this2.clients.client.publish(_this2.instance.channel(), `capacity-priority:${newCapacity}::${counter}`); + } else if (priorityClient === "") { + clearTimeout(_this2.capacityPriorityCounters[counter]); + delete _this2.capacityPriorityCounters[counter]; + return _this2.instance._drainAll(capacity); + } else { + return _this2.capacityPriorityCounters[counter] = setTimeout( + /* @__PURE__ */ _asyncToGenerator2(function* () { + var e3; + try { + delete _this2.capacityPriorityCounters[counter]; + yield _this2.runScript("blacklist_client", [priorityClient]); + return yield _this2.instance._drainAll(capacity); + } catch (error2) { + e3 = error2; + return _this2.instance.Events.trigger("error", e3); + } + }), + 1e3 + ); + } + } else if (type === "message") { + return _this2.instance.Events.trigger("message", data); + } else if (type === "blocked") { + return yield _this2.instance._dropAllQueued(); + } + } catch (error2) { + e2 = error2; + return _this2.instance.Events.trigger("error", e2); + } + })(); } - err[seen] = void 0; - const _err = Object.create(pinoErrProto); - _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; - _err.message = messageWithCauses(err); - _err.stack = stackWithCauses(err); - if (Array.isArray(err.errors)) { - _err.aggregateErrors = err.errors.map((err2) => errSerializer(err2)); + __disconnect__(flush) { + clearInterval(this.heartbeat); + if (this.sharedConnection) { + return this.connection.__removeLimiter__(this.instance); + } else { + return this.connection.disconnect(flush); + } } - for (const key in err) { - if (_err[key] === void 0) { - const val = err[key]; - if (isErrorLike(val)) { - if (key !== "cause" && !Object.prototype.hasOwnProperty.call(val, seen)) { - _err[key] = errSerializer(val); - } - } else { - _err[key] = val; + runScript(name, args) { + var _this3 = this; + return _asyncToGenerator2(function* () { + if (!(name === "init" || name === "register_client")) { + yield _this3.ready; } + return new _this3.Promise((resolve82, reject) => { + var all_args, arr; + all_args = [Date.now(), _this3.clientId].concat(args); + _this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args); + arr = _this3.connection.__scriptArgs__(name, _this3.originalId, all_args, function(err, replies) { + if (err != null) { + return reject(err); + } + return resolve82(replies); + }); + return _this3.connection.__scriptFn__(name)(...arr); + }).catch((e2) => { + if (e2.message === "SETTINGS_KEY_NOT_FOUND") { + if (name === "heartbeat") { + return _this3.Promise.resolve(); + } else { + return _this3.runScript("init", _this3.prepareInitSettings(false)).then(() => { + return _this3.runScript(name, args); + }); + } + } else if (e2.message === "UNKNOWN_CLIENT") { + return _this3.runScript("register_client", [_this3.instance.queued()]).then(() => { + return _this3.runScript(name, args); + }); + } else { + return _this3.Promise.reject(e2); + } + }); + })(); + } + prepareArray(arr) { + var i2, len, results, x3; + results = []; + for (i2 = 0, len = arr.length; i2 < len; i2++) { + x3 = arr[i2]; + results.push(x3 != null ? x3.toString() : ""); } + return results; } - delete err[seen]; - _err.raw = err; - return _err; - } - } -}); -var require_err_with_cause = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-with-cause.js"(exports2, module14) { - "use strict"; - module14.exports = errWithCauseSerializer; - var { isErrorLike } = require_err_helpers(); - var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); - var { seen } = pinoErrorSymbols; - var { toString } = Object.prototype; - function errWithCauseSerializer(err) { - if (!isErrorLike(err)) { - return err; + prepareObject(obj) { + var arr, k, v2; + arr = []; + for (k in obj) { + v2 = obj[k]; + arr.push(k, v2 != null ? v2.toString() : ""); + } + return arr; } - err[seen] = void 0; - const _err = Object.create(pinoErrProto); - _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; - _err.message = err.message; - _err.stack = err.stack; - if (Array.isArray(err.errors)) { - _err.aggregateErrors = err.errors.map((err2) => errWithCauseSerializer(err2)); + prepareInitSettings(clear) { + var args; + args = this.prepareObject(Object.assign({}, this.storeOptions, { + id: this.originalId, + version: this.instance.version, + groupTimeout: this.timeout, + clientTimeout: this.clientTimeout + })); + args.unshift(clear ? 1 : 0, this.instance.version); + return args; } - if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) { - _err.cause = errWithCauseSerializer(err.cause); + convertBool(b) { + return !!b; } - for (const key in err) { - if (_err[key] === void 0) { - const val = err[key]; - if (isErrorLike(val)) { - if (!Object.prototype.hasOwnProperty.call(val, seen)) { - _err[key] = errWithCauseSerializer(val); - } - } else { - _err[key] = val; - } - } + __updateSettings__(options2) { + var _this4 = this; + return _asyncToGenerator2(function* () { + yield _this4.runScript("update_settings", _this4.prepareObject(options2)); + return parser3.overwrite(options2, options2, _this4.storeOptions); + })(); } - delete err[seen]; - _err.raw = err; - return _err; - } - } -}); -var require_req = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/req.js"(exports2, module14) { - "use strict"; - module14.exports = { - mapHttpRequest, - reqSerializer - }; - var rawSymbol = Symbol("pino-raw-req-ref"); - var pinoReqProto = Object.create({}, { - id: { - enumerable: true, - writable: true, - value: "" - }, - method: { - enumerable: true, - writable: true, - value: "" - }, - url: { - enumerable: true, - writable: true, - value: "" - }, - query: { - enumerable: true, - writable: true, - value: "" - }, - params: { - enumerable: true, - writable: true, - value: "" - }, - headers: { - enumerable: true, - writable: true, - value: {} - }, - remoteAddress: { - enumerable: true, - writable: true, - value: "" - }, - remotePort: { - enumerable: true, - writable: true, - value: "" - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; - } + __running__() { + return this.runScript("running", []); } - }); - Object.defineProperty(pinoReqProto, rawSymbol, { - writable: true, - value: {} - }); - function reqSerializer(req) { - const connection = req.info || req.socket; - const _req = Object.create(pinoReqProto); - _req.id = typeof req.id === "function" ? req.id() : req.id || (req.info ? req.info.id : void 0); - _req.method = req.method; - if (req.originalUrl) { - _req.url = req.originalUrl; - } else { - const path8 = req.path; - _req.url = typeof path8 === "string" ? path8 : req.url ? req.url.path || req.url : void 0; + __queued__() { + return this.runScript("queued", []); } - if (req.query) { - _req.query = req.query; + __done__() { + return this.runScript("done", []); } - if (req.params) { - _req.params = req.params; + __groupCheck__() { + var _this5 = this; + return _asyncToGenerator2(function* () { + return _this5.convertBool(yield _this5.runScript("group_check", [])); + })(); } - _req.headers = req.headers; - _req.remoteAddress = connection && connection.remoteAddress; - _req.remotePort = connection && connection.remotePort; - _req.raw = req.raw || req; - return _req; - } - function mapHttpRequest(req) { - return { - req: reqSerializer(req) - }; - } - } -}); -var require_res = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/res.js"(exports2, module14) { - "use strict"; - module14.exports = { - mapHttpResponse, - resSerializer - }; - var rawSymbol = Symbol("pino-raw-res-ref"); - var pinoResProto = Object.create({}, { - statusCode: { - enumerable: true, - writable: true, - value: 0 - }, - headers: { - enumerable: true, - writable: true, - value: "" - }, - raw: { - enumerable: false, - get: function() { - return this[rawSymbol]; - }, - set: function(val) { - this[rawSymbol] = val; - } + __incrementReservoir__(incr) { + return this.runScript("increment_reservoir", [incr]); } - }); - Object.defineProperty(pinoResProto, rawSymbol, { - writable: true, - value: {} - }); - function resSerializer(res) { - const _res = Object.create(pinoResProto); - _res.statusCode = res.headersSent ? res.statusCode : null; - _res.headers = res.getHeaders ? res.getHeaders() : res._headers; - _res.raw = res; - return _res; - } - function mapHttpResponse(res) { - return { - res: resSerializer(res) - }; - } - } -}); -var require_pino_std_serializers = __commonJS({ - "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/index.js"(exports2, module14) { - "use strict"; - var errSerializer = require_err(); - var errWithCauseSerializer = require_err_with_cause(); - var reqSerializers = require_req(); - var resSerializers = require_res(); - module14.exports = { - err: errSerializer, - errWithCause: errWithCauseSerializer, - mapHttpRequest: reqSerializers.mapHttpRequest, - mapHttpResponse: resSerializers.mapHttpResponse, - req: reqSerializers.reqSerializer, - res: resSerializers.resSerializer, - wrapErrorSerializer: function wrapErrorSerializer(customSerializer) { - if (customSerializer === errSerializer) return customSerializer; - return function wrapErrSerializer(err) { - return customSerializer(errSerializer(err)); - }; - }, - wrapRequestSerializer: function wrapRequestSerializer(customSerializer) { - if (customSerializer === reqSerializers.reqSerializer) return customSerializer; - return function wrappedReqSerializer(req) { - return customSerializer(reqSerializers.reqSerializer(req)); - }; - }, - wrapResponseSerializer: function wrapResponseSerializer(customSerializer) { - if (customSerializer === resSerializers.resSerializer) return customSerializer; - return function wrappedResSerializer(res) { - return customSerializer(resSerializers.resSerializer(res)); - }; + __currentReservoir__() { + return this.runScript("current_reservoir", []); + } + __check__(weight) { + var _this6 = this; + return _asyncToGenerator2(function* () { + return _this6.convertBool(yield _this6.runScript("check", _this6.prepareArray([weight]))); + })(); + } + __register__(index, weight, expiration) { + var _this7 = this; + return _asyncToGenerator2(function* () { + var reservoir, success, wait; + var _ref4 = yield _this7.runScript("register", _this7.prepareArray([index, weight, expiration])); + var _ref5 = _slicedToArray2(_ref4, 3); + success = _ref5[0]; + wait = _ref5[1]; + reservoir = _ref5[2]; + return { + success: _this7.convertBool(success), + wait, + reservoir + }; + })(); + } + __submit__(queueLength, weight) { + var _this8 = this; + return _asyncToGenerator2(function* () { + var blocked, e2, maxConcurrent, overweight, reachedHWM, strategy; + try { + var _ref6 = yield _this8.runScript("submit", _this8.prepareArray([queueLength, weight])); + var _ref7 = _slicedToArray2(_ref6, 3); + reachedHWM = _ref7[0]; + blocked = _ref7[1]; + strategy = _ref7[2]; + return { + reachedHWM: _this8.convertBool(reachedHWM), + blocked: _this8.convertBool(blocked), + strategy + }; + } catch (error2) { + e2 = error2; + if (e2.message.indexOf("OVERWEIGHT") === 0) { + var _e$message$split = e2.message.split(":"); + var _e$message$split2 = _slicedToArray2(_e$message$split, 3); + overweight = _e$message$split2[0]; + weight = _e$message$split2[1]; + maxConcurrent = _e$message$split2[2]; + throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${maxConcurrent}`); + } else { + throw e2; + } + } + })(); + } + __free__(index, weight) { + var _this9 = this; + return _asyncToGenerator2(function* () { + var running; + running = yield _this9.runScript("free", _this9.prepareArray([index])); + return { + running + }; + })(); } }; + module14.exports = RedisDatastore; } }); -var require_caller = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/caller.js"(exports2, module14) { +var require_States = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/States.js"(exports2, module14) { "use strict"; - function noOpPrepareStackTrace(_, stack) { - return stack; - } - module14.exports = function getCallers() { - const originalPrepare = Error.prepareStackTrace; - Error.prepareStackTrace = noOpPrepareStackTrace; - const stack = new Error().stack; - Error.prepareStackTrace = originalPrepare; - if (!Array.isArray(stack)) { - return void 0; + var BottleneckError; + var States; + BottleneckError = require_BottleneckError(); + States = class States { + constructor(status1) { + this.status = status1; + this._jobs = {}; + this.counts = this.status.map(function() { + return 0; + }); } - const entries = stack.slice(2); - const fileNames = []; - for (const entry of entries) { - if (!entry) { - continue; + next(id) { + var current, next; + current = this._jobs[id]; + next = current + 1; + if (current != null && next < this.status.length) { + this.counts[current]--; + this.counts[next]++; + return this._jobs[id]++; + } else if (current != null) { + this.counts[current]--; + return delete this._jobs[id]; } - fileNames.push(entry.getFileName()); } - return fileNames; + start(id) { + var initial; + initial = 0; + this._jobs[id] = initial; + return this.counts[initial]++; + } + remove(id) { + var current; + current = this._jobs[id]; + if (current != null) { + this.counts[current]--; + delete this._jobs[id]; + } + return current != null; + } + jobStatus(id) { + var ref; + return (ref = this.status[this._jobs[id]]) != null ? ref : null; + } + statusJobs(status) { + var k, pos, ref, results, v2; + if (status != null) { + pos = this.status.indexOf(status); + if (pos < 0) { + throw new BottleneckError(`status must be one of ${this.status.join(", ")}`); + } + ref = this._jobs; + results = []; + for (k in ref) { + v2 = ref[k]; + if (v2 === pos) { + results.push(k); + } + } + return results; + } else { + return Object.keys(this._jobs); + } + } + statusCounts() { + return this.counts.reduce((acc, v2, i2) => { + acc[this.status[i2]] = v2; + return acc; + }, {}); + } }; + module14.exports = States; } }); -var require_validator = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/validator.js"(exports2, module14) { +var require_Sync = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Sync.js"(exports2, module14) { "use strict"; - module14.exports = validator2; - function validator2(opts = {}) { - const { - ERR_PATHS_MUST_BE_STRINGS = () => "fast-redact - Paths must be (non-empty) strings", - ERR_INVALID_PATH = (s) => `fast-redact \u2013 Invalid path (${s})` - } = opts; - return function validate({ paths }) { - paths.forEach((s) => { - if (typeof s !== "string") { - throw Error(ERR_PATHS_MUST_BE_STRINGS()); + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; + } + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); + } + } + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); } - try { - if (/〇/.test(s)) throw Error(); - const expr = (s[0] === "[" ? "" : ".") + s.replace(/^\*/, "\u3007").replace(/\.\*/g, ".\u3007").replace(/\[\*\]/g, "[\u3007]"); - if (/\n|\r|;/.test(expr)) throw Error(); - if (/\/\*/.test(expr)) throw Error(); - Function(` - 'use strict' - const o = new Proxy({}, { get: () => o, set: () => { throw Error() } }); - const \u3007 = null; - o${expr} - if ([o${expr}].length !== 1) throw Error()`)(); - } catch (e2) { - throw Error(ERR_INVALID_PATH(s)); + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); } + _next(void 0); }); }; } + var DLList; + var Sync; + DLList = require_DLList(); + Sync = class Sync { + constructor(name, Promise2) { + this.schedule = this.schedule.bind(this); + this.name = name; + this.Promise = Promise2; + this._running = 0; + this._queue = new DLList(); + } + isEmpty() { + return this._queue.length === 0; + } + _tryToRun() { + var _this = this; + return _asyncToGenerator2(function* () { + var args, cb, error2, reject, resolve82, returned, task; + if (_this._running < 1 && _this._queue.length > 0) { + _this._running++; + var _this$_queue$shift = _this._queue.shift(); + task = _this$_queue$shift.task; + args = _this$_queue$shift.args; + resolve82 = _this$_queue$shift.resolve; + reject = _this$_queue$shift.reject; + cb = yield _asyncToGenerator2(function* () { + try { + returned = yield task(...args); + return function() { + return resolve82(returned); + }; + } catch (error1) { + error2 = error1; + return function() { + return reject(error2); + }; + } + })(); + _this._running--; + _this._tryToRun(); + return cb(); + } + })(); + } + schedule(task, ...args) { + var promise, reject, resolve82; + resolve82 = reject = null; + promise = new this.Promise(function(_resolve, _reject) { + resolve82 = _resolve; + return reject = _reject; + }); + this._queue.push({ + task, + args, + resolve: resolve82, + reject + }); + this._tryToRun(); + return promise; + } + }; + module14.exports = Sync; } }); -var require_rx = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/rx.js"(exports2, module14) { - "use strict"; - module14.exports = /[^.[\]]+|\[((?:.)*?)\]/g; - } -}); -var require_parse = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/parse.js"(exports2, module14) { - "use strict"; - var rx = require_rx(); - module14.exports = parse62; - function parse62({ paths }) { - const wildcards = []; - var wcLen = 0; - const secret = paths.reduce(function(o2, strPath, ix) { - var path8 = strPath.match(rx).map((p) => p.replace(/'|"|`/g, "")); - const leadingBracket = strPath[0] === "["; - path8 = path8.map((p) => { - if (p[0] === "[") return p.substr(1, p.length - 2); - else return p; - }); - const star = path8.indexOf("*"); - if (star > -1) { - const before = path8.slice(0, star); - const beforeStr = before.join("."); - const after = path8.slice(star + 1, path8.length); - const nested = after.length > 0; - wcLen++; - wildcards.push({ - before, - beforeStr, - after, - nested - }); - } else { - o2[strPath] = { - path: path8, - val: void 0, - precensored: false, - circle: "", - escPath: JSON.stringify(strPath), - leadingBracket - }; - } - return o2; - }, {}); - return { wildcards, wcLen, secret }; - } +var require_version = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/version.json"(exports2, module14) { + module14.exports = { version: "2.19.5" }; } }); -var require_redactor = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/redactor.js"(exports2, module14) { +var require_Group = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Group.js"(exports2, module14) { "use strict"; - var rx = require_rx(); - module14.exports = redactor; - function redactor({ secret, serialize: serialize2, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { - const redact = Function("o", ` - if (typeof o !== 'object' || o == null) { - ${strictImpl(strict, serialize2)} - } - const { censor, secret } = this - const originalSecret = {} - const secretKeys = Object.keys(secret) - for (var i = 0; i < secretKeys.length; i++) { - originalSecret[secretKeys[i]] = secret[secretKeys[i]] + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); } - - ${redactTmpl(secret, isCensorFct, censorFctTakesPath)} - this.compileRestore() - ${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} - this.secret = originalSecret - ${resultTmpl(serialize2)} - `).bind(state); - redact.state = state; - if (serialize2 === false) { - redact.restore = (o2) => state.restore(o2); - } - return redact; + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - function redactTmpl(secret, isCensorFct, censorFctTakesPath) { - return Object.keys(secret).map((path8) => { - const { escPath, leadingBracket, path: arrPath } = secret[path8]; - const skip = leadingBracket ? 1 : 0; - const delim = leadingBracket ? "" : "."; - const hops = []; - var match2; - while ((match2 = rx.exec(path8)) !== null) { - const [, ix] = match2; - const { index, input } = match2; - if (index > skip) hops.push(input.substring(0, index - (ix ? 0 : 1))); + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; } - var existence = hops.map((p) => `o${delim}${p}`).join(" && "); - if (existence.length === 0) existence += `o${delim}${path8} != null`; - else existence += ` && o${delim}${path8} != null`; - const circularDetection = ` - switch (true) { - ${hops.reverse().map((p) => ` - case o${delim}${p} === censor: - secret[${escPath}].circle = ${JSON.stringify(p)} - break - `).join("\n")} - } - `; - const censorArgs = censorFctTakesPath ? `val, ${JSON.stringify(arrPath)}` : `val`; - return ` - if (${existence}) { - const val = o${delim}${path8} - if (val === censor) { - secret[${escPath}].precensored = true - } else { - secret[${escPath}].val = val - o${delim}${path8} = ${isCensorFct ? `censor(${censorArgs})` : "censor"} - ${circularDetection} + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } } - `; - }).join("\n"); - } - function dynamicRedactTmpl(hasWildcards, isCensorFct, censorFctTakesPath) { - return hasWildcards === true ? ` - { - const { wildcards, wcLen, groupRedact, nestedRedact } = this - for (var i = 0; i < wcLen; i++) { - const { before, beforeStr, after, nested } = wildcards[i] - if (nested === true) { - secret[beforeStr] = secret[beforeStr] || [] - nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath}) - } else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath}) - } - } - ` : ""; - } - function resultTmpl(serialize2) { - return serialize2 === false ? `return o` : ` - var s = this.serialize(o) - this.restore(o) - return s - `; + return _arr; } - function strictImpl(strict, serialize2) { - return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize2 === false ? `return o` : `return this.serialize(o)`; + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; } - } -}); -var require_modifiers = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/modifiers.js"(exports2, module14) { - "use strict"; - module14.exports = { - groupRedact, - groupRestore, - nestedRedact, - nestedRestore - }; - function groupRestore({ keys, values, target }) { - if (target == null || typeof target === "string") return; - const length2 = keys.length; - for (var i2 = 0; i2 < length2; i2++) { - const k = keys[i2]; - target[k] = values[i2]; + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; + } + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } } - function groupRedact(o2, path8, censor, isCensorFct, censorFctTakesPath) { - const target = get2(o2, path8); - if (target == null || typeof target === "string") return { keys: null, values: null, target, flat: true }; - const keys = Object.keys(target); - const keysLength = keys.length; - const pathLength = path8.length; - const pathWithKey = censorFctTakesPath ? [...path8] : void 0; - const values = new Array(keysLength); - for (var i2 = 0; i2 < keysLength; i2++) { - const key = keys[i2]; - values[i2] = target[key]; - if (censorFctTakesPath) { - pathWithKey[pathLength] = key; - target[key] = censor(target[key], pathWithKey); - } else if (isCensorFct) { - target[key] = censor(target[key]); - } else { - target[key] = censor; - } - } - return { keys, values, target, flat: true }; + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; } - function nestedRestore(instructions) { - for (let i2 = 0; i2 < instructions.length; i2++) { - const { target, path: path8, value } = instructions[i2]; - let current = target; - for (let i3 = path8.length - 1; i3 > 0; i3--) { - current = current[path8[i3]]; + var Events2; + var Group; + var IORedisConnection2; + var RedisConnection2; + var Scripts2; + var parser3; + parser3 = require_parser2(); + Events2 = require_Events(); + RedisConnection2 = require_RedisConnection(); + IORedisConnection2 = require_IORedisConnection(); + Scripts2 = require_Scripts(); + Group = function() { + class Group2 { + constructor(limiterOptions = {}) { + this.deleteKey = this.deleteKey.bind(this); + this.limiterOptions = limiterOptions; + parser3.load(this.limiterOptions, this.defaults, this); + this.Events = new Events2(this); + this.instances = {}; + this.Bottleneck = require_Bottleneck(); + this._startAutoCleanup(); + this.sharedConnection = this.connection != null; + if (this.connection == null) { + if (this.limiterOptions.datastore === "redis") { + this.connection = new RedisConnection2(Object.assign({}, this.limiterOptions, { + Events: this.Events + })); + } else if (this.limiterOptions.datastore === "ioredis") { + this.connection = new IORedisConnection2(Object.assign({}, this.limiterOptions, { + Events: this.Events + })); + } + } } - current[path8[0]] = value; - } - } - function nestedRedact(store, o2, path8, ns, censor, isCensorFct, censorFctTakesPath) { - const target = get2(o2, path8); - if (target == null) return; - const keys = Object.keys(target); - const keysLength = keys.length; - for (var i2 = 0; i2 < keysLength; i2++) { - const key = keys[i2]; - specialSet(store, target, key, path8, ns, censor, isCensorFct, censorFctTakesPath); - } - return store; - } - function has2(obj, prop) { - return obj !== void 0 && obj !== null ? "hasOwn" in Object ? Object.hasOwn(obj, prop) : Object.prototype.hasOwnProperty.call(obj, prop) : false; - } - function specialSet(store, o2, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath) { - const afterPathLen = afterPath.length; - const lastPathIndex = afterPathLen - 1; - const originalKey = k; - var i2 = -1; - var n; - var nv; - var ov; - var oov = null; - var wc = null; - var kIsWc; - var wcov; - var consecutive = false; - var level = 0; - var depth = 0; - var redactPathCurrent = tree(); - ov = n = o2[k]; - if (typeof n !== "object") return; - while (n != null && ++i2 < afterPathLen) { - depth += 1; - k = afterPath[i2]; - oov = ov; - if (k !== "*" && !wc && !(typeof n === "object" && k in n)) { - break; + key(key = "") { + var ref; + return (ref = this.instances[key]) != null ? ref : (() => { + var limiter; + limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { + id: `${this.id}-${key}`, + timeout: this.timeout, + connection: this.connection + })); + this.Events.trigger("created", limiter, key); + return limiter; + })(); } - if (k === "*") { - if (wc === "*") { - consecutive = true; - } - wc = k; - if (i2 !== lastPathIndex) { - continue; + deleteKey(key = "") { + var _this = this; + return _asyncToGenerator2(function* () { + var deleted, instance; + instance = _this.instances[key]; + if (_this.connection) { + deleted = yield _this.connection.__runCommand__(["del", ...Scripts2.allKeys(`${_this.id}-${key}`)]); + } + if (instance != null) { + delete _this.instances[key]; + yield instance.disconnect(); + } + return instance != null || deleted > 0; + })(); + } + limiters() { + var k, ref, results, v2; + ref = this.instances; + results = []; + for (k in ref) { + v2 = ref[k]; + results.push({ + key: k, + limiter: v2 + }); } + return results; } - if (wc) { - const wcKeys = Object.keys(n); - for (var j = 0; j < wcKeys.length; j++) { - const wck = wcKeys[j]; - wcov = n[wck]; - kIsWc = k === "*"; - if (consecutive) { - redactPathCurrent = node(redactPathCurrent, wck, depth); - level = i2; - ov = iterateNthLevel(wcov, level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, o2[originalKey], depth + 1); - } else { - if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { - if (kIsWc) { - ov = wcov; - } else { - ov = wcov[k]; - } - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (kIsWc) { - const rv = restoreInstr(node(redactPathCurrent, wck, depth), ov, o2[originalKey]); - store.push(rv); - n[wck] = nv; - } else { - if (wcov[k] === nv) { - } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { - redactPathCurrent = node(redactPathCurrent, wck, depth); + keys() { + return Object.keys(this.instances); + } + clusterKeys() { + var _this2 = this; + return _asyncToGenerator2(function* () { + var cursor, end, found, i2, k, keys, len, next, start; + if (_this2.connection == null) { + return _this2.Promise.resolve(_this2.keys()); + } + keys = []; + cursor = null; + start = `b_${_this2.id}-`.length; + end = "_settings".length; + while (cursor !== 0) { + var _ref = yield _this2.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${_this2.id}-*_settings`, "count", 1e4]); + var _ref2 = _slicedToArray2(_ref, 2); + next = _ref2[0]; + found = _ref2[1]; + cursor = ~~next; + for (i2 = 0, len = found.length; i2 < len; i2++) { + k = found[i2]; + keys.push(k.slice(start, -end)); + } + } + return keys; + })(); + } + _startAutoCleanup() { + var _this3 = this; + var base2; + clearInterval(this.interval); + return typeof (base2 = this.interval = setInterval( + /* @__PURE__ */ _asyncToGenerator2(function* () { + var e2, k, ref, results, time3, v2; + time3 = Date.now(); + ref = _this3.instances; + results = []; + for (k in ref) { + v2 = ref[k]; + try { + if (yield v2._store.__groupCheck__(time3)) { + results.push(_this3.deleteKey(k)); } else { - redactPathCurrent = node(redactPathCurrent, wck, depth); - const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, o2[originalKey]); - store.push(rv); - wcov[k] = nv; + results.push(void 0); } + } catch (error2) { + e2 = error2; + results.push(v2.Events.trigger("error", e2)); } } - } - } - wc = null; - } else { - ov = n[k]; - redactPathCurrent = node(redactPathCurrent, k, depth); - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (has2(n, k) && nv === ov || nv === void 0 && censor !== void 0) { - } else { - const rv = restoreInstr(redactPathCurrent, ov, o2[originalKey]); - store.push(rv); - n[k] = nv; + return results; + }), + this.timeout / 2 + )).unref === "function" ? base2.unref() : void 0; + } + updateSettings(options2 = {}) { + parser3.overwrite(options2, this.defaults, this); + parser3.overwrite(options2, options2, this.limiterOptions); + if (options2.timeout != null) { + return this._startAutoCleanup(); } - n = n[k]; } - if (typeof n !== "object") break; - if (ov === oov || typeof ov === "undefined") { + disconnect(flush = true) { + var ref; + if (!this.sharedConnection) { + return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; + } } } - } - function get2(o2, p) { - var i2 = -1; - var l = p.length; - var n = o2; - while (n != null && ++i2 < l) { - n = n[p[i2]]; - } - return n; - } - function iterateNthLevel(wcov, level, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth) { - if (level === 0) { - if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { - if (kIsWc) { - ov = wcov; - } else { - ov = wcov[k]; - } - nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; - if (kIsWc) { - const rv = restoreInstr(redactPathCurrent, ov, parent); - store.push(rv); - n[wck] = nv; - } else { - if (wcov[k] === nv) { - } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { - } else { - const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, parent); - store.push(rv); - wcov[k] = nv; - } + ; + Group2.prototype.defaults = { + timeout: 1e3 * 60 * 5, + connection: null, + Promise, + id: "group-key" + }; + return Group2; + }.call(void 0); + module14.exports = Group; + } +}); +var require_Batcher = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Batcher.js"(exports2, module14) { + "use strict"; + var Batcher; + var Events2; + var parser3; + parser3 = require_parser2(); + Events2 = require_Events(); + Batcher = function() { + class Batcher2 { + constructor(options2 = {}) { + this.options = options2; + parser3.load(this.options, this.defaults, this); + this.Events = new Events2(this); + this._arr = []; + this._resetPromise(); + this._lastFlush = Date.now(); + } + _resetPromise() { + return this._promise = new this.Promise((res, rej) => { + return this._resolve = res; + }); + } + _flush() { + clearTimeout(this._timeout); + this._lastFlush = Date.now(); + this._resolve(); + this.Events.trigger("batch", this._arr); + this._arr = []; + return this._resetPromise(); + } + add(data) { + var ret; + this._arr.push(data); + ret = this._promise; + if (this._arr.length === this.maxSize) { + this._flush(); + } else if (this.maxTime != null && this._arr.length === 1) { + this._timeout = setTimeout(() => { + return this._flush(); + }, this.maxTime); } + return ret; } } - for (const key in wcov) { - if (typeof wcov[key] === "object") { - redactPathCurrent = node(redactPathCurrent, key, depth); - iterateNthLevel(wcov[key], level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth + 1); + ; + Batcher2.prototype.defaults = { + maxTime: null, + maxSize: null, + Promise + }; + return Batcher2; + }.call(void 0); + module14.exports = Batcher; + } +}); +var require_Bottleneck = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Bottleneck.js"(exports2, module14) { + "use strict"; + function _slicedToArray2(arr, i2) { + return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + } + function _iterableToArrayLimit2(arr, i2) { + var _arr = []; + var _n = true; + var _d = false; + var _e = void 0; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i2 && _arr.length === i2) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"] != null) _i["return"](); + } finally { + if (_d) throw _e; } } + return _arr; } - function tree() { - return { parent: null, key: null, children: [], depth: 0 }; + function _toArray(arr) { + return _arrayWithHoles2(arr) || _iterableToArray(arr) || _nonIterableRest2(); } - function node(parent, key, depth) { - if (parent.depth === depth) { - return node(parent.parent, key, depth); - } - var child = { - parent, - key, - depth, - children: [] - }; - parent.children.push(child); - return child; + function _nonIterableRest2() { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - function restoreInstr(node2, value, target) { - let current = node2; - const path8 = []; - do { - path8.push(current.key); - current = current.parent; - } while (current.parent != null); - return { path: path8, value, target }; + function _iterableToArray(iter) { + if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } - } -}); -var require_restorer = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/restorer.js"(exports2, module14) { - "use strict"; - var { groupRestore, nestedRestore } = require_modifiers(); - module14.exports = restorer; - function restorer() { - return function compileRestore() { - if (this.restore) { - this.restore.state.secret = this.secret; - return; - } - const { secret, wcLen } = this; - const paths = Object.keys(secret); - const resetters = resetTmpl(secret, paths); - const hasWildcards = wcLen > 0; - const state = hasWildcards ? { secret, groupRestore, nestedRestore } : { secret }; - this.restore = Function( - "o", - restoreTmpl(resetters, paths, hasWildcards) - ).bind(state); - this.restore.state = state; - }; + function _arrayWithHoles2(arr) { + if (Array.isArray(arr)) return arr; } - function resetTmpl(secret, paths) { - return paths.map((path8) => { - const { circle, escPath, leadingBracket } = secret[path8]; - const delim = leadingBracket ? "" : "."; - const reset = circle ? `o.${circle} = secret[${escPath}].val` : `o${delim}${path8} = secret[${escPath}].val`; - const clear = `secret[${escPath}].val = undefined`; - return ` - if (secret[${escPath}].val !== undefined) { - try { ${reset} } catch (e) {} - ${clear} + function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error2) { + reject(error2); + return; } - `; - }).join(""); - } - function restoreTmpl(resetters, paths, hasWildcards) { - const dynamicReset = hasWildcards === true ? ` - const keys = Object.keys(secret) - const len = keys.length - for (var i = len - 1; i >= ${paths.length}; i--) { - const k = keys[i] - const o = secret[k] - if (o) { - if (o.flat === true) this.groupRestore(o) - else this.nestedRestore(o) - secret[k] = null + if (info.done) { + resolve82(value); + } else { + Promise.resolve(value).then(_next, _throw); } } - ` : ""; - return ` - const secret = this.secret - ${dynamicReset} - ${resetters} - return o - `; + function _asyncToGenerator2(fn) { + return function() { + var self2 = this, args = arguments; + return new Promise(function(resolve82, reject) { + var gen = fn.apply(self2, args); + function _next(value) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); + } + function _throw(err) { + asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + } + _next(void 0); + }); + }; } - } -}); -var require_state = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/state.js"(exports2, module14) { - "use strict"; - module14.exports = state; - function state(o2) { - const { - secret, - censor, - compileRestore, - serialize: serialize2, - groupRedact, - nestedRedact, - wildcards, - wcLen - } = o2; - const builder = [{ secret, censor, compileRestore }]; - if (serialize2 !== false) builder.push({ serialize: serialize2 }); - if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }); - return Object.assign(...builder); - } - } -}); -var require_fast_redact = __commonJS({ - "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/index.js"(exports2, module14) { - "use strict"; - var validator2 = require_validator(); - var parse62 = require_parse(); - var redactor = require_redactor(); - var restorer = require_restorer(); - var { groupRedact, nestedRedact } = require_modifiers(); - var state = require_state(); - var rx = require_rx(); - var validate = validator2(); - var noop = (o2) => o2; - noop.restore = noop; - var DEFAULT_CENSOR = "[REDACTED]"; - fastRedact.rx = rx; - fastRedact.validator = validator2; - module14.exports = fastRedact; - function fastRedact(opts = {}) { - const paths = Array.from(new Set(opts.paths || [])); - const serialize2 = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; - const remove = opts.remove; - if (remove === true && serialize2 !== JSON.stringify) { - throw Error("fast-redact \u2013 remove option may only be set when serializer is JSON.stringify"); - } - const censor = remove === true ? void 0 : "censor" in opts ? opts.censor : DEFAULT_CENSOR; - const isCensorFct = typeof censor === "function"; - const censorFctTakesPath = isCensorFct && censor.length > 1; - if (paths.length === 0) return serialize2 || noop; - validate({ paths, serialize: serialize2, censor }); - const { wildcards, wcLen, secret } = parse62({ paths, censor }); - const compileRestore = restorer(); - const strict = "strict" in opts ? opts.strict : true; - return redactor({ secret, wcLen, serialize: serialize2, strict, isCensorFct, censorFctTakesPath }, state({ - secret, - censor, - compileRestore, - serialize: serialize2, - groupRedact, - nestedRedact, - wildcards, - wcLen - })); - } - } -}); -var require_symbols = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/symbols.js"(exports2, module14) { - "use strict"; - var setLevelSym = Symbol("pino.setLevel"); - var getLevelSym = Symbol("pino.getLevel"); - var levelValSym = Symbol("pino.levelVal"); - var levelCompSym = Symbol("pino.levelComp"); - var useLevelLabelsSym = Symbol("pino.useLevelLabels"); - var useOnlyCustomLevelsSym = Symbol("pino.useOnlyCustomLevels"); - var mixinSym = Symbol("pino.mixin"); - var lsCacheSym = Symbol("pino.lsCache"); - var chindingsSym = Symbol("pino.chindings"); - var asJsonSym = Symbol("pino.asJson"); - var writeSym = Symbol("pino.write"); - var redactFmtSym = Symbol("pino.redactFmt"); - var timeSym = Symbol("pino.time"); - var timeSliceIndexSym = Symbol("pino.timeSliceIndex"); - var streamSym = Symbol("pino.stream"); - var stringifySym = Symbol("pino.stringify"); - var stringifySafeSym = Symbol("pino.stringifySafe"); - var stringifiersSym = Symbol("pino.stringifiers"); - var endSym = Symbol("pino.end"); - var formatOptsSym = Symbol("pino.formatOpts"); - var messageKeySym = Symbol("pino.messageKey"); - var errorKeySym = Symbol("pino.errorKey"); - var nestedKeySym = Symbol("pino.nestedKey"); - var nestedKeyStrSym = Symbol("pino.nestedKeyStr"); - var mixinMergeStrategySym = Symbol("pino.mixinMergeStrategy"); - var msgPrefixSym = Symbol("pino.msgPrefix"); - var wildcardFirstSym = Symbol("pino.wildcardFirst"); - var serializersSym = Symbol.for("pino.serializers"); - var formattersSym = Symbol.for("pino.formatters"); - var hooksSym = Symbol.for("pino.hooks"); - var needsMetadataGsym = Symbol.for("pino.metadata"); - module14.exports = { - setLevelSym, - getLevelSym, - levelValSym, - levelCompSym, - useLevelLabelsSym, - mixinSym, - lsCacheSym, - chindingsSym, - asJsonSym, - writeSym, - serializersSym, - redactFmtSym, - timeSym, - timeSliceIndexSym, - streamSym, - stringifySym, - stringifySafeSym, - stringifiersSym, - endSym, - formatOptsSym, - messageKeySym, - errorKeySym, - nestedKeySym, - wildcardFirstSym, - needsMetadataGsym, - useOnlyCustomLevelsSym, - formattersSym, - hooksSym, - nestedKeyStrSym, - mixinMergeStrategySym, - msgPrefixSym - }; - } -}); -var require_redaction = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/redaction.js"(exports2, module14) { - "use strict"; - var fastRedact = require_fast_redact(); - var { redactFmtSym, wildcardFirstSym } = require_symbols(); - var { rx, validator: validator2 } = fastRedact; - var validate = validator2({ - ERR_PATHS_MUST_BE_STRINGS: () => "pino \u2013 redacted paths must be strings", - ERR_INVALID_PATH: (s) => `pino \u2013 redact paths array contains an invalid path (${s})` - }); - var CENSOR = "[Redacted]"; - var strict = false; - function redaction(opts, serialize2) { - const { paths, censor } = handle(opts); - const shape = paths.reduce((o2, str) => { - rx.lastIndex = 0; - const first = rx.exec(str); - const next = rx.exec(str); - let ns = first[1] !== void 0 ? first[1].replace(/^(?:"|'|`)(.*)(?:"|'|`)$/, "$1") : first[0]; - if (ns === "*") { - ns = wildcardFirstSym; + var Bottleneck2; + var DEFAULT_PRIORITY; + var Events2; + var Job; + var LocalDatastore; + var NUM_PRIORITIES; + var Queues; + var RedisDatastore; + var States; + var Sync; + var parser3; + var splice = [].splice; + NUM_PRIORITIES = 10; + DEFAULT_PRIORITY = 5; + parser3 = require_parser2(); + Queues = require_Queues(); + Job = require_Job(); + LocalDatastore = require_LocalDatastore(); + RedisDatastore = require_RedisDatastore(); + Events2 = require_Events(); + States = require_States(); + Sync = require_Sync(); + Bottleneck2 = function() { + class Bottleneck3 { + constructor(options2 = {}, ...invalid) { + var storeInstanceOptions, storeOptions; + this._addToQueue = this._addToQueue.bind(this); + this._validateOptions(options2, invalid); + parser3.load(options2, this.instanceDefaults, this); + this._queues = new Queues(NUM_PRIORITIES); + this._scheduled = {}; + this._states = new States(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); + this._limiter = null; + this.Events = new Events2(this); + this._submitLock = new Sync("submit", this.Promise); + this._registerLock = new Sync("register", this.Promise); + storeOptions = parser3.load(options2, this.storeDefaults, {}); + this._store = function() { + if (this.datastore === "redis" || this.datastore === "ioredis" || this.connection != null) { + storeInstanceOptions = parser3.load(options2, this.redisStoreDefaults, {}); + return new RedisDatastore(this, storeOptions, storeInstanceOptions); + } else if (this.datastore === "local") { + storeInstanceOptions = parser3.load(options2, this.localStoreDefaults, {}); + return new LocalDatastore(this, storeOptions, storeInstanceOptions); + } else { + throw new Bottleneck3.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); + } + }.call(this); + this._queues.on("leftzero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.ref === "function" ? ref.ref() : void 0 : void 0; + }); + this._queues.on("zero", () => { + var ref; + return (ref = this._store.heartbeat) != null ? typeof ref.unref === "function" ? ref.unref() : void 0 : void 0; + }); } - if (next === null) { - o2[ns] = null; - return o2; + _validateOptions(options2, invalid) { + if (!(options2 != null && typeof options2 === "object" && invalid.length === 0)) { + throw new Bottleneck3.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); + } } - if (o2[ns] === null) { - return o2; + ready() { + return this._store.ready; } - const { index } = next; - const nextPath = `${str.substr(index, str.length - 1)}`; - o2[ns] = o2[ns] || []; - if (ns !== wildcardFirstSym && o2[ns].length === 0) { - o2[ns].push(...o2[wildcardFirstSym] || []); + clients() { + return this._store.clients; } - if (ns === wildcardFirstSym) { - Object.keys(o2).forEach(function(k) { - if (o2[k]) { - o2[k].push(nextPath); - } - }); + channel() { + return `b_${this.id}`; } - o2[ns].push(nextPath); - return o2; - }, {}); - const result = { - [redactFmtSym]: fastRedact({ paths, censor, serialize: serialize2, strict }) - }; - const topCensor = (...args) => { - return typeof censor === "function" ? serialize2(censor(...args)) : serialize2(censor); - }; - return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o2, k) => { - if (shape[k] === null) { - o2[k] = (value) => topCensor(value, [k]); - } else { - const wrappedCensor = typeof censor === "function" ? (value, path8) => { - return censor(value, [k, ...path8]); - } : censor; - o2[k] = fastRedact({ - paths: shape[k], - censor: wrappedCensor, - serialize: serialize2, - strict - }); + channel_client() { + return `b_${this.id}_${this._store.clientId}`; } - return o2; - }, result); - } - function handle(opts) { - if (Array.isArray(opts)) { - opts = { paths: opts, censor: CENSOR }; - validate(opts); - return opts; - } - let { paths, censor = CENSOR, remove } = opts; - if (Array.isArray(paths) === false) { - throw Error("pino \u2013 redact must contain an array of strings"); - } - if (remove === true) censor = void 0; - validate({ paths, censor }); - return { paths, censor }; - } - module14.exports = redaction; - } -}); -var require_time = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/time.js"(exports2, module14) { - "use strict"; - var nullTime = () => ""; - var epochTime = () => `,"time":${Date.now()}`; - var unixTime = () => `,"time":${Math.round(Date.now() / 1e3)}`; - var isoTime = () => `,"time":"${new Date(Date.now()).toISOString()}"`; - module14.exports = { nullTime, epochTime, unixTime, isoTime }; - } -}); -var require_quick_format_unescaped = __commonJS({ - "node_modules/.deno/quick-format-unescaped@4.0.4/node_modules/quick-format-unescaped/index.js"(exports2, module14) { - "use strict"; - function tryStringify(o2) { - try { - return JSON.stringify(o2); - } catch (e2) { - return '"[Circular]"'; - } - } - module14.exports = format52; - function format52(f, args, opts) { - var ss = opts && opts.stringify || tryStringify; - var offset = 1; - if (typeof f === "object" && f !== null) { - var len = args.length + offset; - if (len === 1) return f; - var objects = new Array(len); - objects[0] = ss(f); - for (var index = 1; index < len; index++) { - objects[index] = ss(args[index]); + publish(message) { + return this._store.__publish__(message); } - return objects.join(" "); - } - if (typeof f !== "string") { - return f; - } - var argLen = args.length; - if (argLen === 0) return f; - var str = ""; - var a = 1 - offset; - var lastPos = -1; - var flen = f && f.length || 0; - for (var i2 = 0; i2 < flen; ) { - if (f.charCodeAt(i2) === 37 && i2 + 1 < flen) { - lastPos = lastPos > -1 ? lastPos : 0; - switch (f.charCodeAt(i2 + 1)) { - case 100: - // 'd' - case 102: - if (a >= argLen) - break; - if (args[a] == null) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += Number(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 105: - if (a >= argLen) - break; - if (args[a] == null) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += Math.floor(Number(args[a])); - lastPos = i2 + 2; - i2++; - break; - case 79: - // 'O' - case 111: - // 'o' - case 106: - if (a >= argLen) - break; - if (args[a] === void 0) break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - var type = typeof args[a]; - if (type === "string") { - str += "'" + args[a] + "'"; - lastPos = i2 + 2; - i2++; - break; - } - if (type === "function") { - str += args[a].name || ""; - lastPos = i2 + 2; - i2++; - break; - } - str += ss(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 115: - if (a >= argLen) - break; - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += String(args[a]); - lastPos = i2 + 2; - i2++; - break; - case 37: - if (lastPos < i2) - str += f.slice(lastPos, i2); - str += "%"; - lastPos = i2 + 2; - i2++; - a--; - break; - } - ++a; + disconnect(flush = true) { + return this._store.__disconnect__(flush); } - ++i2; - } - if (lastPos === -1) - return f; - else if (lastPos < flen) { - str += f.slice(lastPos); - } - return str; - } - } -}); -var require_atomic_sleep = __commonJS({ - "node_modules/.deno/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module14) { - "use strict"; - if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") { - let sleep = function(ms) { - const valid = ms > 0 && ms < Infinity; - if (valid === false) { - if (typeof ms !== "number" && typeof ms !== "bigint") { - throw TypeError("sleep: ms must be a number"); - } - throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); + chain(_limiter) { + this._limiter = _limiter; + return this; } - Atomics.wait(nil, 0, 0, Number(ms)); - }; - const nil = new Int32Array(new SharedArrayBuffer(4)); - module14.exports = sleep; - } else { - let sleep = function(ms) { - const valid = ms > 0 && ms < Infinity; - if (valid === false) { - if (typeof ms !== "number" && typeof ms !== "bigint") { - throw TypeError("sleep: ms must be a number"); - } - throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); + queued(priority) { + return this._queues.queued(priority); } - const target = Date.now() + Number(ms); - while (target > Date.now()) { + clusterQueued() { + return this._store.__queued__(); } - }; - module14.exports = sleep; - } - } -}); -var require_sonic_boom = __commonJS({ - "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports2, module14) { - "use strict"; - var fs = __require2("fs"); - var EventEmitter = __require2("events"); - var inherits = __require2("util").inherits; - var path8 = __require2("path"); - var sleep = require_atomic_sleep(); - var BUSY_WRITE_TIMEOUT = 100; - var kEmptyBuffer = Buffer.allocUnsafe(0); - var MAX_WRITE = 16 * 1024; - var kContentModeBuffer = "buffer"; - var kContentModeUtf8 = "utf8"; - function openFile(file, sonic) { - sonic._opening = true; - sonic._writing = true; - sonic._asyncDrainScheduled = false; - function fileOpened(err, fd) { - if (err) { - sonic._reopening = false; - sonic._writing = false; - sonic._opening = false; - if (sonic.sync) { - process.nextTick(() => { - if (sonic.listenerCount("error") > 0) { - sonic.emit("error", err); - } - }); - } else { - sonic.emit("error", err); - } - return; + empty() { + return this.queued() === 0 && this._submitLock.isEmpty(); } - const reopening = sonic._reopening; - sonic.fd = fd; - sonic.file = file; - sonic._reopening = false; - sonic._opening = false; - sonic._writing = false; - if (sonic.sync) { - process.nextTick(() => sonic.emit("ready")); - } else { - sonic.emit("ready"); + running() { + return this._store.__running__(); } - if (sonic.destroyed) { - return; + done() { + return this._store.__done__(); } - if (!sonic._writing && sonic._len > sonic.minLength || sonic._flushPending) { - sonic._actualWrite(); - } else if (reopening) { - process.nextTick(() => sonic.emit("drain")); + jobStatus(id) { + return this._states.jobStatus(id); } - } - const flags = sonic.append ? "a" : "w"; - const mode = sonic.mode; - if (sonic.sync) { - try { - if (sonic.mkdir) fs.mkdirSync(path8.dirname(file), { recursive: true }); - const fd = fs.openSync(file, flags, mode); - fileOpened(null, fd); - } catch (err) { - fileOpened(err); - throw err; + jobs(status) { + return this._states.statusJobs(status); } - } else if (sonic.mkdir) { - fs.mkdir(path8.dirname(file), { recursive: true }, (err) => { - if (err) return fileOpened(err); - fs.open(file, flags, mode, fileOpened); - }); - } else { - fs.open(file, flags, mode, fileOpened); - } - } - function SonicBoom(opts) { - if (!(this instanceof SonicBoom)) { - return new SonicBoom(opts); - } - let { fd, dest, minLength, maxLength, maxWrite, sync, append = true, mkdir: mkdir4, retryEAGAIN, fsync, contentMode, mode } = opts || {}; - fd = fd || dest; - this._len = 0; - this.fd = -1; - this._bufs = []; - this._lens = []; - this._writing = false; - this._ending = false; - this._reopening = false; - this._asyncDrainScheduled = false; - this._flushPending = false; - this._hwm = Math.max(minLength || 0, 16387); - this.file = null; - this.destroyed = false; - this.minLength = minLength || 0; - this.maxLength = maxLength || 0; - this.maxWrite = maxWrite || MAX_WRITE; - this.sync = sync || false; - this.writable = true; - this._fsync = fsync || false; - this.append = append || false; - this.mode = mode; - this.retryEAGAIN = retryEAGAIN || (() => true); - this.mkdir = mkdir4 || false; - let fsWriteSync; - let fsWrite; - if (contentMode === kContentModeBuffer) { - this._writingBuf = kEmptyBuffer; - this.write = writeBuffer; - this.flush = flushBuffer; - this.flushSync = flushBufferSync; - this._actualWrite = actualWriteBuffer; - fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf); - fsWrite = () => fs.write(this.fd, this._writingBuf, this.release); - } else if (contentMode === void 0 || contentMode === kContentModeUtf8) { - this._writingBuf = ""; - this.write = write; - this.flush = flush; - this.flushSync = flushSync; - this._actualWrite = actualWrite; - fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf, "utf8"); - fsWrite = () => fs.write(this.fd, this._writingBuf, "utf8", this.release); - } else { - throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`); - } - if (typeof fd === "number") { - this.fd = fd; - process.nextTick(() => this.emit("ready")); - } else if (typeof fd === "string") { - openFile(fd, this); - } else { - throw new Error("SonicBoom supports only file descriptors and files"); - } - if (this.minLength >= this.maxWrite) { - throw new Error(`minLength should be smaller than maxWrite (${this.maxWrite})`); - } - this.release = (err, n) => { - if (err) { - if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) { - if (this.sync) { - try { - sleep(BUSY_WRITE_TIMEOUT); - this.release(void 0, 0); - } catch (err2) { - this.release(err2); + counts() { + return this._states.statusCounts(); + } + _randomIndex() { + return Math.random().toString(36).slice(2); + } + check(weight = 1) { + return this._store.__check__(weight); + } + _clearGlobalState(index) { + if (this._scheduled[index] != null) { + clearTimeout(this._scheduled[index].expiration); + delete this._scheduled[index]; + return true; + } else { + return false; + } + } + _free(index, job, options2, eventInfo) { + var _this = this; + return _asyncToGenerator2(function* () { + var e2, running; + try { + var _ref = yield _this._store.__free__(index, options2.weight); + running = _ref.running; + _this.Events.trigger("debug", `Freed ${options2.id}`, eventInfo); + if (running === 0 && _this.empty()) { + return _this.Events.trigger("idle"); + } + } catch (error1) { + e2 = error1; + return _this.Events.trigger("error", e2); + } + })(); + } + _run(index, job, wait) { + var clearGlobalState, free, run2; + job.doRun(); + clearGlobalState = this._clearGlobalState.bind(this, index); + run2 = this._run.bind(this, index, job); + free = this._free.bind(this, index, job); + return this._scheduled[index] = { + timeout: setTimeout(() => { + return job.doExecute(this._limiter, clearGlobalState, run2, free); + }, wait), + expiration: job.options.expiration != null ? setTimeout(function() { + return job.doExpire(clearGlobalState, run2, free); + }, wait + job.options.expiration) : void 0, + job + }; + } + _drainOne(capacity) { + return this._registerLock.schedule(() => { + var args, index, next, options2, queue; + if (this.queued() === 0) { + return this.Promise.resolve(null); + } + queue = this._queues.getFirst(); + var _next2 = next = queue.first(); + options2 = _next2.options; + args = _next2.args; + if (capacity != null && options2.weight > capacity) { + return this.Promise.resolve(null); + } + this.Events.trigger("debug", `Draining ${options2.id}`, { + args, + options: options2 + }); + index = this._randomIndex(); + return this._store.__register__(index, options2.weight, options2.expiration).then(({ + success, + wait, + reservoir + }) => { + var empty2; + this.Events.trigger("debug", `Drained ${options2.id}`, { + success, + args, + options: options2 + }); + if (success) { + queue.shift(); + empty2 = this.empty(); + if (empty2) { + this.Events.trigger("empty"); + } + if (reservoir === 0) { + this.Events.trigger("depleted", empty2); + } + this._run(index, next, wait); + return this.Promise.resolve(options2.weight); + } else { + return this.Promise.resolve(null); } + }); + }); + } + _drainAll(capacity, total = 0) { + return this._drainOne(capacity).then((drained) => { + var newCapacity; + if (drained != null) { + newCapacity = capacity != null ? capacity - drained : capacity; + return this._drainAll(newCapacity, total + drained); } else { - setTimeout(fsWrite, BUSY_WRITE_TIMEOUT); + return this.Promise.resolve(total); } - } else { - this._writing = false; - this.emit("error", err); - } - return; + }).catch((e2) => { + return this.Events.trigger("error", e2); + }); } - this.emit("write", n); - const releasedBufObj = releaseWritingBuf(this._writingBuf, this._len, n); - this._len = releasedBufObj.len; - this._writingBuf = releasedBufObj.writingBuf; - if (this._writingBuf.length) { - if (!this.sync) { - fsWrite(); - return; - } - try { - do { - const n2 = fsWriteSync(); - const releasedBufObj2 = releaseWritingBuf(this._writingBuf, this._len, n2); - this._len = releasedBufObj2.len; - this._writingBuf = releasedBufObj2.writingBuf; - } while (this._writingBuf.length); - } catch (err2) { - this.release(err2); - return; - } + _dropAllQueued(message) { + return this._queues.shiftAll(function(job) { + return job.doDrop({ + message + }); + }); } - if (this._fsync) { - fs.fsyncSync(this.fd); + stop(options2 = {}) { + var done, waitForExecuting; + options2 = parser3.load(options2, this.stopDefaults); + waitForExecuting = (at) => { + var finished; + finished = () => { + var counts; + counts = this._states.counts; + return counts[0] + counts[1] + counts[2] + counts[3] === at; + }; + return new this.Promise((resolve82, reject) => { + if (finished()) { + return resolve82(); + } else { + return this.on("done", () => { + if (finished()) { + this.removeAllListeners("done"); + return resolve82(); + } + }); + } + }); + }; + done = options2.dropWaitingJobs ? (this._run = function(index, next) { + return next.doDrop({ + message: options2.dropErrorMessage + }); + }, this._drainOne = () => { + return this.Promise.resolve(null); + }, this._registerLock.schedule(() => { + return this._submitLock.schedule(() => { + var k, ref, v2; + ref = this._scheduled; + for (k in ref) { + v2 = ref[k]; + if (this.jobStatus(v2.job.options.id) === "RUNNING") { + clearTimeout(v2.timeout); + clearTimeout(v2.expiration); + v2.job.doDrop({ + message: options2.dropErrorMessage + }); + } + } + this._dropAllQueued(options2.dropErrorMessage); + return waitForExecuting(0); + }); + })) : this.schedule({ + priority: NUM_PRIORITIES - 1, + weight: 0 + }, () => { + return waitForExecuting(1); + }); + this._receive = function(job) { + return job._reject(new Bottleneck3.prototype.BottleneckError(options2.enqueueErrorMessage)); + }; + this.stop = () => { + return this.Promise.reject(new Bottleneck3.prototype.BottleneckError("stop() has already been called")); + }; + return done; } - const len = this._len; - if (this._reopening) { - this._writing = false; - this._reopening = false; - this.reopen(); - } else if (len > this.minLength) { - this._actualWrite(); - } else if (this._ending) { - if (len > 0) { - this._actualWrite(); + _addToQueue(job) { + var _this2 = this; + return _asyncToGenerator2(function* () { + var args, blocked, error2, options2, reachedHWM, shifted, strategy; + args = job.args; + options2 = job.options; + try { + var _ref2 = yield _this2._store.__submit__(_this2.queued(), options2.weight); + reachedHWM = _ref2.reachedHWM; + blocked = _ref2.blocked; + strategy = _ref2.strategy; + } catch (error1) { + error2 = error1; + _this2.Events.trigger("debug", `Could not queue ${options2.id}`, { + args, + options: options2, + error: error2 + }); + job.doDrop({ + error: error2 + }); + return false; + } + if (blocked) { + job.doDrop(); + return true; + } else if (reachedHWM) { + shifted = strategy === Bottleneck3.prototype.strategy.LEAK ? _this2._queues.shiftLastFrom(options2.priority) : strategy === Bottleneck3.prototype.strategy.OVERFLOW_PRIORITY ? _this2._queues.shiftLastFrom(options2.priority + 1) : strategy === Bottleneck3.prototype.strategy.OVERFLOW ? job : void 0; + if (shifted != null) { + shifted.doDrop(); + } + if (shifted == null || strategy === Bottleneck3.prototype.strategy.OVERFLOW) { + if (shifted == null) { + job.doDrop(); + } + return reachedHWM; + } + } + job.doQueue(reachedHWM, blocked); + _this2._queues.push(job); + yield _this2._drainAll(); + return reachedHWM; + })(); + } + _receive(job) { + if (this._states.jobStatus(job.options.id) != null) { + job._reject(new Bottleneck3.prototype.BottleneckError(`A job with the same id already exists (id=${job.options.id})`)); + return false; } else { - this._writing = false; - actualClose(this); + job.doReceive(); + return this._submitLock.schedule(this._addToQueue, job); } - } else { - this._writing = false; - if (this.sync) { - if (!this._asyncDrainScheduled) { - this._asyncDrainScheduled = true; - process.nextTick(emitDrain, this); + } + submit(...args) { + var cb, fn, job, options2, ref, ref1, task; + if (typeof args[0] === "function") { + var _ref3, _ref4, _splice$call, _splice$call2; + ref = args, _ref3 = ref, _ref4 = _toArray(_ref3), fn = _ref4[0], args = _ref4.slice(1), _ref3, _splice$call = splice.call(args, -1), _splice$call2 = _slicedToArray2(_splice$call, 1), cb = _splice$call2[0], _splice$call; + options2 = parser3.load({}, this.jobDefaults); + } else { + var _ref5, _ref6, _splice$call3, _splice$call4; + ref1 = args, _ref5 = ref1, _ref6 = _toArray(_ref5), options2 = _ref6[0], fn = _ref6[1], args = _ref6.slice(2), _ref5, _splice$call3 = splice.call(args, -1), _splice$call4 = _slicedToArray2(_splice$call3, 1), cb = _splice$call4[0], _splice$call3; + options2 = parser3.load(options2, this.jobDefaults); + } + task = (...args2) => { + return new this.Promise(function(resolve82, reject) { + return fn(...args2, function(...args3) { + return (args3[0] != null ? reject : resolve82)(args3); + }); + }); + }; + job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + job.promise.then(function(args2) { + return typeof cb === "function" ? cb(...args2) : void 0; + }).catch(function(args2) { + if (Array.isArray(args2)) { + return typeof cb === "function" ? cb(...args2) : void 0; + } else { + return typeof cb === "function" ? cb(args2) : void 0; } + }); + return this._receive(job); + } + schedule(...args) { + var job, options2, task; + if (typeof args[0] === "function") { + var _args = args; + var _args2 = _toArray(_args); + task = _args2[0]; + args = _args2.slice(1); + options2 = {}; } else { - this.emit("drain"); + var _args3 = args; + var _args4 = _toArray(_args3); + options2 = _args4[0]; + task = _args4[1]; + args = _args4.slice(2); } + job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); + this._receive(job); + return job.promise; } - }; - this.on("newListener", function(name) { - if (name === "drain") { - this._asyncDrainScheduled = false; + wrap(fn) { + var schedule, wrapped; + schedule = this.schedule.bind(this); + wrapped = function wrapped2(...args) { + return schedule(fn.bind(this), ...args); + }; + wrapped.withOptions = function(options2, ...args) { + return schedule(options2, fn, ...args); + }; + return wrapped; } - }); - } - function releaseWritingBuf(writingBuf, len, n) { - if (typeof writingBuf === "string" && Buffer.byteLength(writingBuf) !== n) { - n = Buffer.from(writingBuf).subarray(0, n).toString().length; - } - len = Math.max(len - n, 0); - writingBuf = writingBuf.slice(n); - return { writingBuf, len }; - } - function emitDrain(sonic) { - const hasListeners = sonic.listenerCount("drain") > 0; - if (!hasListeners) return; - sonic._asyncDrainScheduled = false; - sonic.emit("drain"); - } - inherits(SonicBoom, EventEmitter); - function mergeBuf(bufs, len) { - if (bufs.length === 0) { - return kEmptyBuffer; - } - if (bufs.length === 1) { - return bufs[0]; - } - return Buffer.concat(bufs, len); - } - function write(data) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - const len = this._len + data.length; - const bufs = this._bufs; - if (this.maxLength && len > this.maxLength) { - this.emit("drop", data); - return this._len < this._hwm; - } - if (bufs.length === 0 || bufs[bufs.length - 1].length + data.length > this.maxWrite) { - bufs.push("" + data); - } else { - bufs[bufs.length - 1] += data; - } - this._len = len; - if (!this._writing && this._len >= this.minLength) { - this._actualWrite(); - } - return this._len < this._hwm; - } - function writeBuffer(data) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - const len = this._len + data.length; - const bufs = this._bufs; - const lens = this._lens; - if (this.maxLength && len > this.maxLength) { - this.emit("drop", data); - return this._len < this._hwm; - } - if (bufs.length === 0 || lens[lens.length - 1] + data.length > this.maxWrite) { - bufs.push([data]); - lens.push(data.length); - } else { - bufs[bufs.length - 1].push(data); - lens[lens.length - 1] += data.length; - } - this._len = len; - if (!this._writing && this._len >= this.minLength) { - this._actualWrite(); - } - return this._len < this._hwm; - } - function callFlushCallbackOnDrain(cb) { - this._flushPending = true; - const onDrain = () => { - if (!this._fsync) { - fs.fsync(this.fd, (err) => { - this._flushPending = false; - cb(err); - }); - } else { - this._flushPending = false; - cb(); + updateSettings(options2 = {}) { + var _this3 = this; + return _asyncToGenerator2(function* () { + yield _this3._store.__updateSettings__(parser3.overwrite(options2, _this3.storeDefaults)); + parser3.overwrite(options2, _this3.instanceDefaults, _this3); + return _this3; + })(); } - this.off("error", onError); - }; - const onError = (err) => { - this._flushPending = false; - cb(err); - this.off("drain", onDrain); - }; - this.once("drain", onDrain); - this.once("error", onError); - } - function flush(cb) { - if (cb != null && typeof cb !== "function") { - throw new Error("flush cb must be a function"); - } - if (this.destroyed) { - const error2 = new Error("SonicBoom destroyed"); - if (cb) { - cb(error2); - return; + currentReservoir() { + return this._store.__currentReservoir__(); + } + incrementReservoir(incr = 0) { + return this._store.__incrementReservoir__(incr); } - throw error2; } - if (this.minLength <= 0) { - cb?.(); - return; - } - if (cb) { - callFlushCallbackOnDrain.call(this, cb); - } - if (this._writing) { - return; - } - if (this._bufs.length === 0) { - this._bufs.push(""); - } - this._actualWrite(); - } - function flushBuffer(cb) { - if (cb != null && typeof cb !== "function") { - throw new Error("flush cb must be a function"); - } - if (this.destroyed) { - const error2 = new Error("SonicBoom destroyed"); - if (cb) { - cb(error2); - return; - } - throw error2; - } - if (this.minLength <= 0) { - cb?.(); - return; - } - if (cb) { - callFlushCallbackOnDrain.call(this, cb); - } - if (this._writing) { - return; - } - if (this._bufs.length === 0) { - this._bufs.push([]); - this._lens.push(0); - } - this._actualWrite(); - } - SonicBoom.prototype.reopen = function(file) { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); - } - if (this._opening) { - this.once("ready", () => { - this.reopen(file); - }); - return; - } - if (this._ending) { - return; - } - if (!this.file) { - throw new Error("Unable to reopen a file descriptor, you must pass a file to SonicBoom"); - } - if (file) { - this.file = file; - } - this._reopening = true; - if (this._writing) { - return; - } - const fd = this.fd; - this.once("ready", () => { - if (fd !== this.fd) { - fs.close(fd, (err) => { - if (err) { - return this.emit("error", err); - } - }); - } - }); - openFile(this.file, this); + ; + Bottleneck3.default = Bottleneck3; + Bottleneck3.Events = Events2; + Bottleneck3.version = Bottleneck3.prototype.version = require_version().version; + Bottleneck3.strategy = Bottleneck3.prototype.strategy = { + LEAK: 1, + OVERFLOW: 2, + OVERFLOW_PRIORITY: 4, + BLOCK: 3 + }; + Bottleneck3.BottleneckError = Bottleneck3.prototype.BottleneckError = require_BottleneckError(); + Bottleneck3.Group = Bottleneck3.prototype.Group = require_Group(); + Bottleneck3.RedisConnection = Bottleneck3.prototype.RedisConnection = require_RedisConnection(); + Bottleneck3.IORedisConnection = Bottleneck3.prototype.IORedisConnection = require_IORedisConnection(); + Bottleneck3.Batcher = Bottleneck3.prototype.Batcher = require_Batcher(); + Bottleneck3.prototype.jobDefaults = { + priority: DEFAULT_PRIORITY, + weight: 1, + expiration: null, + id: "" + }; + Bottleneck3.prototype.storeDefaults = { + maxConcurrent: null, + minTime: 0, + highWater: null, + strategy: Bottleneck3.prototype.strategy.LEAK, + penalty: null, + reservoir: null, + reservoirRefreshInterval: null, + reservoirRefreshAmount: null, + reservoirIncreaseInterval: null, + reservoirIncreaseAmount: null, + reservoirIncreaseMaximum: null + }; + Bottleneck3.prototype.localStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 250 + }; + Bottleneck3.prototype.redisStoreDefaults = { + Promise, + timeout: null, + heartbeatInterval: 5e3, + clientTimeout: 1e4, + Redis: null, + clientOptions: {}, + clusterNodes: null, + clearDatastore: false, + connection: null + }; + Bottleneck3.prototype.instanceDefaults = { + datastore: "local", + connection: null, + id: "", + rejectOnDrop: true, + trackDoneStatus: false, + Promise + }; + Bottleneck3.prototype.stopDefaults = { + enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", + dropWaitingJobs: true, + dropErrorMessage: "This limiter has been stopped." + }; + return Bottleneck3; + }.call(void 0); + module14.exports = Bottleneck2; + } +}); +var require_lib6 = __commonJS({ + "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/index.js"(exports2, module14) { + "use strict"; + module14.exports = require_Bottleneck(); + } +}); +var require_err_helpers = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-helpers.js"(exports2, module14) { + "use strict"; + var isErrorLike = (err) => { + return err && typeof err.message === "string"; }; - SonicBoom.prototype.end = function() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); + var getErrorCause = (err) => { + if (!err) return; + const cause = err.cause; + if (typeof cause === "function") { + const causeResult = err.cause(); + return isErrorLike(causeResult) ? causeResult : void 0; + } else { + return isErrorLike(cause) ? cause : void 0; } - if (this._opening) { - this.once("ready", () => { - this.end(); - }); - return; + }; + var _stackWithCauses = (err, seen) => { + if (!isErrorLike(err)) return ""; + const stack = err.stack || ""; + if (seen.has(err)) { + return stack + "\ncauses have become circular..."; } - if (this._ending) { - return; + const cause = getErrorCause(err); + if (cause) { + seen.add(err); + return stack + "\ncaused by: " + _stackWithCauses(cause, seen); + } else { + return stack; } - this._ending = true; - if (this._writing) { - return; + }; + var stackWithCauses = (err) => _stackWithCauses(err, /* @__PURE__ */ new Set()); + var _messageWithCauses = (err, seen, skip) => { + if (!isErrorLike(err)) return ""; + const message = skip ? "" : err.message || ""; + if (seen.has(err)) { + return message + ": ..."; } - if (this._len > 0 && this.fd >= 0) { - this._actualWrite(); + const cause = getErrorCause(err); + if (cause) { + seen.add(err); + const skipIfVErrorStyleCause = typeof err.cause === "function"; + return message + (skipIfVErrorStyleCause ? "" : ": ") + _messageWithCauses(cause, seen, skipIfVErrorStyleCause); } else { - actualClose(this); + return message; } }; - function flushSync() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); + var messageWithCauses = (err) => _messageWithCauses(err, /* @__PURE__ */ new Set()); + module14.exports = { + isErrorLike, + getErrorCause, + stackWithCauses, + messageWithCauses + }; + } +}); +var require_err_proto = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-proto.js"(exports2, module14) { + "use strict"; + var seen = Symbol("circular-ref-tag"); + var rawSymbol = Symbol("pino-raw-err-ref"); + var pinoErrProto = Object.create({}, { + type: { + enumerable: true, + writable: true, + value: void 0 + }, + message: { + enumerable: true, + writable: true, + value: void 0 + }, + stack: { + enumerable: true, + writable: true, + value: void 0 + }, + aggregateErrors: { + enumerable: true, + writable: true, + value: void 0 + }, + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; + }, + set: function(val) { + this[rawSymbol] = val; + } } - if (this.fd < 0) { - throw new Error("sonic boom is not ready yet"); + }); + Object.defineProperty(pinoErrProto, rawSymbol, { + writable: true, + value: {} + }); + module14.exports = { + pinoErrProto, + pinoErrorSymbols: { + seen, + rawSymbol } - if (!this._writing && this._writingBuf.length > 0) { - this._bufs.unshift(this._writingBuf); - this._writingBuf = ""; + }; + } +}); +var require_err = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err.js"(exports2, module14) { + "use strict"; + module14.exports = errSerializer; + var { messageWithCauses, stackWithCauses, isErrorLike } = require_err_helpers(); + var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); + var { seen } = pinoErrorSymbols; + var { toString } = Object.prototype; + function errSerializer(err) { + if (!isErrorLike(err)) { + return err; } - let buf2 = ""; - while (this._bufs.length || buf2) { - if (buf2.length <= 0) { - buf2 = this._bufs[0]; - } - try { - const n = fs.writeSync(this.fd, buf2, "utf8"); - const releasedBufObj = releaseWritingBuf(buf2, this._len, n); - buf2 = releasedBufObj.writingBuf; - this._len = releasedBufObj.len; - if (buf2.length <= 0) { - this._bufs.shift(); - } - } catch (err) { - const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; - if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { - throw err; + err[seen] = void 0; + const _err = Object.create(pinoErrProto); + _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; + _err.message = messageWithCauses(err); + _err.stack = stackWithCauses(err); + if (Array.isArray(err.errors)) { + _err.aggregateErrors = err.errors.map((err2) => errSerializer(err2)); + } + for (const key in err) { + if (_err[key] === void 0) { + const val = err[key]; + if (isErrorLike(val)) { + if (key !== "cause" && !Object.prototype.hasOwnProperty.call(val, seen)) { + _err[key] = errSerializer(val); + } + } else { + _err[key] = val; } - sleep(BUSY_WRITE_TIMEOUT); } } - try { - fs.fsyncSync(this.fd); - } catch { - } + delete err[seen]; + _err.raw = err; + return _err; } - function flushBufferSync() { - if (this.destroyed) { - throw new Error("SonicBoom destroyed"); + } +}); +var require_err_with_cause = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/err-with-cause.js"(exports2, module14) { + "use strict"; + module14.exports = errWithCauseSerializer; + var { isErrorLike } = require_err_helpers(); + var { pinoErrProto, pinoErrorSymbols } = require_err_proto(); + var { seen } = pinoErrorSymbols; + var { toString } = Object.prototype; + function errWithCauseSerializer(err) { + if (!isErrorLike(err)) { + return err; } - if (this.fd < 0) { - throw new Error("sonic boom is not ready yet"); + err[seen] = void 0; + const _err = Object.create(pinoErrProto); + _err.type = toString.call(err.constructor) === "[object Function]" ? err.constructor.name : err.name; + _err.message = err.message; + _err.stack = err.stack; + if (Array.isArray(err.errors)) { + _err.aggregateErrors = err.errors.map((err2) => errWithCauseSerializer(err2)); } - if (!this._writing && this._writingBuf.length > 0) { - this._bufs.unshift([this._writingBuf]); - this._writingBuf = kEmptyBuffer; + if (isErrorLike(err.cause) && !Object.prototype.hasOwnProperty.call(err.cause, seen)) { + _err.cause = errWithCauseSerializer(err.cause); } - let buf2 = kEmptyBuffer; - while (this._bufs.length || buf2.length) { - if (buf2.length <= 0) { - buf2 = mergeBuf(this._bufs[0], this._lens[0]); - } - try { - const n = fs.writeSync(this.fd, buf2); - buf2 = buf2.subarray(n); - this._len = Math.max(this._len - n, 0); - if (buf2.length <= 0) { - this._bufs.shift(); - this._lens.shift(); - } - } catch (err) { - const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; - if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { - throw err; + for (const key in err) { + if (_err[key] === void 0) { + const val = err[key]; + if (isErrorLike(val)) { + if (!Object.prototype.hasOwnProperty.call(val, seen)) { + _err[key] = errWithCauseSerializer(val); + } + } else { + _err[key] = val; } - sleep(BUSY_WRITE_TIMEOUT); } } + delete err[seen]; + _err.raw = err; + return _err; } - SonicBoom.prototype.destroy = function() { - if (this.destroyed) { - return; - } - actualClose(this); + } +}); +var require_req = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/req.js"(exports2, module14) { + "use strict"; + module14.exports = { + mapHttpRequest, + reqSerializer }; - function actualWrite() { - const release = this.release; - this._writing = true; - this._writingBuf = this._writingBuf || this._bufs.shift() || ""; - if (this.sync) { - try { - const written = fs.writeSync(this.fd, this._writingBuf, "utf8"); - release(null, written); - } catch (err) { - release(err); + var rawSymbol = Symbol("pino-raw-req-ref"); + var pinoReqProto = Object.create({}, { + id: { + enumerable: true, + writable: true, + value: "" + }, + method: { + enumerable: true, + writable: true, + value: "" + }, + url: { + enumerable: true, + writable: true, + value: "" + }, + query: { + enumerable: true, + writable: true, + value: "" + }, + params: { + enumerable: true, + writable: true, + value: "" + }, + headers: { + enumerable: true, + writable: true, + value: {} + }, + remoteAddress: { + enumerable: true, + writable: true, + value: "" + }, + remotePort: { + enumerable: true, + writable: true, + value: "" + }, + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; + }, + set: function(val) { + this[rawSymbol] = val; } - } else { - fs.write(this.fd, this._writingBuf, "utf8", release); } - } - function actualWriteBuffer() { - const release = this.release; - this._writing = true; - this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift()); - if (this.sync) { - try { - const written = fs.writeSync(this.fd, this._writingBuf); - release(null, written); - } catch (err) { - release(err); - } + }); + Object.defineProperty(pinoReqProto, rawSymbol, { + writable: true, + value: {} + }); + function reqSerializer(req) { + const connection = req.info || req.socket; + const _req = Object.create(pinoReqProto); + _req.id = typeof req.id === "function" ? req.id() : req.id || (req.info ? req.info.id : void 0); + _req.method = req.method; + if (req.originalUrl) { + _req.url = req.originalUrl; } else { - fs.write(this.fd, this._writingBuf, release); - } - } - function actualClose(sonic) { - if (sonic.fd === -1) { - sonic.once("ready", actualClose.bind(null, sonic)); - return; + const path8 = req.path; + _req.url = typeof path8 === "string" ? path8 : req.url ? req.url.path || req.url : void 0; } - sonic.destroyed = true; - sonic._bufs = []; - sonic._lens = []; - fs.fsync(sonic.fd, closeWrapped); - function closeWrapped() { - if (sonic.fd !== 1 && sonic.fd !== 2) { - fs.close(sonic.fd, done); - } else { - done(); - } + if (req.query) { + _req.query = req.query; } - function done(err) { - if (err) { - sonic.emit("error", err); - return; - } - if (sonic._ending && !sonic._writing) { - sonic.emit("finish"); - } - sonic.emit("close"); + if (req.params) { + _req.params = req.params; } - } - SonicBoom.SonicBoom = SonicBoom; - SonicBoom.default = SonicBoom; - module14.exports = SonicBoom; + _req.headers = req.headers; + _req.remoteAddress = connection && connection.remoteAddress; + _req.remotePort = connection && connection.remotePort; + _req.raw = req.raw || req; + return _req; + } + function mapHttpRequest(req) { + return { + req: reqSerializer(req) + }; + } } }); -var require_on_exit_leak_free = __commonJS({ - "node_modules/.deno/on-exit-leak-free@2.1.2/node_modules/on-exit-leak-free/index.js"(exports2, module14) { +var require_res = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/lib/res.js"(exports2, module14) { "use strict"; - var refs = { - exit: [], - beforeExit: [] - }; - var functions = { - exit: onExit, - beforeExit: onBeforeExit + module14.exports = { + mapHttpResponse, + resSerializer }; - var registry2; - function ensureRegistry() { - if (registry2 === void 0) { - registry2 = new FinalizationRegistry(clear); - } - } - function install(event) { - if (refs[event].length > 0) { - return; - } - process.on(event, functions[event]); - } - function uninstall(event) { - if (refs[event].length > 0) { - return; - } - process.removeListener(event, functions[event]); - if (refs.exit.length === 0 && refs.beforeExit.length === 0) { - registry2 = void 0; - } - } - function onExit() { - callRefs("exit"); - } - function onBeforeExit() { - callRefs("beforeExit"); - } - function callRefs(event) { - for (const ref of refs[event]) { - const obj = ref.deref(); - const fn = ref.fn; - if (obj !== void 0) { - fn(obj, event); + var rawSymbol = Symbol("pino-raw-res-ref"); + var pinoResProto = Object.create({}, { + statusCode: { + enumerable: true, + writable: true, + value: 0 + }, + headers: { + enumerable: true, + writable: true, + value: "" + }, + raw: { + enumerable: false, + get: function() { + return this[rawSymbol]; + }, + set: function(val) { + this[rawSymbol] = val; } } - refs[event] = []; - } - function clear(ref) { - for (const event of ["exit", "beforeExit"]) { - const index = refs[event].indexOf(ref); - refs[event].splice(index, index + 1); - uninstall(event); - } - } - function _register(event, obj, fn) { - if (obj === void 0) { - throw new Error("the object can't be undefined"); - } - install(event); - const ref = new WeakRef(obj); - ref.fn = fn; - ensureRegistry(); - registry2.register(obj, ref); - refs[event].push(ref); - } - function register2(obj, fn) { - _register("exit", obj, fn); - } - function registerBeforeExit(obj, fn) { - _register("beforeExit", obj, fn); + }); + Object.defineProperty(pinoResProto, rawSymbol, { + writable: true, + value: {} + }); + function resSerializer(res) { + const _res = Object.create(pinoResProto); + _res.statusCode = res.headersSent ? res.statusCode : null; + _res.headers = res.getHeaders ? res.getHeaders() : res._headers; + _res.raw = res; + return _res; } - function unregister(obj) { - if (registry2 === void 0) { - return; - } - registry2.unregister(obj); - for (const event of ["exit", "beforeExit"]) { - refs[event] = refs[event].filter((ref) => { - const _obj = ref.deref(); - return _obj && _obj !== obj; - }); - uninstall(event); - } + function mapHttpResponse(res) { + return { + res: resSerializer(res) + }; } - module14.exports = { - register: register2, - registerBeforeExit, - unregister - }; } }); -var require_package3 = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/package.json"(exports2, module14) { +var require_pino_std_serializers = __commonJS({ + "node_modules/.deno/pino-std-serializers@6.2.2/node_modules/pino-std-serializers/index.js"(exports2, module14) { + "use strict"; + var errSerializer = require_err(); + var errWithCauseSerializer = require_err_with_cause(); + var reqSerializers = require_req(); + var resSerializers = require_res(); module14.exports = { - name: "thread-stream", - version: "2.7.0", - description: "A streaming way to send data to a Node.js Worker Thread", - main: "index.js", - types: "index.d.ts", - dependencies: { - "real-require": "^0.2.0" - }, - devDependencies: { - "@types/node": "^20.1.0", - "@types/tap": "^15.0.0", - "@yao-pkg/pkg": "^5.11.5", - desm: "^1.3.0", - fastbench: "^1.0.1", - husky: "^9.0.6", - "pino-elasticsearch": "^8.0.0", - "sonic-boom": "^3.0.0", - standard: "^17.0.0", - tap: "^16.2.0", - "ts-node": "^10.8.0", - typescript: "^5.3.2", - "why-is-node-running": "^2.2.2" - }, - scripts: { - test: 'standard && npm run transpile && tap "test/**/*.test.*js" && tap --ts test/*.test.*ts', - "test:ci": "standard && npm run transpile && npm run test:ci:js && npm run test:ci:ts", - "test:ci:js": 'tap --no-check-coverage --timeout=120 --coverage-report=lcovonly "test/**/*.test.*js"', - "test:ci:ts": 'tap --ts --no-check-coverage --coverage-report=lcovonly "test/**/*.test.*ts"', - "test:yarn": 'npm run transpile && tap "test/**/*.test.js" --no-check-coverage', - transpile: "sh ./test/ts/transpile.sh", - prepare: "husky install" - }, - standard: { - ignore: [ - "test/ts/**/*" - ] - }, - repository: { - type: "git", - url: "git+https://github.com/mcollina/thread-stream.git" + err: errSerializer, + errWithCause: errWithCauseSerializer, + mapHttpRequest: reqSerializers.mapHttpRequest, + mapHttpResponse: resSerializers.mapHttpResponse, + req: reqSerializers.reqSerializer, + res: resSerializers.resSerializer, + wrapErrorSerializer: function wrapErrorSerializer(customSerializer) { + if (customSerializer === errSerializer) return customSerializer; + return function wrapErrSerializer(err) { + return customSerializer(errSerializer(err)); + }; }, - keywords: [ - "worker", - "thread", - "threads", - "stream" - ], - author: "Matteo Collina ", - license: "MIT", - bugs: { - url: "https://github.com/mcollina/thread-stream/issues" + wrapRequestSerializer: function wrapRequestSerializer(customSerializer) { + if (customSerializer === reqSerializers.reqSerializer) return customSerializer; + return function wrappedReqSerializer(req) { + return customSerializer(reqSerializers.reqSerializer(req)); + }; }, - homepage: "https://github.com/mcollina/thread-stream#readme" + wrapResponseSerializer: function wrapResponseSerializer(customSerializer) { + if (customSerializer === resSerializers.resSerializer) return customSerializer; + return function wrappedResSerializer(res) { + return customSerializer(resSerializers.resSerializer(res)); + }; + } }; } }); -var require_wait = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/wait.js"(exports2, module14) { +var require_caller = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/caller.js"(exports2, module14) { "use strict"; - var MAX_TIMEOUT = 1e3; - function wait(state, index, expected, timeout, done) { - const max = Date.now() + timeout; - let current = Atomics.load(state, index); - if (current === expected) { - done(null, "ok"); - return; - } - let prior = current; - const check2 = (backoff) => { - if (Date.now() > max) { - done(null, "timed-out"); - } else { - setTimeout(() => { - prior = current; - current = Atomics.load(state, index); - if (current === prior) { - check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); - } else { - if (current === expected) done(null, "ok"); - else done(null, "not-equal"); - } - }, backoff); - } - }; - check2(1); + function noOpPrepareStackTrace(_, stack) { + return stack; } - function waitDiff(state, index, expected, timeout, done) { - const max = Date.now() + timeout; - let current = Atomics.load(state, index); - if (current !== expected) { - done(null, "ok"); - return; + module14.exports = function getCallers() { + const originalPrepare = Error.prepareStackTrace; + Error.prepareStackTrace = noOpPrepareStackTrace; + const stack = new Error().stack; + Error.prepareStackTrace = originalPrepare; + if (!Array.isArray(stack)) { + return void 0; } - const check2 = (backoff) => { - if (Date.now() > max) { - done(null, "timed-out"); - } else { - setTimeout(() => { - current = Atomics.load(state, index); - if (current !== expected) { - done(null, "ok"); - } else { - check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); - } - }, backoff); + const entries = stack.slice(2); + const fileNames = []; + for (const entry of entries) { + if (!entry) { + continue; } + fileNames.push(entry.getFileName()); + } + return fileNames; + }; + } +}); +var require_validator = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/validator.js"(exports2, module14) { + "use strict"; + module14.exports = validator2; + function validator2(opts = {}) { + const { + ERR_PATHS_MUST_BE_STRINGS = () => "fast-redact - Paths must be (non-empty) strings", + ERR_INVALID_PATH = (s) => `fast-redact \u2013 Invalid path (${s})` + } = opts; + return function validate({ paths }) { + paths.forEach((s) => { + if (typeof s !== "string") { + throw Error(ERR_PATHS_MUST_BE_STRINGS()); + } + try { + if (/〇/.test(s)) throw Error(); + const expr = (s[0] === "[" ? "" : ".") + s.replace(/^\*/, "\u3007").replace(/\.\*/g, ".\u3007").replace(/\[\*\]/g, "[\u3007]"); + if (/\n|\r|;/.test(expr)) throw Error(); + if (/\/\*/.test(expr)) throw Error(); + Function(` + 'use strict' + const o = new Proxy({}, { get: () => o, set: () => { throw Error() } }); + const \u3007 = null; + o${expr} + if ([o${expr}].length !== 1) throw Error()`)(); + } catch (e2) { + throw Error(ERR_INVALID_PATH(s)); + } + }); }; - check2(1); } - module14.exports = { wait, waitDiff }; } }); -var require_indexes = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/indexes.js"(exports2, module14) { +var require_rx = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/rx.js"(exports2, module14) { "use strict"; - var WRITE_INDEX = 4; - var READ_INDEX = 8; - module14.exports = { - WRITE_INDEX, - READ_INDEX - }; + module14.exports = /[^.[\]]+|\[((?:.)*?)\]/g; } }); -var require_thread_stream = __commonJS({ - "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports2, module14) { +var require_parse = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/parse.js"(exports2, module14) { "use strict"; - var { version: version3 } = require_package3(); - var { EventEmitter } = __require2("events"); - var { Worker: Worker2 } = __require2("worker_threads"); - var { join: join10 } = __require2("path"); - var { pathToFileURL: pathToFileURL2 } = __require2("url"); - var { wait } = require_wait(); - var { - WRITE_INDEX, - READ_INDEX - } = require_indexes(); - var buffer = __require2("buffer"); - var assert2 = __require2("assert"); - var kImpl = Symbol("kImpl"); - var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; - var FakeWeakRef = class { - constructor(value) { - this._value = value; - } - deref() { - return this._value; - } - }; - var FakeFinalizationRegistry = class { - register() { - } - unregister() { - } - }; - var FinalizationRegistry2 = process.env.NODE_V8_COVERAGE ? FakeFinalizationRegistry : global.FinalizationRegistry || FakeFinalizationRegistry; - var WeakRef2 = process.env.NODE_V8_COVERAGE ? FakeWeakRef : global.WeakRef || FakeWeakRef; - var registry2 = new FinalizationRegistry2((worker) => { - if (worker.exited) { - return; - } - worker.terminate(); - }); - function createWorker2(stream, opts) { - const { filename, workerData } = opts; - const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; - const toExecute = bundlerOverrides["thread-stream-worker"] || join10(__dirname, "lib", "worker.js"); - const worker = new Worker2(toExecute, { - ...opts.workerOpts, - trackUnmanagedFds: false, - workerData: { - filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, - dataBuf: stream[kImpl].dataBuf, - stateBuf: stream[kImpl].stateBuf, - workerData: { - $context: { - threadStreamVersion: version3 - }, - ...workerData - } + var rx = require_rx(); + module14.exports = parse62; + function parse62({ paths }) { + const wildcards = []; + var wcLen = 0; + const secret = paths.reduce(function(o2, strPath, ix) { + var path8 = strPath.match(rx).map((p) => p.replace(/'|"|`/g, "")); + const leadingBracket = strPath[0] === "["; + path8 = path8.map((p) => { + if (p[0] === "[") return p.substr(1, p.length - 2); + else return p; + }); + const star = path8.indexOf("*"); + if (star > -1) { + const before = path8.slice(0, star); + const beforeStr = before.join("."); + const after = path8.slice(star + 1, path8.length); + const nested = after.length > 0; + wcLen++; + wildcards.push({ + before, + beforeStr, + after, + nested + }); + } else { + o2[strPath] = { + path: path8, + val: void 0, + precensored: false, + circle: "", + escPath: JSON.stringify(strPath), + leadingBracket + }; } - }); - worker.stream = new FakeWeakRef(stream); - worker.on("message", onWorkerMessage); - worker.on("exit", onWorkerExit); - registry2.register(stream, worker); - return worker; + return o2; + }, {}); + return { wildcards, wcLen, secret }; } - function drain(stream) { - assert2(!stream[kImpl].sync); - if (stream[kImpl].needDrain) { - stream[kImpl].needDrain = false; - stream.emit("drain"); + } +}); +var require_redactor = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/redactor.js"(exports2, module14) { + "use strict"; + var rx = require_rx(); + module14.exports = redactor; + function redactor({ secret, serialize: serialize2, wcLen, strict, isCensorFct, censorFctTakesPath }, state) { + const redact = Function("o", ` + if (typeof o !== 'object' || o == null) { + ${strictImpl(strict, serialize2)} + } + const { censor, secret } = this + const originalSecret = {} + const secretKeys = Object.keys(secret) + for (var i = 0; i < secretKeys.length; i++) { + originalSecret[secretKeys[i]] = secret[secretKeys[i]] + } + + ${redactTmpl(secret, isCensorFct, censorFctTakesPath)} + this.compileRestore() + ${dynamicRedactTmpl(wcLen > 0, isCensorFct, censorFctTakesPath)} + this.secret = originalSecret + ${resultTmpl(serialize2)} + `).bind(state); + redact.state = state; + if (serialize2 === false) { + redact.restore = (o2) => state.restore(o2); } + return redact; } - function nextFlush(stream) { - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let leftover = stream[kImpl].data.length - writeIndex; - if (leftover > 0) { - if (stream[kImpl].buf.length === 0) { - stream[kImpl].flushing = false; - if (stream[kImpl].ending) { - end(stream); - } else if (stream[kImpl].needDrain) { - process.nextTick(drain, stream); - } - return; + function redactTmpl(secret, isCensorFct, censorFctTakesPath) { + return Object.keys(secret).map((path8) => { + const { escPath, leadingBracket, path: arrPath } = secret[path8]; + const skip = leadingBracket ? 1 : 0; + const delim = leadingBracket ? "" : "."; + const hops = []; + var match2; + while ((match2 = rx.exec(path8)) !== null) { + const [, ix] = match2; + const { index, input } = match2; + if (index > skip) hops.push(input.substring(0, index - (ix ? 0 : 1))); } - let toWrite = stream[kImpl].buf.slice(0, leftover); - let toWriteBytes = Buffer.byteLength(toWrite); - if (toWriteBytes <= leftover) { - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, nextFlush.bind(null, stream)); + var existence = hops.map((p) => `o${delim}${p}`).join(" && "); + if (existence.length === 0) existence += `o${delim}${path8} != null`; + else existence += ` && o${delim}${path8} != null`; + const circularDetection = ` + switch (true) { + ${hops.reverse().map((p) => ` + case o${delim}${p} === censor: + secret[${escPath}].circle = ${JSON.stringify(p)} + break + `).join("\n")} + } + `; + const censorArgs = censorFctTakesPath ? `val, ${JSON.stringify(arrPath)}` : `val`; + return ` + if (${existence}) { + const val = o${delim}${path8} + if (val === censor) { + secret[${escPath}].precensored = true } else { - stream.flush(() => { - if (stream.destroyed) { - return; - } - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - while (toWriteBytes > stream[kImpl].data.length) { - leftover = leftover / 2; - toWrite = stream[kImpl].buf.slice(0, leftover); - toWriteBytes = Buffer.byteLength(toWrite); - } - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, nextFlush.bind(null, stream)); - }); - } - } else if (leftover === 0) { - if (writeIndex === 0 && stream[kImpl].buf.length === 0) { - return; + secret[${escPath}].val = val + o${delim}${path8} = ${isCensorFct ? `censor(${censorArgs})` : "censor"} + ${circularDetection} } - stream.flush(() => { - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - nextFlush(stream); - }); - } else { - destroy(stream, new Error("overwritten")); } + `; + }).join("\n"); } - function onWorkerMessage(msg) { - const stream = this.stream.deref(); - if (stream === void 0) { - this.exited = true; - this.terminate(); - return; - } - switch (msg.code) { - case "READY": - this.stream = new WeakRef2(stream); - stream.flush(() => { - stream[kImpl].ready = true; - stream.emit("ready"); - }); - break; - case "ERROR": - destroy(stream, msg.err); - break; - case "EVENT": - if (Array.isArray(msg.args)) { - stream.emit(msg.name, ...msg.args); - } else { - stream.emit(msg.name, msg.args); - } - break; - case "WARNING": - process.emitWarning(msg.err); - break; - default: - destroy(stream, new Error("this should not happen: " + msg.code)); + function dynamicRedactTmpl(hasWildcards, isCensorFct, censorFctTakesPath) { + return hasWildcards === true ? ` + { + const { wildcards, wcLen, groupRedact, nestedRedact } = this + for (var i = 0; i < wcLen; i++) { + const { before, beforeStr, after, nested } = wildcards[i] + if (nested === true) { + secret[beforeStr] = secret[beforeStr] || [] + nestedRedact(secret[beforeStr], o, before, after, censor, ${isCensorFct}, ${censorFctTakesPath}) + } else secret[beforeStr] = groupRedact(o, before, censor, ${isCensorFct}, ${censorFctTakesPath}) } } - function onWorkerExit(code2) { - const stream = this.stream.deref(); - if (stream === void 0) { - return; + ` : ""; + } + function resultTmpl(serialize2) { + return serialize2 === false ? `return o` : ` + var s = this.serialize(o) + this.restore(o) + return s + `; + } + function strictImpl(strict, serialize2) { + return strict === true ? `throw Error('fast-redact: primitives cannot be redacted')` : serialize2 === false ? `return o` : `return this.serialize(o)`; + } + } +}); +var require_modifiers = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/modifiers.js"(exports2, module14) { + "use strict"; + module14.exports = { + groupRedact, + groupRestore, + nestedRedact, + nestedRestore + }; + function groupRestore({ keys, values, target }) { + if (target == null || typeof target === "string") return; + const length2 = keys.length; + for (var i2 = 0; i2 < length2; i2++) { + const k = keys[i2]; + target[k] = values[i2]; } - registry2.unregister(stream); - stream.worker.exited = true; - stream.worker.off("exit", onWorkerExit); - destroy(stream, code2 !== 0 ? new Error("the worker thread exited") : null); } - var ThreadStream = class extends EventEmitter { - constructor(opts = {}) { - super(); - if (opts.bufferSize < 4) { - throw new Error("bufferSize must at least fit a 4-byte utf-8 char"); + function groupRedact(o2, path8, censor, isCensorFct, censorFctTakesPath) { + const target = get2(o2, path8); + if (target == null || typeof target === "string") return { keys: null, values: null, target, flat: true }; + const keys = Object.keys(target); + const keysLength = keys.length; + const pathLength = path8.length; + const pathWithKey = censorFctTakesPath ? [...path8] : void 0; + const values = new Array(keysLength); + for (var i2 = 0; i2 < keysLength; i2++) { + const key = keys[i2]; + values[i2] = target[key]; + if (censorFctTakesPath) { + pathWithKey[pathLength] = key; + target[key] = censor(target[key], pathWithKey); + } else if (isCensorFct) { + target[key] = censor(target[key]); + } else { + target[key] = censor; } - this[kImpl] = {}; - this[kImpl].stateBuf = new SharedArrayBuffer(128); - this[kImpl].state = new Int32Array(this[kImpl].stateBuf); - this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024); - this[kImpl].data = Buffer.from(this[kImpl].dataBuf); - this[kImpl].sync = opts.sync || false; - this[kImpl].ending = false; - this[kImpl].ended = false; - this[kImpl].needDrain = false; - this[kImpl].destroyed = false; - this[kImpl].flushing = false; - this[kImpl].ready = false; - this[kImpl].finished = false; - this[kImpl].errored = null; - this[kImpl].closed = false; - this[kImpl].buf = ""; - this.worker = createWorker2(this, opts); - this.on("message", (message, transferList) => { - this.worker.postMessage(message, transferList); - }); } - write(data) { - if (this[kImpl].destroyed) { - error2(this, new Error("the worker has exited")); - return false; - } - if (this[kImpl].ending) { - error2(this, new Error("the worker is ending")); - return false; - } - if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) { - try { - writeSync(this); - this[kImpl].flushing = true; - } catch (err) { - destroy(this, err); - return false; - } - } - this[kImpl].buf += data; - if (this[kImpl].sync) { - try { - writeSync(this); - return true; - } catch (err) { - destroy(this, err); - return false; - } - } - if (!this[kImpl].flushing) { - this[kImpl].flushing = true; - setImmediate(nextFlush, this); + return { keys, values, target, flat: true }; + } + function nestedRestore(instructions) { + for (let i2 = 0; i2 < instructions.length; i2++) { + const { target, path: path8, value } = instructions[i2]; + let current = target; + for (let i3 = path8.length - 1; i3 > 0; i3--) { + current = current[path8[i3]]; } - this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0; - return !this[kImpl].needDrain; + current[path8[0]] = value; } - end() { - if (this[kImpl].destroyed) { - return; - } - this[kImpl].ending = true; - end(this); + } + function nestedRedact(store, o2, path8, ns, censor, isCensorFct, censorFctTakesPath) { + const target = get2(o2, path8); + if (target == null) return; + const keys = Object.keys(target); + const keysLength = keys.length; + for (var i2 = 0; i2 < keysLength; i2++) { + const key = keys[i2]; + specialSet(store, target, key, path8, ns, censor, isCensorFct, censorFctTakesPath); } - flush(cb) { - if (this[kImpl].destroyed) { - if (typeof cb === "function") { - process.nextTick(cb, new Error("the worker has exited")); + return store; + } + function has2(obj, prop) { + return obj !== void 0 && obj !== null ? "hasOwn" in Object ? Object.hasOwn(obj, prop) : Object.prototype.hasOwnProperty.call(obj, prop) : false; + } + function specialSet(store, o2, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath) { + const afterPathLen = afterPath.length; + const lastPathIndex = afterPathLen - 1; + const originalKey = k; + var i2 = -1; + var n; + var nv; + var ov; + var oov = null; + var wc = null; + var kIsWc; + var wcov; + var consecutive = false; + var level = 0; + var depth = 0; + var redactPathCurrent = tree(); + ov = n = o2[k]; + if (typeof n !== "object") return; + while (n != null && ++i2 < afterPathLen) { + depth += 1; + k = afterPath[i2]; + oov = ov; + if (k !== "*" && !wc && !(typeof n === "object" && k in n)) { + break; + } + if (k === "*") { + if (wc === "*") { + consecutive = true; + } + wc = k; + if (i2 !== lastPathIndex) { + continue; } - return; } - const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX); - wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => { - if (err) { - destroy(this, err); - process.nextTick(cb, err); - return; + if (wc) { + const wcKeys = Object.keys(n); + for (var j = 0; j < wcKeys.length; j++) { + const wck = wcKeys[j]; + wcov = n[wck]; + kIsWc = k === "*"; + if (consecutive) { + redactPathCurrent = node(redactPathCurrent, wck, depth); + level = i2; + ov = iterateNthLevel(wcov, level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, o2[originalKey], depth + 1); + } else { + if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { + if (kIsWc) { + ov = wcov; + } else { + ov = wcov[k]; + } + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (kIsWc) { + const rv = restoreInstr(node(redactPathCurrent, wck, depth), ov, o2[originalKey]); + store.push(rv); + n[wck] = nv; + } else { + if (wcov[k] === nv) { + } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { + redactPathCurrent = node(redactPathCurrent, wck, depth); + } else { + redactPathCurrent = node(redactPathCurrent, wck, depth); + const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, o2[originalKey]); + store.push(rv); + wcov[k] = nv; + } + } + } + } } - if (res === "not-equal") { - this.flush(cb); - return; + wc = null; + } else { + ov = n[k]; + redactPathCurrent = node(redactPathCurrent, k, depth); + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (has2(n, k) && nv === ov || nv === void 0 && censor !== void 0) { + } else { + const rv = restoreInstr(redactPathCurrent, ov, o2[originalKey]); + store.push(rv); + n[k] = nv; } - process.nextTick(cb); - }); - } - flushSync() { - if (this[kImpl].destroyed) { - return; + n = n[k]; + } + if (typeof n !== "object") break; + if (ov === oov || typeof ov === "undefined") { } - writeSync(this); - flushSync(this); - } - unref() { - this.worker.unref(); - } - ref() { - this.worker.ref(); - } - get ready() { - return this[kImpl].ready; - } - get destroyed() { - return this[kImpl].destroyed; - } - get closed() { - return this[kImpl].closed; - } - get writable() { - return !this[kImpl].destroyed && !this[kImpl].ending; - } - get writableEnded() { - return this[kImpl].ending; - } - get writableFinished() { - return this[kImpl].finished; - } - get writableNeedDrain() { - return this[kImpl].needDrain; - } - get writableObjectMode() { - return false; - } - get writableErrored() { - return this[kImpl].errored; } - }; - function error2(stream, err) { - setImmediate(() => { - stream.emit("error", err); - }); } - function destroy(stream, err) { - if (stream[kImpl].destroyed) { - return; - } - stream[kImpl].destroyed = true; - if (err) { - stream[kImpl].errored = err; - error2(stream, err); - } - if (!stream.worker.exited) { - stream.worker.terminate().catch(() => { - }).then(() => { - stream[kImpl].closed = true; - stream.emit("close"); - }); - } else { - setImmediate(() => { - stream[kImpl].closed = true; - stream.emit("close"); - }); + function get2(o2, p) { + var i2 = -1; + var l = p.length; + var n = o2; + while (n != null && ++i2 < l) { + n = n[p[i2]]; } + return n; } - function write(stream, data, cb) { - const current = Atomics.load(stream[kImpl].state, WRITE_INDEX); - const length2 = Buffer.byteLength(data); - stream[kImpl].data.write(data, current); - Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length2); - Atomics.notify(stream[kImpl].state, WRITE_INDEX); - cb(); - return true; - } - function end(stream) { - if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) { - return; - } - stream[kImpl].ended = true; - try { - stream.flushSync(); - let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - Atomics.store(stream[kImpl].state, WRITE_INDEX, -1); - Atomics.notify(stream[kImpl].state, WRITE_INDEX); - let spins = 0; - while (readIndex !== -1) { - Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); - readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - if (readIndex === -2) { - destroy(stream, new Error("end() failed")); - return; + function iterateNthLevel(wcov, level, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth) { + if (level === 0) { + if (kIsWc || typeof wcov === "object" && wcov !== null && k in wcov) { + if (kIsWc) { + ov = wcov; + } else { + ov = wcov[k]; } - if (++spins === 10) { - destroy(stream, new Error("end() took too long (10s)")); - return; + nv = i2 !== lastPathIndex ? ov : isCensorFct ? censorFctTakesPath ? censor(ov, [...path8, originalKey, ...afterPath]) : censor(ov) : censor; + if (kIsWc) { + const rv = restoreInstr(redactPathCurrent, ov, parent); + store.push(rv); + n[wck] = nv; + } else { + if (wcov[k] === nv) { + } else if (nv === void 0 && censor !== void 0 || has2(wcov, k) && nv === ov) { + } else { + const rv = restoreInstr(node(redactPathCurrent, k, depth + 1), ov, parent); + store.push(rv); + wcov[k] = nv; + } } } - process.nextTick(() => { - stream[kImpl].finished = true; - stream.emit("finish"); - }); - } catch (err) { - destroy(stream, err); } - } - function writeSync(stream) { - const cb = () => { - if (stream[kImpl].ending) { - end(stream); - } else if (stream[kImpl].needDrain) { - process.nextTick(drain, stream); - } - }; - stream[kImpl].flushing = false; - while (stream[kImpl].buf.length !== 0) { - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let leftover = stream[kImpl].data.length - writeIndex; - if (leftover === 0) { - flushSync(stream); - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - continue; - } else if (leftover < 0) { - throw new Error("overwritten"); - } - let toWrite = stream[kImpl].buf.slice(0, leftover); - let toWriteBytes = Buffer.byteLength(toWrite); - if (toWriteBytes <= leftover) { - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, cb); - } else { - flushSync(stream); - Atomics.store(stream[kImpl].state, READ_INDEX, 0); - Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); - while (toWriteBytes > stream[kImpl].buf.length) { - leftover = leftover / 2; - toWrite = stream[kImpl].buf.slice(0, leftover); - toWriteBytes = Buffer.byteLength(toWrite); - } - stream[kImpl].buf = stream[kImpl].buf.slice(leftover); - write(stream, toWrite, cb); + for (const key in wcov) { + if (typeof wcov[key] === "object") { + redactPathCurrent = node(redactPathCurrent, key, depth); + iterateNthLevel(wcov[key], level - 1, k, path8, afterPath, censor, isCensorFct, censorFctTakesPath, originalKey, n, nv, ov, kIsWc, wck, i2, lastPathIndex, redactPathCurrent, store, parent, depth + 1); } } } - function flushSync(stream) { - if (stream[kImpl].flushing) { - throw new Error("unable to flush while flushing"); - } - const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); - let spins = 0; - while (true) { - const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); - if (readIndex === -2) { - throw Error("_flushSync failed"); - } - if (readIndex !== writeIndex) { - Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); - } else { - break; - } - if (++spins === 10) { - throw new Error("_flushSync took too long (10s)"); - } + function tree() { + return { parent: null, key: null, children: [], depth: 0 }; + } + function node(parent, key, depth) { + if (parent.depth === depth) { + return node(parent.parent, key, depth); } + var child = { + parent, + key, + depth, + children: [] + }; + parent.children.push(child); + return child; } - module14.exports = ThreadStream; - } -}); -var require_transport = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports2, module14) { - "use strict"; - var { createRequire } = __require2("module"); - var getCallers = require_caller(); - var { join: join10, isAbsolute: isAbsolute8, sep } = __require2("path"); - var sleep = require_atomic_sleep(); - var onExit = require_on_exit_leak_free(); - var ThreadStream = require_thread_stream(); - function setupOnExit(stream) { - onExit.register(stream, autoEnd); - onExit.registerBeforeExit(stream, flush); - stream.on("close", function() { - onExit.unregister(stream); - }); + function restoreInstr(node2, value, target) { + let current = node2; + const path8 = []; + do { + path8.push(current.key); + current = current.parent; + } while (current.parent != null); + return { path: path8, value, target }; } - function buildStream(filename, workerData, workerOpts) { - const stream = new ThreadStream({ - filename, - workerData, - workerOpts - }); - stream.on("ready", onReady); - stream.on("close", function() { - process.removeListener("exit", onExit2); - }); - process.on("exit", onExit2); - function onReady() { - process.removeListener("exit", onExit2); - stream.unref(); - if (workerOpts.autoEnd !== false) { - setupOnExit(stream); - } - } - function onExit2() { - if (stream.closed) { + } +}); +var require_restorer = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/restorer.js"(exports2, module14) { + "use strict"; + var { groupRestore, nestedRestore } = require_modifiers(); + module14.exports = restorer; + function restorer() { + return function compileRestore() { + if (this.restore) { + this.restore.state.secret = this.secret; return; } - stream.flushSync(); - sleep(100); - stream.end(); + const { secret, wcLen } = this; + const paths = Object.keys(secret); + const resetters = resetTmpl(secret, paths); + const hasWildcards = wcLen > 0; + const state = hasWildcards ? { secret, groupRestore, nestedRestore } : { secret }; + this.restore = Function( + "o", + restoreTmpl(resetters, paths, hasWildcards) + ).bind(state); + this.restore.state = state; + }; + } + function resetTmpl(secret, paths) { + return paths.map((path8) => { + const { circle, escPath, leadingBracket } = secret[path8]; + const delim = leadingBracket ? "" : "."; + const reset = circle ? `o.${circle} = secret[${escPath}].val` : `o${delim}${path8} = secret[${escPath}].val`; + const clear = `secret[${escPath}].val = undefined`; + return ` + if (secret[${escPath}].val !== undefined) { + try { ${reset} } catch (e) {} + ${clear} } - return stream; + `; + }).join(""); } - function autoEnd(stream) { - stream.ref(); - stream.flushSync(); - stream.end(); - stream.once("close", function() { - stream.unref(); - }); + function restoreTmpl(resetters, paths, hasWildcards) { + const dynamicReset = hasWildcards === true ? ` + const keys = Object.keys(secret) + const len = keys.length + for (var i = len - 1; i >= ${paths.length}; i--) { + const k = keys[i] + const o = secret[k] + if (o) { + if (o.flat === true) this.groupRestore(o) + else this.nestedRestore(o) + secret[k] = null + } } - function flush(stream) { - stream.flushSync(); + ` : ""; + return ` + const secret = this.secret + ${dynamicReset} + ${resetters} + return o + `; } - function transport(fullOptions) { - const { pipeline, targets, levels, dedupe, options: options2 = {}, worker = {}, caller = getCallers() } = fullOptions; - const callers = typeof caller === "string" ? [caller] : caller; - const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; - let target = fullOptions.target; - if (target && targets) { - throw new Error("only one of target or targets can be specified"); - } - if (targets) { - target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js"); - options2.targets = targets.map((dest) => { - return { - ...dest, - target: fixTarget(dest.target) - }; - }); - } else if (pipeline) { - target = bundlerOverrides["pino-pipeline-worker"] || join10(__dirname, "worker-pipeline.js"); - options2.targets = pipeline.map((dest) => { - return { - ...dest, - target: fixTarget(dest.target) - }; - }); - } - if (levels) { - options2.levels = levels; - } - if (dedupe) { - options2.dedupe = dedupe; - } - return buildStream(fixTarget(target), options2, worker); - function fixTarget(origin) { - origin = bundlerOverrides[origin] || origin; - if (isAbsolute8(origin) || origin.indexOf("file://") === 0) { - return origin; - } - if (origin === "pino/file") { - return join10(__dirname, "..", "file.js"); - } - let fixTarget2; - for (const filePath of callers) { - try { - const context = filePath === "node:repl" ? process.cwd() + sep : filePath; - fixTarget2 = createRequire(context).resolve(origin); - break; - } catch (err) { - continue; - } - } - if (!fixTarget2) { - throw new Error(`unable to determine transport target for "${origin}"`); - } - return fixTarget2; + } +}); +var require_state = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/lib/state.js"(exports2, module14) { + "use strict"; + module14.exports = state; + function state(o2) { + const { + secret, + censor, + compileRestore, + serialize: serialize2, + groupRedact, + nestedRedact, + wildcards, + wcLen + } = o2; + const builder = [{ secret, censor, compileRestore }]; + if (serialize2 !== false) builder.push({ serialize: serialize2 }); + if (wcLen > 0) builder.push({ groupRedact, nestedRedact, wildcards, wcLen }); + return Object.assign(...builder); + } + } +}); +var require_fast_redact = __commonJS({ + "node_modules/.deno/fast-redact@3.5.0/node_modules/fast-redact/index.js"(exports2, module14) { + "use strict"; + var validator2 = require_validator(); + var parse62 = require_parse(); + var redactor = require_redactor(); + var restorer = require_restorer(); + var { groupRedact, nestedRedact } = require_modifiers(); + var state = require_state(); + var rx = require_rx(); + var validate = validator2(); + var noop = (o2) => o2; + noop.restore = noop; + var DEFAULT_CENSOR = "[REDACTED]"; + fastRedact.rx = rx; + fastRedact.validator = validator2; + module14.exports = fastRedact; + function fastRedact(opts = {}) { + const paths = Array.from(new Set(opts.paths || [])); + const serialize2 = "serialize" in opts ? opts.serialize === false ? opts.serialize : typeof opts.serialize === "function" ? opts.serialize : JSON.stringify : JSON.stringify; + const remove = opts.remove; + if (remove === true && serialize2 !== JSON.stringify) { + throw Error("fast-redact \u2013 remove option may only be set when serializer is JSON.stringify"); } + const censor = remove === true ? void 0 : "censor" in opts ? opts.censor : DEFAULT_CENSOR; + const isCensorFct = typeof censor === "function"; + const censorFctTakesPath = isCensorFct && censor.length > 1; + if (paths.length === 0) return serialize2 || noop; + validate({ paths, serialize: serialize2, censor }); + const { wildcards, wcLen, secret } = parse62({ paths, censor }); + const compileRestore = restorer(); + const strict = "strict" in opts ? opts.strict : true; + return redactor({ secret, wcLen, serialize: serialize2, strict, isCensorFct, censorFctTakesPath }, state({ + secret, + censor, + compileRestore, + serialize: serialize2, + groupRedact, + nestedRedact, + wildcards, + wcLen + })); } - module14.exports = transport; } }); -var require_tools = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/tools.js"(exports2, module14) { +var require_symbols = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/symbols.js"(exports2, module14) { "use strict"; - var format52 = require_quick_format_unescaped(); - var { mapHttpRequest, mapHttpResponse } = require_pino_std_serializers(); - var SonicBoom = require_sonic_boom(); - var onExit = require_on_exit_leak_free(); - var { + var setLevelSym = Symbol("pino.setLevel"); + var getLevelSym = Symbol("pino.getLevel"); + var levelValSym = Symbol("pino.levelVal"); + var levelCompSym = Symbol("pino.levelComp"); + var useLevelLabelsSym = Symbol("pino.useLevelLabels"); + var useOnlyCustomLevelsSym = Symbol("pino.useOnlyCustomLevels"); + var mixinSym = Symbol("pino.mixin"); + var lsCacheSym = Symbol("pino.lsCache"); + var chindingsSym = Symbol("pino.chindings"); + var asJsonSym = Symbol("pino.asJson"); + var writeSym = Symbol("pino.write"); + var redactFmtSym = Symbol("pino.redactFmt"); + var timeSym = Symbol("pino.time"); + var timeSliceIndexSym = Symbol("pino.timeSliceIndex"); + var streamSym = Symbol("pino.stream"); + var stringifySym = Symbol("pino.stringify"); + var stringifySafeSym = Symbol("pino.stringifySafe"); + var stringifiersSym = Symbol("pino.stringifiers"); + var endSym = Symbol("pino.end"); + var formatOptsSym = Symbol("pino.formatOpts"); + var messageKeySym = Symbol("pino.messageKey"); + var errorKeySym = Symbol("pino.errorKey"); + var nestedKeySym = Symbol("pino.nestedKey"); + var nestedKeyStrSym = Symbol("pino.nestedKeyStr"); + var mixinMergeStrategySym = Symbol("pino.mixinMergeStrategy"); + var msgPrefixSym = Symbol("pino.msgPrefix"); + var wildcardFirstSym = Symbol("pino.wildcardFirst"); + var serializersSym = Symbol.for("pino.serializers"); + var formattersSym = Symbol.for("pino.formatters"); + var hooksSym = Symbol.for("pino.hooks"); + var needsMetadataGsym = Symbol.for("pino.metadata"); + module14.exports = { + setLevelSym, + getLevelSym, + levelValSym, + levelCompSym, + useLevelLabelsSym, + mixinSym, lsCacheSym, chindingsSym, + asJsonSym, writeSym, serializersSym, - formatOptsSym, - endSym, - stringifiersSym, + redactFmtSym, + timeSym, + timeSliceIndexSym, + streamSym, stringifySym, stringifySafeSym, - wildcardFirstSym, - nestedKeySym, - formattersSym, + stringifiersSym, + endSym, + formatOptsSym, messageKeySym, errorKeySym, + nestedKeySym, + wildcardFirstSym, + needsMetadataGsym, + useOnlyCustomLevelsSym, + formattersSym, + hooksSym, nestedKeyStrSym, + mixinMergeStrategySym, msgPrefixSym - } = require_symbols(); - var { isMainThread } = __require2("worker_threads"); - var transport = require_transport(); - function noop() { - } - function genLog(level, hook) { - if (!hook) return LOG; - return function hookWrappedLog(...args) { - hook.call(this, args, LOG, level); - }; - function LOG(o2, ...n) { - if (typeof o2 === "object") { - let msg = o2; - if (o2 !== null) { - if (o2.method && o2.headers && o2.socket) { - o2 = mapHttpRequest(o2); - } else if (typeof o2.setHeader === "function") { - o2 = mapHttpResponse(o2); + }; + } +}); +var require_redaction = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/redaction.js"(exports2, module14) { + "use strict"; + var fastRedact = require_fast_redact(); + var { redactFmtSym, wildcardFirstSym } = require_symbols(); + var { rx, validator: validator2 } = fastRedact; + var validate = validator2({ + ERR_PATHS_MUST_BE_STRINGS: () => "pino \u2013 redacted paths must be strings", + ERR_INVALID_PATH: (s) => `pino \u2013 redact paths array contains an invalid path (${s})` + }); + var CENSOR = "[Redacted]"; + var strict = false; + function redaction(opts, serialize2) { + const { paths, censor } = handle(opts); + const shape = paths.reduce((o2, str) => { + rx.lastIndex = 0; + const first = rx.exec(str); + const next = rx.exec(str); + let ns = first[1] !== void 0 ? first[1].replace(/^(?:"|'|`)(.*)(?:"|'|`)$/, "$1") : first[0]; + if (ns === "*") { + ns = wildcardFirstSym; + } + if (next === null) { + o2[ns] = null; + return o2; + } + if (o2[ns] === null) { + return o2; + } + const { index } = next; + const nextPath = `${str.substr(index, str.length - 1)}`; + o2[ns] = o2[ns] || []; + if (ns !== wildcardFirstSym && o2[ns].length === 0) { + o2[ns].push(...o2[wildcardFirstSym] || []); + } + if (ns === wildcardFirstSym) { + Object.keys(o2).forEach(function(k) { + if (o2[k]) { + o2[k].push(nextPath); } - } - let formatParams; - if (msg === null && n.length === 0) { - formatParams = [null]; - } else { - msg = n.shift(); - formatParams = n; - } - if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { - msg = this[msgPrefixSym] + msg; - } - this[writeSym](o2, format52(msg, formatParams, this[formatOptsSym]), level); + }); + } + o2[ns].push(nextPath); + return o2; + }, {}); + const result = { + [redactFmtSym]: fastRedact({ paths, censor, serialize: serialize2, strict }) + }; + const topCensor = (...args) => { + return typeof censor === "function" ? serialize2(censor(...args)) : serialize2(censor); + }; + return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o2, k) => { + if (shape[k] === null) { + o2[k] = (value) => topCensor(value, [k]); } else { - let msg = o2 === void 0 ? n.shift() : o2; - if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { - msg = this[msgPrefixSym] + msg; - } - this[writeSym](null, format52(msg, n, this[formatOptsSym]), level); + const wrappedCensor = typeof censor === "function" ? (value, path8) => { + return censor(value, [k, ...path8]); + } : censor; + o2[k] = fastRedact({ + paths: shape[k], + censor: wrappedCensor, + serialize: serialize2, + strict + }); } - } + return o2; + }, result); } - function asString(str) { - let result = ""; - let last = 0; - let found = false; - let point = 255; - const l = str.length; - if (l > 100) { - return JSON.stringify(str); - } - for (var i2 = 0; i2 < l && point >= 32; i2++) { - point = str.charCodeAt(i2); - if (point === 34 || point === 92) { - result += str.slice(last, i2) + "\\"; - last = i2; - found = true; - } + function handle(opts) { + if (Array.isArray(opts)) { + opts = { paths: opts, censor: CENSOR }; + validate(opts); + return opts; } - if (!found) { - result = str; - } else { - result += str.slice(last); + let { paths, censor = CENSOR, remove } = opts; + if (Array.isArray(paths) === false) { + throw Error("pino \u2013 redact must contain an array of strings"); } - return point < 32 ? JSON.stringify(str) : '"' + result + '"'; + if (remove === true) censor = void 0; + validate({ paths, censor }); + return { paths, censor }; } - function asJson(obj, msg, num, time3) { - const stringify3 = this[stringifySym]; - const stringifySafe = this[stringifySafeSym]; - const stringifiers = this[stringifiersSym]; - const end = this[endSym]; - const chindings = this[chindingsSym]; - const serializers = this[serializersSym]; - const formatters = this[formattersSym]; - const messageKey = this[messageKeySym]; - const errorKey = this[errorKeySym]; - let data = this[lsCacheSym][num] + time3; - data = data + chindings; - let value; - if (formatters.log) { - obj = formatters.log(obj); + module14.exports = redaction; + } +}); +var require_time = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/time.js"(exports2, module14) { + "use strict"; + var nullTime = () => ""; + var epochTime = () => `,"time":${Date.now()}`; + var unixTime = () => `,"time":${Math.round(Date.now() / 1e3)}`; + var isoTime = () => `,"time":"${new Date(Date.now()).toISOString()}"`; + module14.exports = { nullTime, epochTime, unixTime, isoTime }; + } +}); +var require_quick_format_unescaped = __commonJS({ + "node_modules/.deno/quick-format-unescaped@4.0.4/node_modules/quick-format-unescaped/index.js"(exports2, module14) { + "use strict"; + function tryStringify(o2) { + try { + return JSON.stringify(o2); + } catch (e2) { + return '"[Circular]"'; } - const wildcardStringifier = stringifiers[wildcardFirstSym]; - let propStr = ""; - for (const key in obj) { - value = obj[key]; - if (Object.prototype.hasOwnProperty.call(obj, key) && value !== void 0) { - if (serializers[key]) { - value = serializers[key](value); - } else if (key === errorKey && serializers.err) { - value = serializers.err(value); - } - const stringifier = stringifiers[key] || wildcardStringifier; - switch (typeof value) { - case "undefined": - case "function": - continue; - case "number": - if (Number.isFinite(value) === false) { - value = null; - } - // this case explicitly falls through to the next one - case "boolean": - if (stringifier) value = stringifier(value); - break; - case "string": - value = (stringifier || asString)(value); - break; - default: - value = (stringifier || stringify3)(value, stringifySafe); - } - if (value === void 0) continue; - const strKey = asString(key); - propStr += "," + strKey + ":" + value; + } + module14.exports = format52; + function format52(f, args, opts) { + var ss = opts && opts.stringify || tryStringify; + var offset = 1; + if (typeof f === "object" && f !== null) { + var len = args.length + offset; + if (len === 1) return f; + var objects = new Array(len); + objects[0] = ss(f); + for (var index = 1; index < len; index++) { + objects[index] = ss(args[index]); } + return objects.join(" "); } - let msgStr = ""; - if (msg !== void 0) { - value = serializers[messageKey] ? serializers[messageKey](msg) : msg; - const stringifier = stringifiers[messageKey] || wildcardStringifier; - switch (typeof value) { - case "function": - break; - case "number": - if (Number.isFinite(value) === false) { - value = null; - } - // this case explicitly falls through to the next one - case "boolean": - if (stringifier) value = stringifier(value); - msgStr = ',"' + messageKey + '":' + value; - break; - case "string": - value = (stringifier || asString)(value); - msgStr = ',"' + messageKey + '":' + value; - break; - default: - value = (stringifier || stringify3)(value, stringifySafe); - msgStr = ',"' + messageKey + '":' + value; + if (typeof f !== "string") { + return f; + } + var argLen = args.length; + if (argLen === 0) return f; + var str = ""; + var a = 1 - offset; + var lastPos = -1; + var flen = f && f.length || 0; + for (var i2 = 0; i2 < flen; ) { + if (f.charCodeAt(i2) === 37 && i2 + 1 < flen) { + lastPos = lastPos > -1 ? lastPos : 0; + switch (f.charCodeAt(i2 + 1)) { + case 100: + // 'd' + case 102: + if (a >= argLen) + break; + if (args[a] == null) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += Number(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 105: + if (a >= argLen) + break; + if (args[a] == null) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += Math.floor(Number(args[a])); + lastPos = i2 + 2; + i2++; + break; + case 79: + // 'O' + case 111: + // 'o' + case 106: + if (a >= argLen) + break; + if (args[a] === void 0) break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + var type = typeof args[a]; + if (type === "string") { + str += "'" + args[a] + "'"; + lastPos = i2 + 2; + i2++; + break; + } + if (type === "function") { + str += args[a].name || ""; + lastPos = i2 + 2; + i2++; + break; + } + str += ss(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 115: + if (a >= argLen) + break; + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += String(args[a]); + lastPos = i2 + 2; + i2++; + break; + case 37: + if (lastPos < i2) + str += f.slice(lastPos, i2); + str += "%"; + lastPos = i2 + 2; + i2++; + a--; + break; + } + ++a; } + ++i2; } - if (this[nestedKeySym] && propStr) { - return data + this[nestedKeyStrSym] + propStr.slice(1) + "}" + msgStr + end; - } else { - return data + propStr + msgStr + end; + if (lastPos === -1) + return f; + else if (lastPos < flen) { + str += f.slice(lastPos); } + return str; } - function asChindings(instance, bindings) { - let value; - let data = instance[chindingsSym]; - const stringify3 = instance[stringifySym]; - const stringifySafe = instance[stringifySafeSym]; - const stringifiers = instance[stringifiersSym]; - const wildcardStringifier = stringifiers[wildcardFirstSym]; - const serializers = instance[serializersSym]; - const formatter = instance[formattersSym].bindings; - bindings = formatter(bindings); - for (const key in bindings) { - value = bindings[key]; - const valid = key !== "level" && key !== "serializers" && key !== "formatters" && key !== "customLevels" && bindings.hasOwnProperty(key) && value !== void 0; - if (valid === true) { - value = serializers[key] ? serializers[key](value) : value; - value = (stringifiers[key] || wildcardStringifier || stringify3)(value, stringifySafe); - if (value === void 0) continue; - data += ',"' + key + '":' + value; + } +}); +var require_atomic_sleep = __commonJS({ + "node_modules/.deno/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module14) { + "use strict"; + if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") { + let sleep = function(ms) { + const valid = ms > 0 && ms < Infinity; + if (valid === false) { + if (typeof ms !== "number" && typeof ms !== "bigint") { + throw TypeError("sleep: ms must be a number"); + } + throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); } - } - return data; - } - function hasBeenTampered(stream) { - return stream.write !== stream.constructor.prototype.write; + Atomics.wait(nil, 0, 0, Number(ms)); + }; + const nil = new Int32Array(new SharedArrayBuffer(4)); + module14.exports = sleep; + } else { + let sleep = function(ms) { + const valid = ms > 0 && ms < Infinity; + if (valid === false) { + if (typeof ms !== "number" && typeof ms !== "bigint") { + throw TypeError("sleep: ms must be a number"); + } + throw RangeError("sleep: ms must be a number that is greater than 0 but less than Infinity"); + } + const target = Date.now() + Number(ms); + while (target > Date.now()) { + } + }; + module14.exports = sleep; } - var hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE; - function buildSafeSonicBoom(opts) { - const stream = new SonicBoom(opts); - stream.on("error", filterBrokenPipe); - if (!hasNodeCodeCoverage && !opts.sync && isMainThread) { - onExit.register(stream, autoEnd); - stream.on("close", function() { - onExit.unregister(stream); - }); - } - return stream; - function filterBrokenPipe(err) { - if (err.code === "EPIPE") { - stream.write = noop; - stream.end = noop; - stream.flushSync = noop; - stream.destroy = noop; + } +}); +var require_sonic_boom = __commonJS({ + "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports2, module14) { + "use strict"; + var fs = __require2("fs"); + var EventEmitter = __require2("events"); + var inherits = __require2("util").inherits; + var path8 = __require2("path"); + var sleep = require_atomic_sleep(); + var BUSY_WRITE_TIMEOUT = 100; + var kEmptyBuffer = Buffer.allocUnsafe(0); + var MAX_WRITE = 16 * 1024; + var kContentModeBuffer = "buffer"; + var kContentModeUtf8 = "utf8"; + function openFile(file, sonic) { + sonic._opening = true; + sonic._writing = true; + sonic._asyncDrainScheduled = false; + function fileOpened(err, fd) { + if (err) { + sonic._reopening = false; + sonic._writing = false; + sonic._opening = false; + if (sonic.sync) { + process.nextTick(() => { + if (sonic.listenerCount("error") > 0) { + sonic.emit("error", err); + } + }); + } else { + sonic.emit("error", err); + } return; } - stream.removeListener("error", filterBrokenPipe); - stream.emit("error", err); - } - } - function autoEnd(stream, eventName) { - if (stream.destroyed) { - return; + const reopening = sonic._reopening; + sonic.fd = fd; + sonic.file = file; + sonic._reopening = false; + sonic._opening = false; + sonic._writing = false; + if (sonic.sync) { + process.nextTick(() => sonic.emit("ready")); + } else { + sonic.emit("ready"); + } + if (sonic.destroyed) { + return; + } + if (!sonic._writing && sonic._len > sonic.minLength || sonic._flushPending) { + sonic._actualWrite(); + } else if (reopening) { + process.nextTick(() => sonic.emit("drain")); + } } - if (eventName === "beforeExit") { - stream.flush(); - stream.on("drain", function() { - stream.end(); + const flags = sonic.append ? "a" : "w"; + const mode = sonic.mode; + if (sonic.sync) { + try { + if (sonic.mkdir) fs.mkdirSync(path8.dirname(file), { recursive: true }); + const fd = fs.openSync(file, flags, mode); + fileOpened(null, fd); + } catch (err) { + fileOpened(err); + throw err; + } + } else if (sonic.mkdir) { + fs.mkdir(path8.dirname(file), { recursive: true }, (err) => { + if (err) return fileOpened(err); + fs.open(file, flags, mode, fileOpened); }); } else { - stream.flushSync(); + fs.open(file, flags, mode, fileOpened); } } - function createArgsNormalizer(defaultOptions4) { - return function normalizeArgs(instance, caller, opts = {}, stream) { - if (typeof opts === "string") { - stream = buildSafeSonicBoom({ dest: opts }); - opts = {}; - } else if (typeof stream === "string") { - if (opts && opts.transport) { - throw Error("only one of option.transport or stream can be specified"); - } - stream = buildSafeSonicBoom({ dest: stream }); - } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) { - stream = opts; - opts = {}; - } else if (opts.transport) { - if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) { - throw Error("option.transport do not allow stream, please pass to option directly. e.g. pino(transport)"); + function SonicBoom(opts) { + if (!(this instanceof SonicBoom)) { + return new SonicBoom(opts); + } + let { fd, dest, minLength, maxLength, maxWrite, sync, append = true, mkdir: mkdir4, retryEAGAIN, fsync, contentMode, mode } = opts || {}; + fd = fd || dest; + this._len = 0; + this.fd = -1; + this._bufs = []; + this._lens = []; + this._writing = false; + this._ending = false; + this._reopening = false; + this._asyncDrainScheduled = false; + this._flushPending = false; + this._hwm = Math.max(minLength || 0, 16387); + this.file = null; + this.destroyed = false; + this.minLength = minLength || 0; + this.maxLength = maxLength || 0; + this.maxWrite = maxWrite || MAX_WRITE; + this.sync = sync || false; + this.writable = true; + this._fsync = fsync || false; + this.append = append || false; + this.mode = mode; + this.retryEAGAIN = retryEAGAIN || (() => true); + this.mkdir = mkdir4 || false; + let fsWriteSync; + let fsWrite; + if (contentMode === kContentModeBuffer) { + this._writingBuf = kEmptyBuffer; + this.write = writeBuffer; + this.flush = flushBuffer; + this.flushSync = flushBufferSync; + this._actualWrite = actualWriteBuffer; + fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf); + fsWrite = () => fs.write(this.fd, this._writingBuf, this.release); + } else if (contentMode === void 0 || contentMode === kContentModeUtf8) { + this._writingBuf = ""; + this.write = write; + this.flush = flush; + this.flushSync = flushSync; + this._actualWrite = actualWrite; + fsWriteSync = () => fs.writeSync(this.fd, this._writingBuf, "utf8"); + fsWrite = () => fs.write(this.fd, this._writingBuf, "utf8", this.release); + } else { + throw new Error(`SonicBoom supports "${kContentModeUtf8}" and "${kContentModeBuffer}", but passed ${contentMode}`); + } + if (typeof fd === "number") { + this.fd = fd; + process.nextTick(() => this.emit("ready")); + } else if (typeof fd === "string") { + openFile(fd, this); + } else { + throw new Error("SonicBoom supports only file descriptors and files"); + } + if (this.minLength >= this.maxWrite) { + throw new Error(`minLength should be smaller than maxWrite (${this.maxWrite})`); + } + this.release = (err, n) => { + if (err) { + if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) { + if (this.sync) { + try { + sleep(BUSY_WRITE_TIMEOUT); + this.release(void 0, 0); + } catch (err2) { + this.release(err2); + } + } else { + setTimeout(fsWrite, BUSY_WRITE_TIMEOUT); + } + } else { + this._writing = false; + this.emit("error", err); } - if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === "function") { - throw Error("option.transport.targets do not allow custom level formatters"); + return; + } + this.emit("write", n); + const releasedBufObj = releaseWritingBuf(this._writingBuf, this._len, n); + this._len = releasedBufObj.len; + this._writingBuf = releasedBufObj.writingBuf; + if (this._writingBuf.length) { + if (!this.sync) { + fsWrite(); + return; } - let customLevels; - if (opts.customLevels) { - customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels); + try { + do { + const n2 = fsWriteSync(); + const releasedBufObj2 = releaseWritingBuf(this._writingBuf, this._len, n2); + this._len = releasedBufObj2.len; + this._writingBuf = releasedBufObj2.writingBuf; + } while (this._writingBuf.length); + } catch (err2) { + this.release(err2); + return; } - stream = transport({ caller, ...opts.transport, levels: customLevels }); } - opts = Object.assign({}, defaultOptions4, opts); - opts.serializers = Object.assign({}, defaultOptions4.serializers, opts.serializers); - opts.formatters = Object.assign({}, defaultOptions4.formatters, opts.formatters); - if (opts.prettyPrint) { - throw new Error("prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)"); + if (this._fsync) { + fs.fsyncSync(this.fd); } - const { enabled: enabled2, onChild } = opts; - if (enabled2 === false) opts.level = "silent"; - if (!onChild) opts.onChild = noop; - if (!stream) { - if (!hasBeenTampered(process.stdout)) { - stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 }); + const len = this._len; + if (this._reopening) { + this._writing = false; + this._reopening = false; + this.reopen(); + } else if (len > this.minLength) { + this._actualWrite(); + } else if (this._ending) { + if (len > 0) { + this._actualWrite(); } else { - stream = process.stdout; + this._writing = false; + actualClose(this); + } + } else { + this._writing = false; + if (this.sync) { + if (!this._asyncDrainScheduled) { + this._asyncDrainScheduled = true; + process.nextTick(emitDrain, this); + } + } else { + this.emit("drain"); } } - return { opts, stream }; }; - } - function stringify2(obj, stringifySafeFn) { - try { - return JSON.stringify(obj); - } catch (_) { - try { - const stringify3 = stringifySafeFn || this[stringifySafeSym]; - return stringify3(obj); - } catch (_2) { - return '"[unable to serialize, circular reference is too complex to analyze]"'; + this.on("newListener", function(name) { + if (name === "drain") { + this._asyncDrainScheduled = false; } + }); + } + function releaseWritingBuf(writingBuf, len, n) { + if (typeof writingBuf === "string" && Buffer.byteLength(writingBuf) !== n) { + n = Buffer.from(writingBuf).subarray(0, n).toString().length; } + len = Math.max(len - n, 0); + writingBuf = writingBuf.slice(n); + return { writingBuf, len }; } - function buildFormatters(level, bindings, log2) { - return { - level, - bindings, - log: log2 - }; + function emitDrain(sonic) { + const hasListeners = sonic.listenerCount("drain") > 0; + if (!hasListeners) return; + sonic._asyncDrainScheduled = false; + sonic.emit("drain"); } - function normalizeDestFileDescriptor(destination) { - const fd = Number(destination); - if (typeof destination === "string" && Number.isFinite(fd)) { - return fd; + inherits(SonicBoom, EventEmitter); + function mergeBuf(bufs, len) { + if (bufs.length === 0) { + return kEmptyBuffer; } - if (destination === void 0) { - return 1; + if (bufs.length === 1) { + return bufs[0]; } - return destination; + return Buffer.concat(bufs, len); } - module14.exports = { - noop, - buildSafeSonicBoom, - asChindings, - asJson, - genLog, - createArgsNormalizer, - stringify: stringify2, - buildFormatters, - normalizeDestFileDescriptor - }; - } -}); -var require_constants = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/constants.js"(exports2, module14) { - var DEFAULT_LEVELS = { - trace: 10, - debug: 20, - info: 30, - warn: 40, - error: 50, - fatal: 60 - }; - var SORTING_ORDER = { - ASC: "ASC", - DESC: "DESC" - }; - module14.exports = { - DEFAULT_LEVELS, - SORTING_ORDER - }; - } -}); -var require_levels = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/levels.js"(exports2, module14) { - "use strict"; - var { - lsCacheSym, - levelValSym, - useOnlyCustomLevelsSym, - streamSym, - formattersSym, - hooksSym, - levelCompSym - } = require_symbols(); - var { noop, genLog } = require_tools(); - var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); - var levelMethods = { - fatal: (hook) => { - const logFatal = genLog(DEFAULT_LEVELS.fatal, hook); - return function(...args) { - const stream = this[streamSym]; - logFatal.call(this, ...args); - if (typeof stream.flushSync === "function") { - try { - stream.flushSync(); - } catch (e2) { - } - } - }; - }, - error: (hook) => genLog(DEFAULT_LEVELS.error, hook), - warn: (hook) => genLog(DEFAULT_LEVELS.warn, hook), - info: (hook) => genLog(DEFAULT_LEVELS.info, hook), - debug: (hook) => genLog(DEFAULT_LEVELS.debug, hook), - trace: (hook) => genLog(DEFAULT_LEVELS.trace, hook) - }; - var nums = Object.keys(DEFAULT_LEVELS).reduce((o2, k) => { - o2[DEFAULT_LEVELS[k]] = k; - return o2; - }, {}); - var initialLsCache = Object.keys(nums).reduce((o2, k) => { - o2[k] = '{"level":' + Number(k); - return o2; - }, {}); - function genLsCache(instance) { - const formatter = instance[formattersSym].level; - const { labels } = instance.levels; - const cache2 = {}; - for (const label in labels) { - const level = formatter(labels[label], Number(label)); - cache2[label] = JSON.stringify(level).slice(0, -1); + function write(data) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); } - instance[lsCacheSym] = cache2; - return instance; - } - function isStandardLevel(level, useOnlyCustomLevels) { - if (useOnlyCustomLevels) { - return false; + const len = this._len + data.length; + const bufs = this._bufs; + if (this.maxLength && len > this.maxLength) { + this.emit("drop", data); + return this._len < this._hwm; } - switch (level) { - case "fatal": - case "error": - case "warn": - case "info": - case "debug": - case "trace": - return true; - default: - return false; + if (bufs.length === 0 || bufs[bufs.length - 1].length + data.length > this.maxWrite) { + bufs.push("" + data); + } else { + bufs[bufs.length - 1] += data; + } + this._len = len; + if (!this._writing && this._len >= this.minLength) { + this._actualWrite(); } + return this._len < this._hwm; } - function setLevel(level) { - const { labels, values } = this.levels; - if (typeof level === "number") { - if (labels[level] === void 0) throw Error("unknown level value" + level); - level = labels[level]; + function writeBuffer(data) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); } - if (values[level] === void 0) throw Error("unknown level " + level); - const preLevelVal = this[levelValSym]; - const levelVal = this[levelValSym] = values[level]; - const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]; - const levelComparison = this[levelCompSym]; - const hook = this[hooksSym].logMethod; - for (const key in values) { - if (levelComparison(values[key], levelVal) === false) { - this[key] = noop; - continue; - } - this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook); + const len = this._len + data.length; + const bufs = this._bufs; + const lens = this._lens; + if (this.maxLength && len > this.maxLength) { + this.emit("drop", data); + return this._len < this._hwm; } - this.emit( - "level-change", - level, - levelVal, - labels[preLevelVal], - preLevelVal, - this - ); - } - function getLevel(level) { - const { levels, levelVal } = this; - return levels && levels.labels ? levels.labels[levelVal] : ""; - } - function isLevelEnabled(logLevel2) { - const { values } = this.levels; - const logLevelVal = values[logLevel2]; - return logLevelVal !== void 0 && this[levelCompSym](logLevelVal, this[levelValSym]); - } - function compareLevel(direction, current, expected) { - if (direction === SORTING_ORDER.DESC) { - return current <= expected; + if (bufs.length === 0 || lens[lens.length - 1] + data.length > this.maxWrite) { + bufs.push([data]); + lens.push(data.length); + } else { + bufs[bufs.length - 1].push(data); + lens[lens.length - 1] += data.length; } - return current >= expected; - } - function genLevelComparison(levelComparison) { - if (typeof levelComparison === "string") { - return compareLevel.bind(null, levelComparison); + this._len = len; + if (!this._writing && this._len >= this.minLength) { + this._actualWrite(); } - return levelComparison; + return this._len < this._hwm; } - function mappings(customLevels = null, useOnlyCustomLevels = false) { - const customNums = customLevels ? Object.keys(customLevels).reduce((o2, k) => { - o2[customLevels[k]] = k; - return o2; - }, {}) : null; - const labels = Object.assign( - Object.create(Object.prototype, { Infinity: { value: "silent" } }), - useOnlyCustomLevels ? null : nums, - customNums - ); - const values = Object.assign( - Object.create(Object.prototype, { silent: { value: Infinity } }), - useOnlyCustomLevels ? null : DEFAULT_LEVELS, - customLevels - ); - return { labels, values }; + function callFlushCallbackOnDrain(cb) { + this._flushPending = true; + const onDrain = () => { + if (!this._fsync) { + fs.fsync(this.fd, (err) => { + this._flushPending = false; + cb(err); + }); + } else { + this._flushPending = false; + cb(); + } + this.off("error", onError); + }; + const onError = (err) => { + this._flushPending = false; + cb(err); + this.off("drain", onDrain); + }; + this.once("drain", onDrain); + this.once("error", onError); } - function assertDefaultLevelFound(defaultLevel, customLevels, useOnlyCustomLevels) { - if (typeof defaultLevel === "number") { - const values = [].concat( - Object.keys(customLevels || {}).map((key) => customLevels[key]), - useOnlyCustomLevels ? [] : Object.keys(nums).map((level) => +level), - Infinity - ); - if (!values.includes(defaultLevel)) { - throw Error(`default level:${defaultLevel} must be included in custom levels`); + function flush(cb) { + if (cb != null && typeof cb !== "function") { + throw new Error("flush cb must be a function"); + } + if (this.destroyed) { + const error2 = new Error("SonicBoom destroyed"); + if (cb) { + cb(error2); + return; } + throw error2; + } + if (this.minLength <= 0) { + cb?.(); return; } - const labels = Object.assign( - Object.create(Object.prototype, { silent: { value: Infinity } }), - useOnlyCustomLevels ? null : DEFAULT_LEVELS, - customLevels - ); - if (!(defaultLevel in labels)) { - throw Error(`default level:${defaultLevel} must be included in custom levels`); + if (cb) { + callFlushCallbackOnDrain.call(this, cb); + } + if (this._writing) { + return; } + if (this._bufs.length === 0) { + this._bufs.push(""); + } + this._actualWrite(); } - function assertNoLevelCollisions(levels, customLevels) { - const { labels, values } = levels; - for (const k in customLevels) { - if (k in values) { - throw Error("levels cannot be overridden"); - } - if (customLevels[k] in labels) { - throw Error("pre-existing level values cannot be used for new levels"); + function flushBuffer(cb) { + if (cb != null && typeof cb !== "function") { + throw new Error("flush cb must be a function"); + } + if (this.destroyed) { + const error2 = new Error("SonicBoom destroyed"); + if (cb) { + cb(error2); + return; } + throw error2; } - } - function assertLevelComparison(levelComparison) { - if (typeof levelComparison === "function") { + if (this.minLength <= 0) { + cb?.(); return; } - if (typeof levelComparison === "string" && Object.values(SORTING_ORDER).includes(levelComparison)) { + if (cb) { + callFlushCallbackOnDrain.call(this, cb); + } + if (this._writing) { return; } - throw new Error('Levels comparison should be one of "ASC", "DESC" or "function" type'); + if (this._bufs.length === 0) { + this._bufs.push([]); + this._lens.push(0); + } + this._actualWrite(); } - module14.exports = { - initialLsCache, - genLsCache, - levelMethods, - getLevel, - setLevel, - isLevelEnabled, - mappings, - assertNoLevelCollisions, - assertDefaultLevelFound, - genLevelComparison, - assertLevelComparison - }; - } -}); -var require_meta = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/meta.js"(exports2, module14) { - "use strict"; - module14.exports = { version: "8.19.0" }; - } -}); -var require_proto = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports2, module14) { - "use strict"; - var { EventEmitter } = __require2("events"); - var { - lsCacheSym, - levelValSym, - setLevelSym, - getLevelSym, - chindingsSym, - parsedChindingsSym, - mixinSym, - asJsonSym, - writeSym, - mixinMergeStrategySym, - timeSym, - timeSliceIndexSym, - streamSym, - serializersSym, - formattersSym, - errorKeySym, - messageKeySym, - useOnlyCustomLevelsSym, - needsMetadataGsym, - redactFmtSym, - stringifySym, - formatOptsSym, - stringifiersSym, - msgPrefixSym - } = require_symbols(); - var { - getLevel, - setLevel, - isLevelEnabled, - mappings, - initialLsCache, - genLsCache, - assertNoLevelCollisions - } = require_levels(); - var { - asChindings, - asJson, - buildFormatters, - stringify: stringify2 - } = require_tools(); - var { - version: version3 - } = require_meta(); - var redaction = require_redaction(); - var constructor = class Pino { - }; - var prototype = { - constructor, - child, - bindings, - setBindings, - flush, - isLevelEnabled, - version: version3, - get level() { - return this[getLevelSym](); - }, - set level(lvl) { - this[setLevelSym](lvl); - }, - get levelVal() { - return this[levelValSym]; - }, - set levelVal(n) { - throw Error("levelVal is read-only"); - }, - [lsCacheSym]: initialLsCache, - [writeSym]: write, - [asJsonSym]: asJson, - [getLevelSym]: getLevel, - [setLevelSym]: setLevel - }; - Object.setPrototypeOf(prototype, EventEmitter.prototype); - module14.exports = function() { - return Object.create(prototype); - }; - var resetChildingsFormatter = (bindings2) => bindings2; - function child(bindings2, options2) { - if (!bindings2) { - throw Error("missing bindings for child Pino"); + SonicBoom.prototype.reopen = function(file) { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); } - options2 = options2 || {}; - const serializers = this[serializersSym]; - const formatters = this[formattersSym]; - const instance = Object.create(this); - if (options2.hasOwnProperty("serializers") === true) { - instance[serializersSym] = /* @__PURE__ */ Object.create(null); - for (const k in serializers) { - instance[serializersSym][k] = serializers[k]; - } - const parentSymbols = Object.getOwnPropertySymbols(serializers); - for (var i2 = 0; i2 < parentSymbols.length; i2++) { - const ks = parentSymbols[i2]; - instance[serializersSym][ks] = serializers[ks]; - } - for (const bk in options2.serializers) { - instance[serializersSym][bk] = options2.serializers[bk]; - } - const bindingsSymbols = Object.getOwnPropertySymbols(options2.serializers); - for (var bi = 0; bi < bindingsSymbols.length; bi++) { - const bks = bindingsSymbols[bi]; - instance[serializersSym][bks] = options2.serializers[bks]; - } - } else instance[serializersSym] = serializers; - if (options2.hasOwnProperty("formatters")) { - const { level, bindings: chindings, log: log2 } = options2.formatters; - instance[formattersSym] = buildFormatters( - level || formatters.level, - chindings || resetChildingsFormatter, - log2 || formatters.log - ); - } else { - instance[formattersSym] = buildFormatters( - formatters.level, - resetChildingsFormatter, - formatters.log - ); + if (this._opening) { + this.once("ready", () => { + this.reopen(file); + }); + return; } - if (options2.hasOwnProperty("customLevels") === true) { - assertNoLevelCollisions(this.levels, options2.customLevels); - instance.levels = mappings(options2.customLevels, instance[useOnlyCustomLevelsSym]); - genLsCache(instance); + if (this._ending) { + return; } - if (typeof options2.redact === "object" && options2.redact !== null || Array.isArray(options2.redact)) { - instance.redact = options2.redact; - const stringifiers = redaction(instance.redact, stringify2); - const formatOpts = { stringify: stringifiers[redactFmtSym] }; - instance[stringifySym] = stringify2; - instance[stringifiersSym] = stringifiers; - instance[formatOptsSym] = formatOpts; + if (!this.file) { + throw new Error("Unable to reopen a file descriptor, you must pass a file to SonicBoom"); } - if (typeof options2.msgPrefix === "string") { - instance[msgPrefixSym] = (this[msgPrefixSym] || "") + options2.msgPrefix; + if (file) { + this.file = file; } - instance[chindingsSym] = asChindings(instance, bindings2); - const childLevel = options2.level || this.level; - instance[setLevelSym](childLevel); - this.onChild(instance); - return instance; - } - function bindings() { - const chindings = this[chindingsSym]; - const chindingsJson = `{${chindings.substr(1)}}`; - const bindingsFromJson = JSON.parse(chindingsJson); - delete bindingsFromJson.pid; - delete bindingsFromJson.hostname; - return bindingsFromJson; - } - function setBindings(newBindings) { - const chindings = asChindings(this, newBindings); - this[chindingsSym] = chindings; - delete this[parsedChindingsSym]; - } - function defaultMixinMergeStrategy(mergeObject, mixinObject) { - return Object.assign(mixinObject, mergeObject); - } - function write(_obj, msg, num) { - const t = this[timeSym](); - const mixin3 = this[mixinSym]; - const errorKey = this[errorKeySym]; - const messageKey = this[messageKeySym]; - const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy; - let obj; - if (_obj === void 0 || _obj === null) { - obj = {}; - } else if (_obj instanceof Error) { - obj = { [errorKey]: _obj }; - if (msg === void 0) { - msg = _obj.message; + this._reopening = true; + if (this._writing) { + return; + } + const fd = this.fd; + this.once("ready", () => { + if (fd !== this.fd) { + fs.close(fd, (err) => { + if (err) { + return this.emit("error", err); + } + }); } + }); + openFile(this.file, this); + }; + SonicBoom.prototype.end = function() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); + } + if (this._opening) { + this.once("ready", () => { + this.end(); + }); + return; + } + if (this._ending) { + return; + } + this._ending = true; + if (this._writing) { + return; + } + if (this._len > 0 && this.fd >= 0) { + this._actualWrite(); } else { - obj = _obj; - if (msg === void 0 && _obj[messageKey] === void 0 && _obj[errorKey]) { - msg = _obj[errorKey].message; - } + actualClose(this); } - if (mixin3) { - obj = mixinMergeStrategy(obj, mixin3(obj, num, this)); + }; + function flushSync() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); } - const s = this[asJsonSym](obj, msg, num, t); - const stream = this[streamSym]; - if (stream[needsMetadataGsym] === true) { - stream.lastLevel = num; - stream.lastObj = obj; - stream.lastMsg = msg; - stream.lastTime = t.slice(this[timeSliceIndexSym]); - stream.lastLogger = this; + if (this.fd < 0) { + throw new Error("sonic boom is not ready yet"); } - stream.write(s); - } - function noop() { - } - function flush(cb) { - if (cb != null && typeof cb !== "function") { - throw Error("callback must be a function"); + if (!this._writing && this._writingBuf.length > 0) { + this._bufs.unshift(this._writingBuf); + this._writingBuf = ""; } - const stream = this[streamSym]; - if (typeof stream.flush === "function") { - stream.flush(cb || noop); - } else if (cb) cb(); - } - } -}); -var require_safe_stable_stringify = __commonJS({ - "node_modules/.deno/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports2, module14) { - "use strict"; - var { hasOwnProperty } = Object.prototype; - var stringify2 = configure(); - stringify2.configure = configure; - stringify2.stringify = stringify2; - stringify2.default = stringify2; - exports2.stringify = stringify2; - exports2.configure = configure; - module14.exports = stringify2; - var strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/; - function strEscape(str) { - if (str.length < 5e3 && !strEscapeSequencesRegExp.test(str)) { - return `"${str}"`; - } - return JSON.stringify(str); - } - function sort(array2, comparator) { - if (array2.length > 200 || comparator) { - return array2.sort(comparator); - } - for (let i2 = 1; i2 < array2.length; i2++) { - const currentValue = array2[i2]; - let position = i2; - while (position !== 0 && array2[position - 1] > currentValue) { - array2[position] = array2[position - 1]; - position--; + let buf2 = ""; + while (this._bufs.length || buf2) { + if (buf2.length <= 0) { + buf2 = this._bufs[0]; + } + try { + const n = fs.writeSync(this.fd, buf2, "utf8"); + const releasedBufObj = releaseWritingBuf(buf2, this._len, n); + buf2 = releasedBufObj.writingBuf; + this._len = releasedBufObj.len; + if (buf2.length <= 0) { + this._bufs.shift(); + } + } catch (err) { + const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; + if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { + throw err; + } + sleep(BUSY_WRITE_TIMEOUT); } - array2[position] = currentValue; } - return array2; - } - var typedArrayPrototypeGetSymbolToStringTag = Object.getOwnPropertyDescriptor( - Object.getPrototypeOf( - Object.getPrototypeOf( - new Int8Array() - ) - ), - Symbol.toStringTag - ).get; - function isTypedArrayWithEntries(value) { - return typedArrayPrototypeGetSymbolToStringTag.call(value) !== void 0 && value.length !== 0; + try { + fs.fsyncSync(this.fd); + } catch { + } } - function stringifyTypedArray(array2, separator, maximumBreadth) { - if (array2.length < maximumBreadth) { - maximumBreadth = array2.length; + function flushBufferSync() { + if (this.destroyed) { + throw new Error("SonicBoom destroyed"); } - const whitespace = separator === "," ? "" : " "; - let res = `"0":${whitespace}${array2[0]}`; - for (let i2 = 1; i2 < maximumBreadth; i2++) { - res += `${separator}"${i2}":${whitespace}${array2[i2]}`; + if (this.fd < 0) { + throw new Error("sonic boom is not ready yet"); } - return res; - } - function getCircularValueOption(options2) { - if (hasOwnProperty.call(options2, "circularValue")) { - const circularValue = options2.circularValue; - if (typeof circularValue === "string") { - return `"${circularValue}"`; - } - if (circularValue == null) { - return circularValue; + if (!this._writing && this._writingBuf.length > 0) { + this._bufs.unshift([this._writingBuf]); + this._writingBuf = kEmptyBuffer; + } + let buf2 = kEmptyBuffer; + while (this._bufs.length || buf2.length) { + if (buf2.length <= 0) { + buf2 = mergeBuf(this._bufs[0], this._lens[0]); } - if (circularValue === Error || circularValue === TypeError) { - return { - toString() { - throw new TypeError("Converting circular structure to JSON"); - } - }; + try { + const n = fs.writeSync(this.fd, buf2); + buf2 = buf2.subarray(n); + this._len = Math.max(this._len - n, 0); + if (buf2.length <= 0) { + this._bufs.shift(); + this._lens.shift(); + } + } catch (err) { + const shouldRetry = err.code === "EAGAIN" || err.code === "EBUSY"; + if (shouldRetry && !this.retryEAGAIN(err, buf2.length, this._len - buf2.length)) { + throw err; + } + sleep(BUSY_WRITE_TIMEOUT); } - throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined'); } - return '"[Circular]"'; } - function getDeterministicOption(options2) { - let value; - if (hasOwnProperty.call(options2, "deterministic")) { - value = options2.deterministic; - if (typeof value !== "boolean" && typeof value !== "function") { - throw new TypeError('The "deterministic" argument must be of type boolean or comparator function'); + SonicBoom.prototype.destroy = function() { + if (this.destroyed) { + return; + } + actualClose(this); + }; + function actualWrite() { + const release = this.release; + this._writing = true; + this._writingBuf = this._writingBuf || this._bufs.shift() || ""; + if (this.sync) { + try { + const written = fs.writeSync(this.fd, this._writingBuf, "utf8"); + release(null, written); + } catch (err) { + release(err); } + } else { + fs.write(this.fd, this._writingBuf, "utf8", release); } - return value === void 0 ? true : value; } - function getBooleanOption(options2, key) { - let value; - if (hasOwnProperty.call(options2, key)) { - value = options2[key]; - if (typeof value !== "boolean") { - throw new TypeError(`The "${key}" argument must be of type boolean`); + function actualWriteBuffer() { + const release = this.release; + this._writing = true; + this._writingBuf = this._writingBuf.length ? this._writingBuf : mergeBuf(this._bufs.shift(), this._lens.shift()); + if (this.sync) { + try { + const written = fs.writeSync(this.fd, this._writingBuf); + release(null, written); + } catch (err) { + release(err); } + } else { + fs.write(this.fd, this._writingBuf, release); } - return value === void 0 ? true : value; } - function getPositiveIntegerOption(options2, key) { - let value; - if (hasOwnProperty.call(options2, key)) { - value = options2[key]; - if (typeof value !== "number") { - throw new TypeError(`The "${key}" argument must be of type number`); + function actualClose(sonic) { + if (sonic.fd === -1) { + sonic.once("ready", actualClose.bind(null, sonic)); + return; + } + sonic.destroyed = true; + sonic._bufs = []; + sonic._lens = []; + fs.fsync(sonic.fd, closeWrapped); + function closeWrapped() { + if (sonic.fd !== 1 && sonic.fd !== 2) { + fs.close(sonic.fd, done); + } else { + done(); } - if (!Number.isInteger(value)) { - throw new TypeError(`The "${key}" argument must be an integer`); + } + function done(err) { + if (err) { + sonic.emit("error", err); + return; } - if (value < 1) { - throw new RangeError(`The "${key}" argument must be >= 1`); + if (sonic._ending && !sonic._writing) { + sonic.emit("finish"); } + sonic.emit("close"); } - return value === void 0 ? Infinity : value; } - function getItemCount(number3) { - if (number3 === 1) { - return "1 item"; + SonicBoom.SonicBoom = SonicBoom; + SonicBoom.default = SonicBoom; + module14.exports = SonicBoom; + } +}); +var require_on_exit_leak_free = __commonJS({ + "node_modules/.deno/on-exit-leak-free@2.1.2/node_modules/on-exit-leak-free/index.js"(exports2, module14) { + "use strict"; + var refs = { + exit: [], + beforeExit: [] + }; + var functions = { + exit: onExit, + beforeExit: onBeforeExit + }; + var registry2; + function ensureRegistry() { + if (registry2 === void 0) { + registry2 = new FinalizationRegistry(clear); } - return `${number3} items`; } - function getUniqueReplacerSet(replacerArray) { - const replacerSet = /* @__PURE__ */ new Set(); - for (const value of replacerArray) { - if (typeof value === "string" || typeof value === "number") { - replacerSet.add(String(value)); - } + function install(event) { + if (refs[event].length > 0) { + return; } - return replacerSet; + process.on(event, functions[event]); } - function getStrictOption(options2) { - if (hasOwnProperty.call(options2, "strict")) { - const value = options2.strict; - if (typeof value !== "boolean") { - throw new TypeError('The "strict" argument must be of type boolean'); - } - if (value) { - return (value2) => { - let message = `Object can not safely be stringified. Received type ${typeof value2}`; - if (typeof value2 !== "function") message += ` (${value2.toString()})`; - throw new Error(message); - }; + function uninstall(event) { + if (refs[event].length > 0) { + return; + } + process.removeListener(event, functions[event]); + if (refs.exit.length === 0 && refs.beforeExit.length === 0) { + registry2 = void 0; + } + } + function onExit() { + callRefs("exit"); + } + function onBeforeExit() { + callRefs("beforeExit"); + } + function callRefs(event) { + for (const ref of refs[event]) { + const obj = ref.deref(); + const fn = ref.fn; + if (obj !== void 0) { + fn(obj, event); } } + refs[event] = []; } - function configure(options2) { - options2 = { ...options2 }; - const fail = getStrictOption(options2); - if (fail) { - if (options2.bigint === void 0) { - options2.bigint = false; + function clear(ref) { + for (const event of ["exit", "beforeExit"]) { + const index = refs[event].indexOf(ref); + refs[event].splice(index, index + 1); + uninstall(event); + } + } + function _register(event, obj, fn) { + if (obj === void 0) { + throw new Error("the object can't be undefined"); + } + install(event); + const ref = new WeakRef(obj); + ref.fn = fn; + ensureRegistry(); + registry2.register(obj, ref); + refs[event].push(ref); + } + function register2(obj, fn) { + _register("exit", obj, fn); + } + function registerBeforeExit(obj, fn) { + _register("beforeExit", obj, fn); + } + function unregister(obj) { + if (registry2 === void 0) { + return; + } + registry2.unregister(obj); + for (const event of ["exit", "beforeExit"]) { + refs[event] = refs[event].filter((ref) => { + const _obj = ref.deref(); + return _obj && _obj !== obj; + }); + uninstall(event); + } + } + module14.exports = { + register: register2, + registerBeforeExit, + unregister + }; + } +}); +var require_package3 = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/package.json"(exports2, module14) { + module14.exports = { + name: "thread-stream", + version: "2.7.0", + description: "A streaming way to send data to a Node.js Worker Thread", + main: "index.js", + types: "index.d.ts", + dependencies: { + "real-require": "^0.2.0" + }, + devDependencies: { + "@types/node": "^20.1.0", + "@types/tap": "^15.0.0", + "@yao-pkg/pkg": "^5.11.5", + desm: "^1.3.0", + fastbench: "^1.0.1", + husky: "^9.0.6", + "pino-elasticsearch": "^8.0.0", + "sonic-boom": "^3.0.0", + standard: "^17.0.0", + tap: "^16.2.0", + "ts-node": "^10.8.0", + typescript: "^5.3.2", + "why-is-node-running": "^2.2.2" + }, + scripts: { + test: 'standard && npm run transpile && tap "test/**/*.test.*js" && tap --ts test/*.test.*ts', + "test:ci": "standard && npm run transpile && npm run test:ci:js && npm run test:ci:ts", + "test:ci:js": 'tap --no-check-coverage --timeout=120 --coverage-report=lcovonly "test/**/*.test.*js"', + "test:ci:ts": 'tap --ts --no-check-coverage --coverage-report=lcovonly "test/**/*.test.*ts"', + "test:yarn": 'npm run transpile && tap "test/**/*.test.js" --no-check-coverage', + transpile: "sh ./test/ts/transpile.sh", + prepare: "husky install" + }, + standard: { + ignore: [ + "test/ts/**/*" + ] + }, + repository: { + type: "git", + url: "git+https://github.com/mcollina/thread-stream.git" + }, + keywords: [ + "worker", + "thread", + "threads", + "stream" + ], + author: "Matteo Collina ", + license: "MIT", + bugs: { + url: "https://github.com/mcollina/thread-stream/issues" + }, + homepage: "https://github.com/mcollina/thread-stream#readme" + }; + } +}); +var require_wait = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/wait.js"(exports2, module14) { + "use strict"; + var MAX_TIMEOUT = 1e3; + function wait(state, index, expected, timeout, done) { + const max = Date.now() + timeout; + let current = Atomics.load(state, index); + if (current === expected) { + done(null, "ok"); + return; + } + let prior = current; + const check2 = (backoff) => { + if (Date.now() > max) { + done(null, "timed-out"); + } else { + setTimeout(() => { + prior = current; + current = Atomics.load(state, index); + if (current === prior) { + check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); + } else { + if (current === expected) done(null, "ok"); + else done(null, "not-equal"); + } + }, backoff); } - if (!("circularValue" in options2)) { - options2.circularValue = Error; + }; + check2(1); + } + function waitDiff(state, index, expected, timeout, done) { + const max = Date.now() + timeout; + let current = Atomics.load(state, index); + if (current !== expected) { + done(null, "ok"); + return; + } + const check2 = (backoff) => { + if (Date.now() > max) { + done(null, "timed-out"); + } else { + setTimeout(() => { + current = Atomics.load(state, index); + if (current !== expected) { + done(null, "ok"); + } else { + check2(backoff >= MAX_TIMEOUT ? MAX_TIMEOUT : backoff * 2); + } + }, backoff); } + }; + check2(1); + } + module14.exports = { wait, waitDiff }; + } +}); +var require_indexes = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/lib/indexes.js"(exports2, module14) { + "use strict"; + var WRITE_INDEX = 4; + var READ_INDEX = 8; + module14.exports = { + WRITE_INDEX, + READ_INDEX + }; + } +}); +var require_thread_stream = __commonJS({ + "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports2, module14) { + "use strict"; + var { version: version3 } = require_package3(); + var { EventEmitter } = __require2("events"); + var { Worker: Worker2 } = __require2("worker_threads"); + var { join: join10 } = __require2("path"); + var { pathToFileURL: pathToFileURL2 } = __require2("url"); + var { wait } = require_wait(); + var { + WRITE_INDEX, + READ_INDEX + } = require_indexes(); + var buffer = __require2("buffer"); + var assert2 = __require2("assert"); + var kImpl = Symbol("kImpl"); + var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; + var FakeWeakRef = class { + constructor(value) { + this._value = value; } - const circularValue = getCircularValueOption(options2); - const bigint2 = getBooleanOption(options2, "bigint"); - const deterministic = getDeterministicOption(options2); - const comparator = typeof deterministic === "function" ? deterministic : void 0; - const maximumDepth = getPositiveIntegerOption(options2, "maximumDepth"); - const maximumBreadth = getPositiveIntegerOption(options2, "maximumBreadth"); - function stringifyFnReplacer(key, parent, stack, replacer, spacer, indentation) { - let value = parent[key]; - if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { - value = value.toJSON(key); + deref() { + return this._value; + } + }; + var FakeFinalizationRegistry = class { + register() { + } + unregister() { + } + }; + var FinalizationRegistry2 = process.env.NODE_V8_COVERAGE ? FakeFinalizationRegistry : global.FinalizationRegistry || FakeFinalizationRegistry; + var WeakRef2 = process.env.NODE_V8_COVERAGE ? FakeWeakRef : global.WeakRef || FakeWeakRef; + var registry2 = new FinalizationRegistry2((worker) => { + if (worker.exited) { + return; + } + worker.terminate(); + }); + function createWorker2(stream, opts) { + const { filename, workerData } = opts; + const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; + const toExecute = bundlerOverrides["thread-stream-worker"] || join10(__dirname, "lib", "worker.js"); + const worker = new Worker2(toExecute, { + ...opts.workerOpts, + trackUnmanagedFds: false, + workerData: { + filename: filename.indexOf("file://") === 0 ? filename : pathToFileURL2(filename).href, + dataBuf: stream[kImpl].dataBuf, + stateBuf: stream[kImpl].stateBuf, + workerData: { + $context: { + threadStreamVersion: version3 + }, + ...workerData + } } - value = replacer.call(parent, key, value); - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - let res = ""; - let join10 = ","; - const originalIndentation = indentation; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - if (spacer !== "") { - indentation += spacer; - res += ` -${indentation}`; - join10 = `, -${indentation}`; - } - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += join10; - } - const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; - } - if (spacer !== "") { - res += ` -${originalIndentation}`; - } - stack.pop(); - return `[${res}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - let whitespace = ""; - let separator = ""; - if (spacer !== "") { - indentation += spacer; - join10 = `, -${indentation}`; - whitespace = " "; - } - const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (deterministic && !isTypedArrayWithEntries(value)) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join10; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`; - separator = join10; + }); + worker.stream = new FakeWeakRef(stream); + worker.on("message", onWorkerMessage); + worker.on("exit", onWorkerExit); + registry2.register(stream, worker); + return worker; + } + function drain(stream) { + assert2(!stream[kImpl].sync); + if (stream[kImpl].needDrain) { + stream[kImpl].needDrain = false; + stream.emit("drain"); + } + } + function nextFlush(stream) { + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let leftover = stream[kImpl].data.length - writeIndex; + if (leftover > 0) { + if (stream[kImpl].buf.length === 0) { + stream[kImpl].flushing = false; + if (stream[kImpl].ending) { + end(stream); + } else if (stream[kImpl].needDrain) { + process.nextTick(drain, stream); + } + return; + } + let toWrite = stream[kImpl].buf.slice(0, leftover); + let toWriteBytes = Buffer.byteLength(toWrite); + if (toWriteBytes <= leftover) { + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, nextFlush.bind(null, stream)); + } else { + stream.flush(() => { + if (stream.destroyed) { + return; } - if (spacer !== "" && separator.length > 1) { - res = ` -${indentation}${res} -${originalIndentation}`; + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + while (toWriteBytes > stream[kImpl].data.length) { + leftover = leftover / 2; + toWrite = stream[kImpl].buf.slice(0, leftover); + toWriteBytes = Buffer.byteLength(toWrite); } - stack.pop(); - return `{${res}}`; + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, nextFlush.bind(null, stream)); + }); + } + } else if (leftover === 0) { + if (writeIndex === 0 && stream[kImpl].buf.length === 0) { + return; + } + stream.flush(() => { + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + nextFlush(stream); + }); + } else { + destroy(stream, new Error("overwritten")); + } + } + function onWorkerMessage(msg) { + const stream = this.stream.deref(); + if (stream === void 0) { + this.exited = true; + this.terminate(); + return; + } + switch (msg.code) { + case "READY": + this.stream = new WeakRef2(stream); + stream.flush(() => { + stream[kImpl].ready = true; + stream.emit("ready"); + }); + break; + case "ERROR": + destroy(stream, msg.err); + break; + case "EVENT": + if (Array.isArray(msg.args)) { + stream.emit(msg.name, ...msg.args); + } else { + stream.emit(msg.name, msg.args); } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; + break; + case "WARNING": + process.emitWarning(msg.err); + break; + default: + destroy(stream, new Error("this should not happen: " + msg.code)); + } + } + function onWorkerExit(code2) { + const stream = this.stream.deref(); + if (stream === void 0) { + return; + } + registry2.unregister(stream); + stream.worker.exited = true; + stream.worker.off("exit", onWorkerExit); + destroy(stream, code2 !== 0 ? new Error("the worker thread exited") : null); + } + var ThreadStream = class extends EventEmitter { + constructor(opts = {}) { + super(); + if (opts.bufferSize < 4) { + throw new Error("bufferSize must at least fit a 4-byte utf-8 char"); } + this[kImpl] = {}; + this[kImpl].stateBuf = new SharedArrayBuffer(128); + this[kImpl].state = new Int32Array(this[kImpl].stateBuf); + this[kImpl].dataBuf = new SharedArrayBuffer(opts.bufferSize || 4 * 1024 * 1024); + this[kImpl].data = Buffer.from(this[kImpl].dataBuf); + this[kImpl].sync = opts.sync || false; + this[kImpl].ending = false; + this[kImpl].ended = false; + this[kImpl].needDrain = false; + this[kImpl].destroyed = false; + this[kImpl].flushing = false; + this[kImpl].ready = false; + this[kImpl].finished = false; + this[kImpl].errored = null; + this[kImpl].closed = false; + this[kImpl].buf = ""; + this.worker = createWorker2(this, opts); + this.on("message", (message, transferList) => { + this.worker.postMessage(message, transferList); + }); } - function stringifyArrayReplacer(key, value, stack, replacer, spacer, indentation) { - if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { - value = value.toJSON(key); + write(data) { + if (this[kImpl].destroyed) { + error2(this, new Error("the worker has exited")); + return false; } - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - const originalIndentation = indentation; - let res = ""; - let join10 = ","; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - if (spacer !== "") { - indentation += spacer; - res += ` -${indentation}`; - join10 = `, -${indentation}`; - } - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += join10; - } - const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; - } - if (spacer !== "") { - res += ` -${originalIndentation}`; - } - stack.pop(); - return `[${res}]`; - } - stack.push(value); - let whitespace = ""; - if (spacer !== "") { - indentation += spacer; - join10 = `, -${indentation}`; - whitespace = " "; - } - let separator = ""; - for (const key2 of replacer) { - const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; - separator = join10; - } - } - if (spacer !== "" && separator.length > 1) { - res = ` -${indentation}${res} -${originalIndentation}`; - } - stack.pop(); - return `{${res}}`; + if (this[kImpl].ending) { + error2(this, new Error("the worker is ending")); + return false; + } + if (this[kImpl].flushing && this[kImpl].buf.length + data.length >= MAX_STRING) { + try { + writeSync(this); + this[kImpl].flushing = true; + } catch (err) { + destroy(this, err); + return false; } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; } + this[kImpl].buf += data; + if (this[kImpl].sync) { + try { + writeSync(this); + return true; + } catch (err) { + destroy(this, err); + return false; + } + } + if (!this[kImpl].flushing) { + this[kImpl].flushing = true; + setImmediate(nextFlush, this); + } + this[kImpl].needDrain = this[kImpl].data.length - this[kImpl].buf.length - Atomics.load(this[kImpl].state, WRITE_INDEX) <= 0; + return !this[kImpl].needDrain; } - function stringifyIndent(key, value, stack, spacer, indentation) { - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (typeof value.toJSON === "function") { - value = value.toJSON(key); - if (typeof value !== "object") { - return stringifyIndent(key, value, stack, spacer, indentation); - } - if (value === null) { - return "null"; - } - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - const originalIndentation = indentation; - if (Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - indentation += spacer; - let res2 = ` -${indentation}`; - const join11 = `, -${indentation}`; - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); - res2 += tmp2 !== void 0 ? tmp2 : "null"; - res2 += join11; - } - const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); - res2 += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res2 += `${join11}"... ${getItemCount(removedKeys)} not stringified"`; - } - res2 += ` -${originalIndentation}`; - stack.pop(); - return `[${res2}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - indentation += spacer; - const join10 = `, -${indentation}`; - let res = ""; - let separator = ""; - let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (isTypedArrayWithEntries(value)) { - res += stringifyTypedArray(value, join10, maximumBreadth); - keys = keys.slice(value.length); - maximumPropertiesToStringify -= value.length; - separator = join10; - } - if (deterministic) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}: ${tmp}`; - separator = join10; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`; - separator = join10; - } - if (separator !== "") { - res = ` -${indentation}${res} -${originalIndentation}`; - } - stack.pop(); - return `{${res}}`; + end() { + if (this[kImpl].destroyed) { + return; + } + this[kImpl].ending = true; + end(this); + } + flush(cb) { + if (this[kImpl].destroyed) { + if (typeof cb === "function") { + process.nextTick(cb, new Error("the worker has exited")); } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; + return; } + const writeIndex = Atomics.load(this[kImpl].state, WRITE_INDEX); + wait(this[kImpl].state, READ_INDEX, writeIndex, Infinity, (err, res) => { + if (err) { + destroy(this, err); + process.nextTick(cb, err); + return; + } + if (res === "not-equal") { + this.flush(cb); + return; + } + process.nextTick(cb); + }); } - function stringifySimple(key, value, stack) { - switch (typeof value) { - case "string": - return strEscape(value); - case "object": { - if (value === null) { - return "null"; - } - if (typeof value.toJSON === "function") { - value = value.toJSON(key); - if (typeof value !== "object") { - return stringifySimple(key, value, stack); - } - if (value === null) { - return "null"; - } - } - if (stack.indexOf(value) !== -1) { - return circularValue; - } - let res = ""; - const hasLength = value.length !== void 0; - if (hasLength && Array.isArray(value)) { - if (value.length === 0) { - return "[]"; - } - if (maximumDepth < stack.length + 1) { - return '"[Array]"'; - } - stack.push(value); - const maximumValuesToStringify = Math.min(value.length, maximumBreadth); - let i2 = 0; - for (; i2 < maximumValuesToStringify - 1; i2++) { - const tmp2 = stringifySimple(String(i2), value[i2], stack); - res += tmp2 !== void 0 ? tmp2 : "null"; - res += ","; - } - const tmp = stringifySimple(String(i2), value[i2], stack); - res += tmp !== void 0 ? tmp : "null"; - if (value.length - 1 > maximumBreadth) { - const removedKeys = value.length - maximumBreadth - 1; - res += `,"... ${getItemCount(removedKeys)} not stringified"`; - } - stack.pop(); - return `[${res}]`; - } - let keys = Object.keys(value); - const keyLength = keys.length; - if (keyLength === 0) { - return "{}"; - } - if (maximumDepth < stack.length + 1) { - return '"[Object]"'; - } - let separator = ""; - let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); - if (hasLength && isTypedArrayWithEntries(value)) { - res += stringifyTypedArray(value, ",", maximumBreadth); - keys = keys.slice(value.length); - maximumPropertiesToStringify -= value.length; - separator = ","; - } - if (deterministic) { - keys = sort(keys, comparator); - } - stack.push(value); - for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { - const key2 = keys[i2]; - const tmp = stringifySimple(key2, value[key2], stack); - if (tmp !== void 0) { - res += `${separator}${strEscape(key2)}:${tmp}`; - separator = ","; - } - } - if (keyLength > maximumBreadth) { - const removedKeys = keyLength - maximumBreadth; - res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`; - } - stack.pop(); - return `{${res}}`; - } - case "number": - return isFinite(value) ? String(value) : fail ? fail(value) : "null"; - case "boolean": - return value === true ? "true" : "false"; - case "undefined": - return void 0; - case "bigint": - if (bigint2) { - return String(value); - } - // fallthrough - default: - return fail ? fail(value) : void 0; + flushSync() { + if (this[kImpl].destroyed) { + return; } + writeSync(this); + flushSync(this); } - function stringify3(value, replacer, space) { - if (arguments.length > 1) { - let spacer = ""; - if (typeof space === "number") { - spacer = " ".repeat(Math.min(space, 10)); - } else if (typeof space === "string") { - spacer = space.slice(0, 10); - } - if (replacer != null) { - if (typeof replacer === "function") { - return stringifyFnReplacer("", { "": value }, [], replacer, spacer, ""); - } - if (Array.isArray(replacer)) { - return stringifyArrayReplacer("", value, [], getUniqueReplacerSet(replacer), spacer, ""); - } - } - if (spacer.length !== 0) { - return stringifyIndent("", value, [], spacer, ""); - } - } - return stringifySimple("", value, []); + unref() { + this.worker.unref(); } - return stringify3; + ref() { + this.worker.ref(); + } + get ready() { + return this[kImpl].ready; + } + get destroyed() { + return this[kImpl].destroyed; + } + get closed() { + return this[kImpl].closed; + } + get writable() { + return !this[kImpl].destroyed && !this[kImpl].ending; + } + get writableEnded() { + return this[kImpl].ending; + } + get writableFinished() { + return this[kImpl].finished; + } + get writableNeedDrain() { + return this[kImpl].needDrain; + } + get writableObjectMode() { + return false; + } + get writableErrored() { + return this[kImpl].errored; + } + }; + function error2(stream, err) { + setImmediate(() => { + stream.emit("error", err); + }); } - } -}); -var require_multistream = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/multistream.js"(exports2, module14) { - "use strict"; - var metadata = Symbol.for("pino.metadata"); - var { DEFAULT_LEVELS } = require_constants(); - var DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info; - function multistream(streamsArray, opts) { - let counter = 0; - streamsArray = streamsArray || []; - opts = opts || { dedupe: false }; - const streamLevels = Object.create(DEFAULT_LEVELS); - streamLevels.silent = Infinity; - if (opts.levels && typeof opts.levels === "object") { - Object.keys(opts.levels).forEach((i2) => { - streamLevels[i2] = opts.levels[i2]; - }); + function destroy(stream, err) { + if (stream[kImpl].destroyed) { + return; } - const res = { - write, - add, - flushSync, - end, - minLevel: 0, - streams: [], - clone: clone2, - [metadata]: true, - streamLevels - }; - if (Array.isArray(streamsArray)) { - streamsArray.forEach(add, res); + stream[kImpl].destroyed = true; + if (err) { + stream[kImpl].errored = err; + error2(stream, err); + } + if (!stream.worker.exited) { + stream.worker.terminate().catch(() => { + }).then(() => { + stream[kImpl].closed = true; + stream.emit("close"); + }); } else { - add.call(res, streamsArray); + setImmediate(() => { + stream[kImpl].closed = true; + stream.emit("close"); + }); } - streamsArray = null; - return res; - function write(data) { - let dest; - const level = this.lastLevel; - const { streams } = this; - let recordedLevel = 0; - let stream; - for (let i2 = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i2, streams.length, opts.dedupe); i2 = adjustLoopVar(i2, opts.dedupe)) { - dest = streams[i2]; - if (dest.level <= level) { - if (recordedLevel !== 0 && recordedLevel !== dest.level) { - break; - } - stream = dest.stream; - if (stream[metadata]) { - const { lastTime, lastMsg, lastObj, lastLogger } = this; - stream.lastLevel = level; - stream.lastTime = lastTime; - stream.lastMsg = lastMsg; - stream.lastObj = lastObj; - stream.lastLogger = lastLogger; - } - stream.write(data); - if (opts.dedupe) { - recordedLevel = dest.level; - } - } else if (!opts.dedupe) { - break; + } + function write(stream, data, cb) { + const current = Atomics.load(stream[kImpl].state, WRITE_INDEX); + const length2 = Buffer.byteLength(data); + stream[kImpl].data.write(data, current); + Atomics.store(stream[kImpl].state, WRITE_INDEX, current + length2); + Atomics.notify(stream[kImpl].state, WRITE_INDEX); + cb(); + return true; + } + function end(stream) { + if (stream[kImpl].ended || !stream[kImpl].ending || stream[kImpl].flushing) { + return; + } + stream[kImpl].ended = true; + try { + stream.flushSync(); + let readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + Atomics.store(stream[kImpl].state, WRITE_INDEX, -1); + Atomics.notify(stream[kImpl].state, WRITE_INDEX); + let spins = 0; + while (readIndex !== -1) { + Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); + readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + if (readIndex === -2) { + destroy(stream, new Error("end() failed")); + return; + } + if (++spins === 10) { + destroy(stream, new Error("end() took too long (10s)")); + return; } } + process.nextTick(() => { + stream[kImpl].finished = true; + stream.emit("finish"); + }); + } catch (err) { + destroy(stream, err); } - function flushSync() { - for (const { stream } of this.streams) { - if (typeof stream.flushSync === "function") { - stream.flushSync(); + } + function writeSync(stream) { + const cb = () => { + if (stream[kImpl].ending) { + end(stream); + } else if (stream[kImpl].needDrain) { + process.nextTick(drain, stream); + } + }; + stream[kImpl].flushing = false; + while (stream[kImpl].buf.length !== 0) { + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let leftover = stream[kImpl].data.length - writeIndex; + if (leftover === 0) { + flushSync(stream); + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + continue; + } else if (leftover < 0) { + throw new Error("overwritten"); + } + let toWrite = stream[kImpl].buf.slice(0, leftover); + let toWriteBytes = Buffer.byteLength(toWrite); + if (toWriteBytes <= leftover) { + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, cb); + } else { + flushSync(stream); + Atomics.store(stream[kImpl].state, READ_INDEX, 0); + Atomics.store(stream[kImpl].state, WRITE_INDEX, 0); + while (toWriteBytes > stream[kImpl].buf.length) { + leftover = leftover / 2; + toWrite = stream[kImpl].buf.slice(0, leftover); + toWriteBytes = Buffer.byteLength(toWrite); } + stream[kImpl].buf = stream[kImpl].buf.slice(leftover); + write(stream, toWrite, cb); } } - function add(dest) { - if (!dest) { - return res; - } - const isStream = typeof dest.write === "function" || dest.stream; - const stream_ = dest.write ? dest : dest.stream; - if (!isStream) { - throw Error("stream object needs to implement either StreamEntry or DestinationStream interface"); + } + function flushSync(stream) { + if (stream[kImpl].flushing) { + throw new Error("unable to flush while flushing"); + } + const writeIndex = Atomics.load(stream[kImpl].state, WRITE_INDEX); + let spins = 0; + while (true) { + const readIndex = Atomics.load(stream[kImpl].state, READ_INDEX); + if (readIndex === -2) { + throw Error("_flushSync failed"); } - const { streams, streamLevels: streamLevels2 } = this; - let level; - if (typeof dest.levelVal === "number") { - level = dest.levelVal; - } else if (typeof dest.level === "string") { - level = streamLevels2[dest.level]; - } else if (typeof dest.level === "number") { - level = dest.level; + if (readIndex !== writeIndex) { + Atomics.wait(stream[kImpl].state, READ_INDEX, readIndex, 1e3); } else { - level = DEFAULT_INFO_LEVEL; + break; + } + if (++spins === 10) { + throw new Error("_flushSync took too long (10s)"); } - const dest_ = { - stream: stream_, - level, - levelVal: void 0, - id: counter++ - }; - streams.unshift(dest_); - streams.sort(compareByLevel); - this.minLevel = streams[0].level; - return res; } - function end() { - for (const { stream } of this.streams) { - if (typeof stream.flushSync === "function") { - stream.flushSync(); - } - stream.end(); + } + module14.exports = ThreadStream; + } +}); +var require_transport = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports2, module14) { + "use strict"; + var { createRequire } = __require2("module"); + var getCallers = require_caller(); + var { join: join10, isAbsolute: isAbsolute8, sep } = __require2("path"); + var sleep = require_atomic_sleep(); + var onExit = require_on_exit_leak_free(); + var ThreadStream = require_thread_stream(); + function setupOnExit(stream) { + onExit.register(stream, autoEnd); + onExit.registerBeforeExit(stream, flush); + stream.on("close", function() { + onExit.unregister(stream); + }); + } + function buildStream(filename, workerData, workerOpts) { + const stream = new ThreadStream({ + filename, + workerData, + workerOpts + }); + stream.on("ready", onReady); + stream.on("close", function() { + process.removeListener("exit", onExit2); + }); + process.on("exit", onExit2); + function onReady() { + process.removeListener("exit", onExit2); + stream.unref(); + if (workerOpts.autoEnd !== false) { + setupOnExit(stream); } } - function clone2(level) { - const streams = new Array(this.streams.length); - for (let i2 = 0; i2 < streams.length; i2++) { - streams[i2] = { - level, - stream: this.streams[i2].stream - }; + function onExit2() { + if (stream.closed) { + return; } - return { - write, - add, - minLevel: level, - streams, - clone: clone2, - flushSync, - [metadata]: true - }; + stream.flushSync(); + sleep(100); + stream.end(); } + return stream; } - function compareByLevel(a, b) { - return a.level - b.level; - } - function initLoopVar(length2, dedupe) { - return dedupe ? length2 - 1 : 0; + function autoEnd(stream) { + stream.ref(); + stream.flushSync(); + stream.end(); + stream.once("close", function() { + stream.unref(); + }); } - function adjustLoopVar(i2, dedupe) { - return dedupe ? i2 - 1 : i2 + 1; + function flush(stream) { + stream.flushSync(); } - function checkLoopVar(i2, length2, dedupe) { - return dedupe ? i2 >= 0 : i2 < length2; + function transport(fullOptions) { + const { pipeline, targets, levels, dedupe, options: options2 = {}, worker = {}, caller = getCallers() } = fullOptions; + const callers = typeof caller === "string" ? [caller] : caller; + const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {}; + let target = fullOptions.target; + if (target && targets) { + throw new Error("only one of target or targets can be specified"); + } + if (targets) { + target = bundlerOverrides["pino-worker"] || join10(__dirname, "worker.js"); + options2.targets = targets.map((dest) => { + return { + ...dest, + target: fixTarget(dest.target) + }; + }); + } else if (pipeline) { + target = bundlerOverrides["pino-pipeline-worker"] || join10(__dirname, "worker-pipeline.js"); + options2.targets = pipeline.map((dest) => { + return { + ...dest, + target: fixTarget(dest.target) + }; + }); + } + if (levels) { + options2.levels = levels; + } + if (dedupe) { + options2.dedupe = dedupe; + } + return buildStream(fixTarget(target), options2, worker); + function fixTarget(origin) { + origin = bundlerOverrides[origin] || origin; + if (isAbsolute8(origin) || origin.indexOf("file://") === 0) { + return origin; + } + if (origin === "pino/file") { + return join10(__dirname, "..", "file.js"); + } + let fixTarget2; + for (const filePath of callers) { + try { + const context = filePath === "node:repl" ? process.cwd() + sep : filePath; + fixTarget2 = createRequire(context).resolve(origin); + break; + } catch (err) { + continue; + } + } + if (!fixTarget2) { + throw new Error(`unable to determine transport target for "${origin}"`); + } + return fixTarget2; + } } - module14.exports = multistream; + module14.exports = transport; } }); -var require_pino = __commonJS({ - "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports2, module14) { +var require_tools = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/tools.js"(exports2, module14) { "use strict"; - var os = __require2("os"); - var stdSerializers = require_pino_std_serializers(); - var caller = require_caller(); - var redaction = require_redaction(); - var time3 = require_time(); - var proto3 = require_proto(); - var symbols2 = require_symbols(); - var { configure } = require_safe_stable_stringify(); - var { assertDefaultLevelFound, mappings, genLsCache, genLevelComparison, assertLevelComparison } = require_levels(); - var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); - var { - createArgsNormalizer, - asChindings, - buildSafeSonicBoom, - buildFormatters, - stringify: stringify2, - normalizeDestFileDescriptor, - noop - } = require_tools(); - var { version: version3 } = require_meta(); + var format52 = require_quick_format_unescaped(); + var { mapHttpRequest, mapHttpResponse } = require_pino_std_serializers(); + var SonicBoom = require_sonic_boom(); + var onExit = require_on_exit_leak_free(); var { + lsCacheSym, chindingsSym, - redactFmtSym, + writeSym, serializersSym, - timeSym, - timeSliceIndexSym, - streamSym, + formatOptsSym, + endSym, + stringifiersSym, stringifySym, stringifySafeSym, - stringifiersSym, - setLevelSym, - endSym, - formatOptsSym, - messageKeySym, - errorKeySym, + wildcardFirstSym, nestedKeySym, - mixinSym, - levelCompSym, - useOnlyCustomLevelsSym, formattersSym, - hooksSym, + messageKeySym, + errorKeySym, nestedKeyStrSym, - mixinMergeStrategySym, msgPrefixSym - } = symbols2; - var { epochTime, nullTime } = time3; - var { pid } = process; - var hostname2 = os.hostname(); - var defaultErrorSerializer = stdSerializers.err; - var defaultOptions4 = { - level: "info", - levelComparison: SORTING_ORDER.ASC, - levels: DEFAULT_LEVELS, - messageKey: "msg", - errorKey: "err", - nestedKey: null, - enabled: true, - base: { pid, hostname: hostname2 }, - serializers: Object.assign(/* @__PURE__ */ Object.create(null), { - err: defaultErrorSerializer - }), - formatters: Object.assign(/* @__PURE__ */ Object.create(null), { - bindings(bindings) { - return bindings; - }, - level(label, number3) { - return { level: number3 }; - } - }), - hooks: { - logMethod: void 0 - }, - timestamp: epochTime, - name: void 0, - redact: null, - customLevels: null, - useOnlyCustomLevels: false, - depthLimit: 5, - edgeLimit: 100 - }; - var normalize32 = createArgsNormalizer(defaultOptions4); - var serializers = Object.assign(/* @__PURE__ */ Object.create(null), stdSerializers); - function pino2(...args) { - const instance = {}; - const { opts, stream } = normalize32(instance, caller(), ...args); - const { - redact, - crlf, - serializers: serializers2, - timestamp, - messageKey, - errorKey, - nestedKey, - base: base2, - name, - level, - customLevels, - levelComparison, - mixin: mixin3, - mixinMergeStrategy, - useOnlyCustomLevels, - formatters, - hooks, - depthLimit, - edgeLimit, - onChild, - msgPrefix - } = opts; - const stringifySafe = configure({ - maximumDepth: depthLimit, - maximumBreadth: edgeLimit - }); - const allFormatters = buildFormatters( - formatters.level, - formatters.bindings, - formatters.log - ); - const stringifyFn = stringify2.bind({ - [stringifySafeSym]: stringifySafe - }); - const stringifiers = redact ? redaction(redact, stringifyFn) : {}; - const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn }; - const end = "}" + (crlf ? "\r\n" : "\n"); - const coreChindings = asChindings.bind(null, { - [chindingsSym]: "", - [serializersSym]: serializers2, - [stringifiersSym]: stringifiers, - [stringifySym]: stringify2, - [stringifySafeSym]: stringifySafe, - [formattersSym]: allFormatters - }); - let chindings = ""; - if (base2 !== null) { - if (name === void 0) { - chindings = coreChindings(base2); - } else { - chindings = coreChindings(Object.assign({}, base2, { name })); - } - } - const time4 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime; - const timeSliceIndex = time4().indexOf(":") + 1; - if (useOnlyCustomLevels && !customLevels) throw Error("customLevels is required if useOnlyCustomLevels is set true"); - if (mixin3 && typeof mixin3 !== "function") throw Error(`Unknown mixin type "${typeof mixin3}" - expected "function"`); - if (msgPrefix && typeof msgPrefix !== "string") throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`); - assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels); - const levels = mappings(customLevels, useOnlyCustomLevels); - assertLevelComparison(levelComparison); - const levelCompFunc = genLevelComparison(levelComparison); - Object.assign(instance, { - levels, - [levelCompSym]: levelCompFunc, - [useOnlyCustomLevelsSym]: useOnlyCustomLevels, - [streamSym]: stream, - [timeSym]: time4, - [timeSliceIndexSym]: timeSliceIndex, - [stringifySym]: stringify2, - [stringifySafeSym]: stringifySafe, - [stringifiersSym]: stringifiers, - [endSym]: end, - [formatOptsSym]: formatOpts, - [messageKeySym]: messageKey, - [errorKeySym]: errorKey, - [nestedKeySym]: nestedKey, - // protect against injection - [nestedKeyStrSym]: nestedKey ? `,${JSON.stringify(nestedKey)}:{` : "", - [serializersSym]: serializers2, - [mixinSym]: mixin3, - [mixinMergeStrategySym]: mixinMergeStrategy, - [chindingsSym]: chindings, - [formattersSym]: allFormatters, - [hooksSym]: hooks, - silent: noop, - onChild, - [msgPrefixSym]: msgPrefix - }); - Object.setPrototypeOf(instance, proto3()); - genLsCache(instance); - instance[setLevelSym](level); - return instance; - } - module14.exports = pino2; - module14.exports.destination = (dest = process.stdout.fd) => { - if (typeof dest === "object") { - dest.dest = normalizeDestFileDescriptor(dest.dest || process.stdout.fd); - return buildSafeSonicBoom(dest); - } else { - return buildSafeSonicBoom({ dest: normalizeDestFileDescriptor(dest), minLength: 0 }); - } - }; - module14.exports.transport = require_transport(); - module14.exports.multistream = require_multistream(); - module14.exports.levels = mappings(); - module14.exports.stdSerializers = serializers; - module14.exports.stdTimeFunctions = Object.assign({}, time3); - module14.exports.symbols = symbols2; - module14.exports.version = version3; - module14.exports.default = pino2; - module14.exports.pino = pino2; - } -}); -function logMethod(args, method) { - const stringIdx = typeof args[0] === "string" ? 0 : 1; - if (args.length > 1) { - for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { - args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; + } = require_symbols(); + var { isMainThread } = __require2("worker_threads"); + var transport = require_transport(); + function noop() { } - } - method.apply(this, args); -} -var import_npm_pino; -var prettyPrint; -var logger; -var logLevel; -var logger_default; -var init_logger = __esm({ - "src/serve/logger.ts"() { - "use strict"; - import_npm_pino = __toESM(require_pino()); - prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; - if (prettyPrint) { - try { - logger = (0, import_npm_pino.default)({ - hooks: { logMethod }, - transport: { - target: "pino-pretty", - options: { - colorize: true + function genLog(level, hook) { + if (!hook) return LOG; + return function hookWrappedLog(...args) { + hook.call(this, args, LOG, level); + }; + function LOG(o2, ...n) { + if (typeof o2 === "object") { + let msg = o2; + if (o2 !== null) { + if (o2.method && o2.headers && o2.socket) { + o2 = mapHttpRequest(o2); + } else if (typeof o2.setHeader === "function") { + o2 = mapHttpResponse(o2); } } - }); - } catch (e2) { - console.warn("pino-pretty transport unavailable, using basic logging", e2); - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); + let formatParams; + if (msg === null && n.length === 0) { + formatParams = [null]; + } else { + msg = n.shift(); + formatParams = n; + } + if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { + msg = this[msgPrefixSym] + msg; + } + this[writeSym](o2, format52(msg, formatParams, this[formatOptsSym]), level); + } else { + let msg = o2 === void 0 ? n.shift() : o2; + if (typeof this[msgPrefixSym] === "string" && msg !== void 0 && msg !== null) { + msg = this[msgPrefixSym] + msg; + } + this[writeSym](null, format52(msg, n, this[formatOptsSym]), level); + } } - } else { - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); } - logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); - if (Object.keys(logger.levels.values).includes(logLevel)) { - logger.level = logLevel; - } else { - logger.warn(`Unknown log level: ${logLevel}`); - } - console.debug = logger.debug.bind(logger); - console.info = logger.info.bind(logger); - console.log = logger.info.bind(logger); - console.warn = logger.warn.bind(logger); - console.error = logger.error.bind(logger); - logger_default = logger; - } -}); -var timer; -var coerceToError; -var defaultOptions2; -var tag; -var PersistentAction; -var persistent_actions_default; -var init_persistent_actions = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/persistent-actions.mjs"() { - init_esm4(); - init_esm(); - init_events(); - timer = Symbol("timer"); - coerceToError = (arg) => { - if (arg && arg instanceof Error) - return arg; - console.warn(tag, "Please use Error objects when throwing or rejecting"); - return new Error((typeof arg === "string" ? arg : JSON.stringify(arg)) ?? "undefined"); - }; - defaultOptions2 = { - maxAttempts: Number.POSITIVE_INFINITY, - retrySeconds: 30 - }; - tag = "[chelonia.persistentActions]"; - PersistentAction = class { - id; - invocation; - options; - status; - [timer]; - constructor(invocation, options2 = {}) { - this.id = crypto.randomUUID(); - this.invocation = invocation; - this.options = { ...defaultOptions2, ...options2 }; - this.status = { - attempting: false, - failedAttemptsSoFar: 0, - lastError: "", - nextRetry: "", - resolved: false - }; + function asString(str) { + let result = ""; + let last = 0; + let found = false; + let point = 255; + const l = str.length; + if (l > 100) { + return JSON.stringify(str); } - async attempt() { - if (this.status.attempting || this.status.resolved) - return; - if (await this.trySBP(this.options.skipCondition)) - this.cancel(); - if (this.status.resolved) - return; - try { - this.status.attempting = true; - const result = await esm_default(...this.invocation); - this.status.attempting = false; - this.handleSuccess(result); - } catch (error2) { - this.status.attempting = false; - await this.handleError(coerceToError(error2)); - } - } - cancel() { - if (this[timer]) - clearTimeout(this[timer]); - this.status.nextRetry = ""; - this.status.resolved = true; - } - async handleError(error2) { - const { id, options: options2, status } = this; - status.failedAttemptsSoFar++; - status.lastError = error2.message; - const anyAttemptLeft = options2.maxAttempts > status.failedAttemptsSoFar; - if (!anyAttemptLeft) - status.resolved = true; - status.nextRetry = anyAttemptLeft && !status.resolved ? new Date(Date.now() + options2.retrySeconds * 1e3).toISOString() : ""; - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_FAILURE, { error: error2, id }); - await this.trySBP(options2.errorInvocation); - if (!anyAttemptLeft) { - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_TOTAL_FAILURE, { error: error2, id }); - await this.trySBP(options2.totalFailureInvocation); - } - if (status.nextRetry) { - this[timer] = setTimeout(() => { - this.attempt().catch((e2) => { - console.error("Error attempting persistent action", id, e2); - }); - }, this.options.retrySeconds * 1e3); + for (var i2 = 0; i2 < l && point >= 32; i2++) { + point = str.charCodeAt(i2); + if (point === 34 || point === 92) { + result += str.slice(last, i2) + "\\"; + last = i2; + found = true; } } - handleSuccess(result) { - const { id, status } = this; - status.lastError = ""; - status.nextRetry = ""; - status.resolved = true; - esm_default("okTurtles.events/emit", PERSISTENT_ACTION_SUCCESS, { id, result }); + if (!found) { + result = str; + } else { + result += str.slice(last); } - async trySBP(invocation) { - try { - return invocation ? await esm_default(...invocation) : void 0; - } catch (error2) { - console.error(tag, coerceToError(error2).message); - } + return point < 32 ? JSON.stringify(str) : '"' + result + '"'; + } + function asJson(obj, msg, num, time3) { + const stringify3 = this[stringifySym]; + const stringifySafe = this[stringifySafeSym]; + const stringifiers = this[stringifiersSym]; + const end = this[endSym]; + const chindings = this[chindingsSym]; + const serializers = this[serializersSym]; + const formatters = this[formattersSym]; + const messageKey = this[messageKeySym]; + const errorKey = this[errorKeySym]; + let data = this[lsCacheSym][num] + time3; + data = data + chindings; + let value; + if (formatters.log) { + obj = formatters.log(obj); } - }; - persistent_actions_default = esm_default("sbp/selectors/register", { - "chelonia.persistentActions/_init"() { - this.actionsByID = /* @__PURE__ */ Object.create(null); - this.checkDatabaseKey = () => { - if (!this.databaseKey) - throw new TypeError(`${tag} No database key configured`); - }; - esm_default("okTurtles.events/on", PERSISTENT_ACTION_SUCCESS, ({ id }) => { - esm_default("chelonia.persistentActions/cancel", id); - }); - esm_default("okTurtles.events/on", PERSISTENT_ACTION_TOTAL_FAILURE, ({ id }) => { - esm_default("chelonia.persistentActions/cancel", id); - }); - }, - // Cancels a specific action by its ID. - // The action won't be retried again, but an async action cannot be aborted if its promise is stil attempting. - async "chelonia.persistentActions/cancel"(id) { - if (id in this.actionsByID) { - this.actionsByID[id].cancel(); - delete this.actionsByID[id]; - return await esm_default("chelonia.persistentActions/save"); - } - }, - // TODO: validation - "chelonia.persistentActions/configure"({ databaseKey, options: options2 = {} }) { - this.databaseKey = databaseKey; - for (const key in options2) { - if (key in defaultOptions2) { - defaultOptions2[key] = options2[key]; - } else { - throw new TypeError(`${tag} Unknown option: ${key}`); + const wildcardStringifier = stringifiers[wildcardFirstSym]; + let propStr = ""; + for (const key in obj) { + value = obj[key]; + if (Object.prototype.hasOwnProperty.call(obj, key) && value !== void 0) { + if (serializers[key]) { + value = serializers[key](value); + } else if (key === errorKey && serializers.err) { + value = serializers.err(value); } - } - }, - "chelonia.persistentActions/enqueue"(...args) { - const ids = []; - for (const arg of args) { - const action = Array.isArray(arg) ? new PersistentAction(arg) : new PersistentAction(arg.invocation, arg); - this.actionsByID[action.id] = action; - ids.push(action.id); - } - esm_default("chelonia.persistentActions/save").catch((e2) => { - console.error("Error saving persistent actions", e2); - }); - for (const id of ids) { - this.actionsByID[id].attempt().catch((e2) => { - console.error("Error attempting persistent action", id, e2); - }); - } - return ids; - }, - // Forces retrying a given persisted action immediately, rather than waiting for the scheduled retry. - // - 'status.failedAttemptsSoFar' will still be increased upon failure. - // - Does nothing if a retry is already running. - // - Does nothing if the action has already been resolved, rejected or cancelled. - "chelonia.persistentActions/forceRetry"(id) { - if (id in this.actionsByID) { - return this.actionsByID[id].attempt(); - } - }, - // Loads and tries every stored persistent action under the configured database key. - async "chelonia.persistentActions/load"() { - this.checkDatabaseKey(); - const storedActions = JSON.parse(await esm_default("chelonia.db/get", this.databaseKey) ?? "[]"); - for (const { id, invocation, options: options2 } of storedActions) { - this.actionsByID[id] = new PersistentAction(invocation, options2); - this.actionsByID[id].id = id; - } - return esm_default("chelonia.persistentActions/retryAll"); - }, - // Retry all existing persisted actions. - // TODO: add some delay between actions so as not to spam the server, - // or have a way to issue them all at once in a single network call. - "chelonia.persistentActions/retryAll"() { - return Promise.allSettled(Object.keys(this.actionsByID).map((id) => esm_default("chelonia.persistentActions/forceRetry", id))); - }, - // Updates the database version of the attempting action list. - "chelonia.persistentActions/save"() { - this.checkDatabaseKey(); - return esm_default("chelonia.db/set", this.databaseKey, JSON.stringify(Object.values(this.actionsByID))); - }, - "chelonia.persistentActions/status"() { - return Object.values(this.actionsByID).map((action) => ({ - id: action.id, - invocation: action.invocation, - ...action.status - })); - }, - // Pauses every currently loaded action, and removes them from memory. - // Note: persistent storage is not affected, so that these actions can be later loaded again and retried. - "chelonia.persistentActions/unload"() { - for (const id in this.actionsByID) { - if (this.actionsByID[id][timer]) { - clearTimeout(this.actionsByID[id][timer]); + const stringifier = stringifiers[key] || wildcardStringifier; + switch (typeof value) { + case "undefined": + case "function": + continue; + case "number": + if (Number.isFinite(value) === false) { + value = null; + } + // this case explicitly falls through to the next one + case "boolean": + if (stringifier) value = stringifier(value); + break; + case "string": + value = (stringifier || asString)(value); + break; + default: + value = (stringifier || stringify3)(value, stringifySafe); } - delete this.actionsByID[id]; + if (value === void 0) continue; + const strKey = asString(key); + propStr += "," + strKey + ":" + value; } } - }); - } -}); -var SERVER; -var init_presets = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/presets.mjs"() { - SERVER = { - // We don't check the subscriptionSet in the server because we accpt new - // contract registrations, and are also not subcribed to contracts the same - // way clients are - acceptAllMessages: true, - // The server also doesn't process actions - skipActionProcessing: true, - // The previous setting implies this one, which we set to be on the safe side - skipSideEffects: true, - // Changes the behaviour of unwrapMaybeEncryptedData so that it never decrypts. - // Mostly useful for the server, to avoid filling up the logs and for faster - // execution. - skipDecryptionAttempts: true, - // If an error occurs during processing, the message is rejected rather than - // ignored - strictProcessing: true, - // The server expects events to be received in order (no past or future events) - strictOrdering: true - }; - } -}); -var cors; -var init_cors = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/cors/index.js"() { - cors = (options2) => { - const defaults = { - origin: "*", - allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"], - allowHeaders: [], - exposeHeaders: [] - }; - const opts = { - ...defaults, - ...options2 - }; - const findAllowOrigin = ((optsOrigin) => { - if (typeof optsOrigin === "string") { - if (optsOrigin === "*") { - if (opts.credentials) { - return (origin) => origin || null; + let msgStr = ""; + if (msg !== void 0) { + value = serializers[messageKey] ? serializers[messageKey](msg) : msg; + const stringifier = stringifiers[messageKey] || wildcardStringifier; + switch (typeof value) { + case "function": + break; + case "number": + if (Number.isFinite(value) === false) { + value = null; } - return () => optsOrigin; - } else { - return (origin) => optsOrigin === origin ? origin : null; - } - } else if (typeof optsOrigin === "function") { - return optsOrigin; - } else { - return (origin) => optsOrigin.includes(origin) ? origin : null; - } - })(opts.origin); - const findAllowMethods = ((optsAllowMethods) => { - if (typeof optsAllowMethods === "function") { - return optsAllowMethods; - } else if (Array.isArray(optsAllowMethods)) { - return () => optsAllowMethods; - } else { - return () => []; - } - })(opts.allowMethods); - return async function cors2(c, next) { - function set(key, value) { - c.res.headers.set(key, value); - } - const allowOrigin = await findAllowOrigin(c.req.header("origin") || "", c); - if (allowOrigin) { - set("Access-Control-Allow-Origin", allowOrigin); + // this case explicitly falls through to the next one + case "boolean": + if (stringifier) value = stringifier(value); + msgStr = ',"' + messageKey + '":' + value; + break; + case "string": + value = (stringifier || asString)(value); + msgStr = ',"' + messageKey + '":' + value; + break; + default: + value = (stringifier || stringify3)(value, stringifySafe); + msgStr = ',"' + messageKey + '":' + value; } - if (opts.credentials) { - set("Access-Control-Allow-Credentials", "true"); + } + if (this[nestedKeySym] && propStr) { + return data + this[nestedKeyStrSym] + propStr.slice(1) + "}" + msgStr + end; + } else { + return data + propStr + msgStr + end; + } + } + function asChindings(instance, bindings) { + let value; + let data = instance[chindingsSym]; + const stringify3 = instance[stringifySym]; + const stringifySafe = instance[stringifySafeSym]; + const stringifiers = instance[stringifiersSym]; + const wildcardStringifier = stringifiers[wildcardFirstSym]; + const serializers = instance[serializersSym]; + const formatter = instance[formattersSym].bindings; + bindings = formatter(bindings); + for (const key in bindings) { + value = bindings[key]; + const valid = key !== "level" && key !== "serializers" && key !== "formatters" && key !== "customLevels" && bindings.hasOwnProperty(key) && value !== void 0; + if (valid === true) { + value = serializers[key] ? serializers[key](value) : value; + value = (stringifiers[key] || wildcardStringifier || stringify3)(value, stringifySafe); + if (value === void 0) continue; + data += ',"' + key + '":' + value; } - if (opts.exposeHeaders?.length) { - set("Access-Control-Expose-Headers", opts.exposeHeaders.join(",")); + } + return data; + } + function hasBeenTampered(stream) { + return stream.write !== stream.constructor.prototype.write; + } + var hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE; + function buildSafeSonicBoom(opts) { + const stream = new SonicBoom(opts); + stream.on("error", filterBrokenPipe); + if (!hasNodeCodeCoverage && !opts.sync && isMainThread) { + onExit.register(stream, autoEnd); + stream.on("close", function() { + onExit.unregister(stream); + }); + } + return stream; + function filterBrokenPipe(err) { + if (err.code === "EPIPE") { + stream.write = noop; + stream.end = noop; + stream.flushSync = noop; + stream.destroy = noop; + return; } - if (c.req.method === "OPTIONS") { - if (opts.origin !== "*" || opts.credentials) { - set("Vary", "Origin"); - } - if (opts.maxAge != null) { - set("Access-Control-Max-Age", opts.maxAge.toString()); + stream.removeListener("error", filterBrokenPipe); + stream.emit("error", err); + } + } + function autoEnd(stream, eventName) { + if (stream.destroyed) { + return; + } + if (eventName === "beforeExit") { + stream.flush(); + stream.on("drain", function() { + stream.end(); + }); + } else { + stream.flushSync(); + } + } + function createArgsNormalizer(defaultOptions4) { + return function normalizeArgs(instance, caller, opts = {}, stream) { + if (typeof opts === "string") { + stream = buildSafeSonicBoom({ dest: opts }); + opts = {}; + } else if (typeof stream === "string") { + if (opts && opts.transport) { + throw Error("only one of option.transport or stream can be specified"); } - const allowMethods = await findAllowMethods(c.req.header("origin") || "", c); - if (allowMethods.length) { - set("Access-Control-Allow-Methods", allowMethods.join(",")); + stream = buildSafeSonicBoom({ dest: stream }); + } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) { + stream = opts; + opts = {}; + } else if (opts.transport) { + if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) { + throw Error("option.transport do not allow stream, please pass to option directly. e.g. pino(transport)"); } - let headers = opts.allowHeaders; - if (!headers?.length) { - const requestHeaders = c.req.header("Access-Control-Request-Headers"); - if (requestHeaders) { - headers = requestHeaders.split(/\s*,\s*/); - } + if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === "function") { + throw Error("option.transport.targets do not allow custom level formatters"); } - if (headers?.length) { - set("Access-Control-Allow-Headers", headers.join(",")); - c.res.headers.append("Vary", "Access-Control-Request-Headers"); + let customLevels; + if (opts.customLevels) { + customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels); } - c.res.headers.delete("Content-Length"); - c.res.headers.delete("Content-Type"); - return new Response(null, { - headers: c.res.headers, - status: 204, - statusText: "No Content" - }); + stream = transport({ caller, ...opts.transport, levels: customLevels }); } - await next(); - if (opts.origin !== "*" || opts.credentials) { - c.header("Vary", "Origin", { append: true }); + opts = Object.assign({}, defaultOptions4, opts); + opts.serializers = Object.assign({}, defaultOptions4.serializers, opts.serializers); + opts.formatters = Object.assign({}, defaultOptions4.formatters, opts.formatters); + if (opts.prettyPrint) { + throw new Error("prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)"); + } + const { enabled: enabled2, onChild } = opts; + if (enabled2 === false) opts.level = "silent"; + if (!onChild) opts.onChild = noop; + if (!stream) { + if (!hasBeenTampered(process.stdout)) { + stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 }); + } else { + stream = process.stdout; + } } + return { opts, stream }; }; - }; - } -}); -async function readWithoutBlocking(readPromise) { - return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]); -} -function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) { - const cancel = (error2) => { - reader.cancel(error2).catch(() => { - }); - }; - writable.on("close", cancel); - writable.on("error", cancel); - (currentReadPromise ?? reader.read()).then(flow, handleStreamError); - return reader.closed.finally(() => { - writable.off("close", cancel); - writable.off("error", cancel); - }); - function handleStreamError(error2) { - if (error2) { - writable.destroy(error2); - } - } - function onDrain() { - reader.read().then(flow, handleStreamError); - } - function flow({ done, value }) { - try { - if (done) { - writable.end(); - } else if (!writable.write(value)) { - writable.once("drain", onDrain); - } else { - return reader.read().then(flow, handleStreamError); - } - } catch (e2) { - handleStreamError(e2); } - } -} -function writeFromReadableStream(stream, writable) { - if (stream.locked) { - throw new TypeError("ReadableStream is locked."); - } else if (writable.destroyed) { - return; - } - return writeFromReadableStreamDefaultReader(stream.getReader(), writable); -} -var RequestError; -var toRequestError; -var GlobalRequest; -var Request2; -var newHeadersFromIncoming; -var wrapBodyStream; -var newRequestFromIncoming; -var getRequestCache; -var requestCache; -var incomingKey; -var urlKey; -var headersKey; -var abortControllerKey; -var getAbortController; -var requestPrototype; -var newRequest; -var responseCache; -var getResponseCache; -var cacheKey; -var GlobalResponse; -var Response2; -var buildOutgoingHttpHeaders; -var X_ALREADY_SENT; -var outgoingEnded; -var incomingDraining; -var DRAIN_TIMEOUT_MS; -var MAX_DRAIN_BYTES; -var drainIncoming; -var handleRequestError; -var handleFetchError; -var handleResponseError; -var flushHeaders; -var responseViaCache; -var isPromise; -var responseViaResponseObject; -var getRequestListener; -var createAdaptorServer; -var init_dist2 = __esm({ - "node_modules/.deno/@hono+node-server@1.19.14/node_modules/@hono/node-server/dist/index.mjs"() { - RequestError = class extends Error { - constructor(message, options2) { - super(message, options2); - this.name = "RequestError"; - } - }; - toRequestError = (e2) => { - if (e2 instanceof RequestError) { - return e2; - } - return new RequestError(e2.message, { cause: e2 }); - }; - GlobalRequest = global.Request; - Request2 = class extends GlobalRequest { - constructor(input, options2) { - if (typeof input === "object" && getRequestCache in input) { - input = input[getRequestCache](); - } - if (typeof options2?.body?.getReader !== "undefined") { - ; - options2.duplex ??= "half"; - } - super(input, options2); - } - }; - newHeadersFromIncoming = (incoming) => { - const headerRecord = []; - const rawHeaders = incoming.rawHeaders; - for (let i2 = 0; i2 < rawHeaders.length; i2 += 2) { - const { [i2]: key, [i2 + 1]: value } = rawHeaders; - if (key.charCodeAt(0) !== /*:*/ - 58) { - headerRecord.push([key, value]); + function stringify2(obj, stringifySafeFn) { + try { + return JSON.stringify(obj); + } catch (_) { + try { + const stringify3 = stringifySafeFn || this[stringifySafeSym]; + return stringify3(obj); + } catch (_2) { + return '"[unable to serialize, circular reference is too complex to analyze]"'; } } - return new Headers(headerRecord); - }; - wrapBodyStream = Symbol("wrapBodyStream"); - newRequestFromIncoming = (method, url2, headers, incoming, abortController) => { - const init2 = { - method, - headers, - signal: abortController.signal + } + function buildFormatters(level, bindings, log2) { + return { + level, + bindings, + log: log2 }; - if (method === "TRACE") { - init2.method = "GET"; - const req = new Request2(url2, init2); - Object.defineProperty(req, "method", { - get() { - return "TRACE"; - } - }); - return req; + } + function normalizeDestFileDescriptor(destination) { + const fd = Number(destination); + if (typeof destination === "string" && Number.isFinite(fd)) { + return fd; } - if (!(method === "GET" || method === "HEAD")) { - if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) { - init2.body = new ReadableStream({ - start(controller) { - controller.enqueue(incoming.rawBody); - controller.close(); - } - }); - } else if (incoming[wrapBodyStream]) { - let reader; - init2.body = new ReadableStream({ - async pull(controller) { - try { - reader ||= Readable2.toWeb(incoming).getReader(); - const { done, value } = await reader.read(); - if (done) { - controller.close(); - } else { - controller.enqueue(value); - } - } catch (error2) { - controller.error(error2); - } - } - }); - } else { - init2.body = Readable2.toWeb(incoming); - } + if (destination === void 0) { + return 1; } - return new Request2(url2, init2); + return destination; + } + module14.exports = { + noop, + buildSafeSonicBoom, + asChindings, + asJson, + genLog, + createArgsNormalizer, + stringify: stringify2, + buildFormatters, + normalizeDestFileDescriptor }; - getRequestCache = Symbol("getRequestCache"); - requestCache = Symbol("requestCache"); - incomingKey = Symbol("incomingKey"); - urlKey = Symbol("urlKey"); - headersKey = Symbol("headersKey"); - abortControllerKey = Symbol("abortControllerKey"); - getAbortController = Symbol("getAbortController"); - requestPrototype = { - get method() { - return this[incomingKey].method || "GET"; - }, - get url() { - return this[urlKey]; - }, - get headers() { - return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]); - }, - [getAbortController]() { - this[getRequestCache](); - return this[abortControllerKey]; - }, - [getRequestCache]() { - this[abortControllerKey] ||= new AbortController(); - return this[requestCache] ||= newRequestFromIncoming( - this.method, - this[urlKey], - this.headers, - this[incomingKey], - this[abortControllerKey] - ); - } + } +}); +var require_constants = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/constants.js"(exports2, module14) { + var DEFAULT_LEVELS = { + trace: 10, + debug: 20, + info: 30, + warn: 40, + error: 50, + fatal: 60 }; - [ - "body", - "bodyUsed", - "cache", - "credentials", - "destination", - "integrity", - "mode", - "redirect", - "referrer", - "referrerPolicy", - "signal", - "keepalive" - ].forEach((k) => { - Object.defineProperty(requestPrototype, k, { - get() { - return this[getRequestCache]()[k]; - } - }); - }); - ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { - Object.defineProperty(requestPrototype, k, { - value: function() { - return this[getRequestCache]()[k](); - } - }); - }); - Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { - value: function(depth, options2, inspectFn) { - const props = { - method: this.method, - url: this.url, - headers: this.headers, - nativeRequest: this[requestCache] - }; - return `Request (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; - } - }); - Object.setPrototypeOf(requestPrototype, Request2.prototype); - newRequest = (incoming, defaultHostname) => { - const req = Object.create(requestPrototype); - req[incomingKey] = incoming; - const incomingUrl = incoming.url || ""; - if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL. - (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) { - if (incoming instanceof Http2ServerRequest) { - throw new RequestError("Absolute URL for :path is not allowed in HTTP/2"); - } - try { - const url22 = new URL(incomingUrl); - req[urlKey] = url22.href; - } catch (e2) { - throw new RequestError("Invalid absolute URL", { cause: e2 }); - } - return req; - } - const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname; - if (!host) { - throw new RequestError("Missing host header"); - } - let scheme; - if (incoming instanceof Http2ServerRequest) { - scheme = incoming.scheme; - if (!(scheme === "http" || scheme === "https")) { - throw new RequestError("Unsupported scheme"); - } - } else { - scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http"; - } - const url2 = new URL(`${scheme}://${host}${incomingUrl}`); - if (url2.hostname.length !== host.length && url2.hostname !== host.replace(/:\d+$/, "")) { - throw new RequestError("Invalid host header"); - } - req[urlKey] = url2.href; - return req; - }; - responseCache = Symbol("responseCache"); - getResponseCache = Symbol("getResponseCache"); - cacheKey = Symbol("cache"); - GlobalResponse = global.Response; - Response2 = class _Response { - #body; - #init; - [getResponseCache]() { - delete this[cacheKey]; - return this[responseCache] ||= new GlobalResponse(this.#body, this.#init); - } - constructor(body, init2) { - let headers; - this.#body = body; - if (init2 instanceof _Response) { - const cachedGlobalResponse = init2[responseCache]; - if (cachedGlobalResponse) { - this.#init = cachedGlobalResponse; - this[getResponseCache](); - return; - } else { - this.#init = init2.#init; - headers = new Headers(init2.#init.headers); - } - } else { - this.#init = init2; - } - if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) { - ; - this[cacheKey] = [init2?.status || 200, body, headers || init2?.headers]; - } - } - get headers() { - const cache2 = this[cacheKey]; - if (cache2) { - if (!(cache2[2] instanceof Headers)) { - cache2[2] = new Headers( - cache2[2] || { "content-type": "text/plain; charset=UTF-8" } - ); - } - return cache2[2]; - } - return this[getResponseCache]().headers; - } - get status() { - return this[cacheKey]?.[0] ?? this[getResponseCache]().status; - } - get ok() { - const status = this.status; - return status >= 200 && status < 300; - } + var SORTING_ORDER = { + ASC: "ASC", + DESC: "DESC" }; - ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => { - Object.defineProperty(Response2.prototype, k, { - get() { - return this[getResponseCache]()[k]; - } - }); - }); - ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { - Object.defineProperty(Response2.prototype, k, { - value: function() { - return this[getResponseCache]()[k](); - } - }); - }); - Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), { - value: function(depth, options2, inspectFn) { - const props = { - status: this.status, - headers: this.headers, - ok: this.ok, - nativeResponse: this[responseCache] + module14.exports = { + DEFAULT_LEVELS, + SORTING_ORDER + }; + } +}); +var require_levels = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/levels.js"(exports2, module14) { + "use strict"; + var { + lsCacheSym, + levelValSym, + useOnlyCustomLevelsSym, + streamSym, + formattersSym, + hooksSym, + levelCompSym + } = require_symbols(); + var { noop, genLog } = require_tools(); + var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); + var levelMethods = { + fatal: (hook) => { + const logFatal = genLog(DEFAULT_LEVELS.fatal, hook); + return function(...args) { + const stream = this[streamSym]; + logFatal.call(this, ...args); + if (typeof stream.flushSync === "function") { + try { + stream.flushSync(); + } catch (e2) { + } + } }; - return `Response (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; + }, + error: (hook) => genLog(DEFAULT_LEVELS.error, hook), + warn: (hook) => genLog(DEFAULT_LEVELS.warn, hook), + info: (hook) => genLog(DEFAULT_LEVELS.info, hook), + debug: (hook) => genLog(DEFAULT_LEVELS.debug, hook), + trace: (hook) => genLog(DEFAULT_LEVELS.trace, hook) + }; + var nums = Object.keys(DEFAULT_LEVELS).reduce((o2, k) => { + o2[DEFAULT_LEVELS[k]] = k; + return o2; + }, {}); + var initialLsCache = Object.keys(nums).reduce((o2, k) => { + o2[k] = '{"level":' + Number(k); + return o2; + }, {}); + function genLsCache(instance) { + const formatter = instance[formattersSym].level; + const { labels } = instance.levels; + const cache2 = {}; + for (const label in labels) { + const level = formatter(labels[label], Number(label)); + cache2[label] = JSON.stringify(level).slice(0, -1); } - }); - Object.setPrototypeOf(Response2, GlobalResponse); - Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype); - buildOutgoingHttpHeaders = (headers) => { - const res = {}; - if (!(headers instanceof Headers)) { - headers = new Headers(headers ?? void 0); - } - const cookies = []; - for (const [k, v2] of headers) { - if (k === "set-cookie") { - cookies.push(v2); - } else { - res[k] = v2; - } + instance[lsCacheSym] = cache2; + return instance; + } + function isStandardLevel(level, useOnlyCustomLevels) { + if (useOnlyCustomLevels) { + return false; } - if (cookies.length > 0) { - res["set-cookie"] = cookies; + switch (level) { + case "fatal": + case "error": + case "warn": + case "info": + case "debug": + case "trace": + return true; + default: + return false; } - res["content-type"] ??= "text/plain; charset=UTF-8"; - return res; - }; - X_ALREADY_SENT = "x-hono-already-sent"; - if (typeof global.crypto === "undefined") { - global.crypto = crypto2; - } - outgoingEnded = Symbol("outgoingEnded"); - incomingDraining = Symbol("incomingDraining"); - DRAIN_TIMEOUT_MS = 500; - MAX_DRAIN_BYTES = 64 * 1024 * 1024; - drainIncoming = (incoming) => { - const incomingWithDrainState = incoming; - if (incoming.destroyed || incomingWithDrainState[incomingDraining]) { - return; + } + function setLevel(level) { + const { labels, values } = this.levels; + if (typeof level === "number") { + if (labels[level] === void 0) throw Error("unknown level value" + level); + level = labels[level]; } - incomingWithDrainState[incomingDraining] = true; - if (incoming instanceof Http2ServerRequest2) { - try { - ; - incoming.stream?.close?.(h2constants.NGHTTP2_NO_ERROR); - } catch { + if (values[level] === void 0) throw Error("unknown level " + level); + const preLevelVal = this[levelValSym]; + const levelVal = this[levelValSym] = values[level]; + const useOnlyCustomLevelsVal = this[useOnlyCustomLevelsSym]; + const levelComparison = this[levelCompSym]; + const hook = this[hooksSym].logMethod; + for (const key in values) { + if (levelComparison(values[key], levelVal) === false) { + this[key] = noop; + continue; } - return; + this[key] = isStandardLevel(key, useOnlyCustomLevelsVal) ? levelMethods[key](hook) : genLog(values[key], hook); } - let bytesRead = 0; - const cleanup = () => { - clearTimeout(timer2); - incoming.off("data", onData); - incoming.off("end", cleanup); - incoming.off("error", cleanup); - }; - const forceClose = () => { - cleanup(); - const socket = incoming.socket; - if (socket && !socket.destroyed) { - socket.destroySoon(); - } - }; - const timer2 = setTimeout(forceClose, DRAIN_TIMEOUT_MS); - timer2.unref?.(); - const onData = (chunk) => { - bytesRead += chunk.length; - if (bytesRead > MAX_DRAIN_BYTES) { - forceClose(); - } - }; - incoming.on("data", onData); - incoming.on("end", cleanup); - incoming.on("error", cleanup); - incoming.resume(); - }; - handleRequestError = () => new Response(null, { - status: 400 - }); - handleFetchError = (e2) => new Response(null, { - status: e2 instanceof Error && (e2.name === "TimeoutError" || e2.constructor.name === "TimeoutError") ? 504 : 500 - }); - handleResponseError = (e2, outgoing) => { - const err = e2 instanceof Error ? e2 : new Error("unknown error", { cause: e2 }); - if (err.code === "ERR_STREAM_PREMATURE_CLOSE") { - console.info("The user aborted a request."); - } else { - console.error(e2); - if (!outgoing.headersSent) { - outgoing.writeHead(500, { "Content-Type": "text/plain" }); - } - outgoing.end(`Error: ${err.message}`); - outgoing.destroy(err); - } - }; - flushHeaders = (outgoing) => { - if ("flushHeaders" in outgoing && outgoing.writable) { - outgoing.flushHeaders(); - } - }; - responseViaCache = async (res, outgoing) => { - let [status, body, header] = res[cacheKey]; - let hasContentLength = false; - if (!header) { - header = { "content-type": "text/plain; charset=UTF-8" }; - } else if (header instanceof Headers) { - hasContentLength = header.has("content-length"); - header = buildOutgoingHttpHeaders(header); - } else if (Array.isArray(header)) { - const headerObj = new Headers(header); - hasContentLength = headerObj.has("content-length"); - header = buildOutgoingHttpHeaders(headerObj); - } else { - for (const key in header) { - if (key.length === 14 && key.toLowerCase() === "content-length") { - hasContentLength = true; - break; - } - } + this.emit( + "level-change", + level, + levelVal, + labels[preLevelVal], + preLevelVal, + this + ); + } + function getLevel(level) { + const { levels, levelVal } = this; + return levels && levels.labels ? levels.labels[levelVal] : ""; + } + function isLevelEnabled(logLevel2) { + const { values } = this.levels; + const logLevelVal = values[logLevel2]; + return logLevelVal !== void 0 && this[levelCompSym](logLevelVal, this[levelValSym]); + } + function compareLevel(direction, current, expected) { + if (direction === SORTING_ORDER.DESC) { + return current <= expected; } - if (!hasContentLength) { - if (typeof body === "string") { - header["Content-Length"] = Buffer.byteLength(body); - } else if (body instanceof Uint8Array) { - header["Content-Length"] = body.byteLength; - } else if (body instanceof Blob) { - header["Content-Length"] = body.size; - } + return current >= expected; + } + function genLevelComparison(levelComparison) { + if (typeof levelComparison === "string") { + return compareLevel.bind(null, levelComparison); } - outgoing.writeHead(status, header); - if (typeof body === "string" || body instanceof Uint8Array) { - outgoing.end(body); - } else if (body instanceof Blob) { - outgoing.end(new Uint8Array(await body.arrayBuffer())); - } else { - flushHeaders(outgoing); - await writeFromReadableStream(body, outgoing)?.catch( - (e2) => handleResponseError(e2, outgoing) + return levelComparison; + } + function mappings(customLevels = null, useOnlyCustomLevels = false) { + const customNums = customLevels ? Object.keys(customLevels).reduce((o2, k) => { + o2[customLevels[k]] = k; + return o2; + }, {}) : null; + const labels = Object.assign( + Object.create(Object.prototype, { Infinity: { value: "silent" } }), + useOnlyCustomLevels ? null : nums, + customNums + ); + const values = Object.assign( + Object.create(Object.prototype, { silent: { value: Infinity } }), + useOnlyCustomLevels ? null : DEFAULT_LEVELS, + customLevels + ); + return { labels, values }; + } + function assertDefaultLevelFound(defaultLevel, customLevels, useOnlyCustomLevels) { + if (typeof defaultLevel === "number") { + const values = [].concat( + Object.keys(customLevels || {}).map((key) => customLevels[key]), + useOnlyCustomLevels ? [] : Object.keys(nums).map((level) => +level), + Infinity ); - } - ; - outgoing[outgoingEnded]?.(); - }; - isPromise = (res) => typeof res.then === "function"; - responseViaResponseObject = async (res, outgoing, options2 = {}) => { - if (isPromise(res)) { - if (options2.errorHandler) { - try { - res = await res; - } catch (err) { - const errRes = await options2.errorHandler(err); - if (!errRes) { - return; - } - res = errRes; - } - } else { - res = await res.catch(handleFetchError); + if (!values.includes(defaultLevel)) { + throw Error(`default level:${defaultLevel} must be included in custom levels`); } + return; } - if (cacheKey in res) { - return responseViaCache(res, outgoing); + const labels = Object.assign( + Object.create(Object.prototype, { silent: { value: Infinity } }), + useOnlyCustomLevels ? null : DEFAULT_LEVELS, + customLevels + ); + if (!(defaultLevel in labels)) { + throw Error(`default level:${defaultLevel} must be included in custom levels`); } - const resHeaderRecord = buildOutgoingHttpHeaders(res.headers); - if (res.body) { - const reader = res.body.getReader(); - const values = []; - let done = false; - let currentReadPromise = void 0; - if (resHeaderRecord["transfer-encoding"] !== "chunked") { - let maxReadCount = 2; - for (let i2 = 0; i2 < maxReadCount; i2++) { - currentReadPromise ||= reader.read(); - const chunk = await readWithoutBlocking(currentReadPromise).catch((e2) => { - console.error(e2); - done = true; - }); - if (!chunk) { - if (i2 === 1) { - await new Promise((resolve82) => setTimeout(resolve82)); - maxReadCount = 3; - continue; - } - break; - } - currentReadPromise = void 0; - if (chunk.value) { - values.push(chunk.value); - } - if (chunk.done) { - done = true; - break; - } - } - if (done && !("content-length" in resHeaderRecord)) { - resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0); - } + } + function assertNoLevelCollisions(levels, customLevels) { + const { labels, values } = levels; + for (const k in customLevels) { + if (k in values) { + throw Error("levels cannot be overridden"); } - outgoing.writeHead(res.status, resHeaderRecord); - values.forEach((value) => { - ; - outgoing.write(value); - }); - if (done) { - outgoing.end(); - } else { - if (values.length === 0) { - flushHeaders(outgoing); - } - await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise); + if (customLevels[k] in labels) { + throw Error("pre-existing level values cannot be used for new levels"); } - } else if (resHeaderRecord[X_ALREADY_SENT]) { - } else { - outgoing.writeHead(res.status, resHeaderRecord); - outgoing.end(); } - ; - outgoing[outgoingEnded]?.(); - }; - getRequestListener = (fetchCallback, options2 = {}) => { - const autoCleanupIncoming = options2.autoCleanupIncoming ?? true; - if (options2.overrideGlobalObjects !== false && global.Request !== Request2) { - Object.defineProperty(global, "Request", { - value: Request2 - }); - Object.defineProperty(global, "Response", { - value: Response2 - }); + } + function assertLevelComparison(levelComparison) { + if (typeof levelComparison === "function") { + return; } - return async (incoming, outgoing) => { - let res, req; - try { - req = newRequest(incoming, options2.hostname); - let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD"; - if (!incomingEnded) { - ; - incoming[wrapBodyStream] = true; - incoming.on("end", () => { - incomingEnded = true; - }); - if (incoming instanceof Http2ServerRequest2) { - ; - outgoing[outgoingEnded] = () => { - if (!incomingEnded) { - setTimeout(() => { - if (!incomingEnded) { - setTimeout(() => { - drainIncoming(incoming); - }); - } - }); - } - }; - } - outgoing.on("finish", () => { - if (!incomingEnded) { - drainIncoming(incoming); - } - }); - } - outgoing.on("close", () => { - const abortController = req[abortControllerKey]; - if (abortController) { - if (incoming.errored) { - req[abortControllerKey].abort(incoming.errored.toString()); - } else if (!outgoing.writableFinished) { - req[abortControllerKey].abort("Client connection prematurely closed."); - } - } - if (!incomingEnded) { - setTimeout(() => { - if (!incomingEnded) { - setTimeout(() => { - drainIncoming(incoming); - }); - } - }); - } - }); - res = fetchCallback(req, { incoming, outgoing }); - if (cacheKey in res) { - return responseViaCache(res, outgoing); - } - } catch (e2) { - if (!res) { - if (options2.errorHandler) { - res = await options2.errorHandler(req ? e2 : toRequestError(e2)); - if (!res) { - return; - } - } else if (!req) { - res = handleRequestError(); - } else { - res = handleFetchError(e2); - } - } else { - return handleResponseError(e2, outgoing); - } - } - try { - return await responseViaResponseObject(res, outgoing, options2); - } catch (e2) { - return handleResponseError(e2, outgoing); - } - }; - }; - createAdaptorServer = (options2) => { - const fetchCallback = options2.fetch; - const requestListener = getRequestListener(fetchCallback, { - hostname: options2.hostname, - overrideGlobalObjects: options2.overrideGlobalObjects, - autoCleanupIncoming: options2.autoCleanupIncoming - }); - const createServer2 = options2.createServer || createServerHTTP; - const server = createServer2(options2.serverOptions || {}, requestListener); - return server; - }; - } -}); -var createWorker; -var createWorker_default; -var init_createWorker = __esm({ - "src/serve/createWorker.ts"() { - "use strict"; - init_esm8(); - init_esm(); - Object.defineProperties(Buffer13, { - [serdesDeserializeSymbol]: { - value(buf2) { - return Buffer13.from(buf2); - } - }, - [serdesSerializeSymbol]: { - value(buf2) { - return new Uint8Array(buf2.buffer, buf2.byteOffset, buf2.byteLength); - } - }, - [serdesTagSymbol]: { - value: "node:buffer" + if (typeof levelComparison === "string" && Object.values(SORTING_ORDER).includes(levelComparison)) { + return; } - }); - deserializer.register(Buffer13); - createWorker = (path8) => { - let worker; - let ready; - const launchWorker = () => { - worker = new Worker(new URL(path8, import.meta.url), { type: "module" }); - return new Promise((resolve82, reject) => { - const msgHandler = (event) => { - const msg = event.data; - if (msg === "ready") { - worker.removeEventListener("error", reject, { capture: false }); - worker.addEventListener("error", (ev) => { - const e2 = ev.error; - console.error(e2, `Running worker ${basename52(path8)} terminated. Attempting relaunch...`); - worker.removeEventListener("message", msgHandler, false); - ready = launchWorker().catch((e3) => { - console.error(e3, `Error on worker ${basename52(path8)} relaunch`); - process7.exit(1); - }); - }, false); - resolve82(); - } else if (msg && typeof msg === "object" && msg.type === "sbp" && Array.isArray(msg.data) && String(msg.data[0]).startsWith("chelonia.db/")) { - const port = msg.port; - Promise.try(() => esm_default(...deserializer(msg.data))).then((r) => { - const { data, transferables } = serializer(r); - port.postMessage([true, data], transferables); - }).catch((e2) => { - const { data, transferables } = serializer(e2); - port.postMessage([false, data], transferables); - }).finally(() => { - port.close(); - }); - } - }; - worker.addEventListener("message", msgHandler, false); - worker.addEventListener("error", reject, { capture: false, once: true }); - }); - }; - ready = launchWorker(); - const rpcSbp = (...args) => { - return ready.then(() => new Promise((resolve82, reject) => { - const mc = new MessageChannel(); - const cleanup = /* @__PURE__ */ ((worker2) => () => { - worker2.removeEventListener("error", reject, { capture: true }); - mc.port2.close(); - mc.port2.onmessage = null; - mc.port2.onmessageerror = null; - })(worker); - mc.port2.onmessage = (event) => { - cleanup(); - const [success, result] = event.data; - if (success) return resolve82(result); - reject(result); - }; - mc.port2.onmessageerror = () => { - cleanup(); - reject(new Error("Message error")); - }; - worker.postMessage([mc.port1, ...args], [mc.port1]); - worker.addEventListener("error", reject, { capture: false, once: true }); - })); - }; - return { - ready, - rpcSbp, - terminate: () => worker.terminate() - }; + throw new Error('Levels comparison should be one of "ASC", "DESC" or "function" type'); + } + module14.exports = { + initialLsCache, + genLsCache, + levelMethods, + getLevel, + setLevel, + isLevelEnabled, + mappings, + assertNoLevelCollisions, + assertDefaultLevelFound, + genLevelComparison, + assertLevelComparison }; - createWorker_default = createWorker; - } -}); -var CREDITS_WORKER_TASK_TIME_INTERVAL; -var OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL; -var init_constants4 = __esm({ - "src/serve/constants.ts"() { - "use strict"; - CREDITS_WORKER_TASK_TIME_INTERVAL = 3e5; - OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL = 3e4; } }); -var rfc8291Ikm_default; -var init_rfc8291Ikm = __esm({ - "src/serve/rfc8291Ikm.ts"() { +var require_meta = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/meta.js"(exports2, module14) { "use strict"; - rfc8291Ikm_default = async (uaPublic, salt) => { - const [[asPrivateKey, asPublic], uaPublicKey] = await Promise.all([ - crypto.subtle.generateKey( - { - name: "ECDH", - namedCurve: "P-256" - }, - false, - ["deriveKey"] - ).then(async (asKeyPair) => { - const asPublic2 = await crypto.subtle.exportKey( - "raw", - asKeyPair.publicKey - ); - return [asKeyPair.privateKey, asPublic2]; - }), - crypto.subtle.importKey( - "raw", - uaPublic, - { name: "ECDH", namedCurve: "P-256" }, - false, - [] - ) - ]); - const ecdhSecret = await crypto.subtle.deriveKey( - { - name: "ECDH", - public: uaPublicKey - }, - asPrivateKey, - { - name: "HKDF", - hash: "SHA-256" - }, - false, - ["deriveBits"] - ); - const infoString = new Uint8Array([ - 87, - 101, - 98, - 80, - 117, - 115, - 104, - 58, - 32, - 105, - 110, - 102, - 111, - 0 - ]); - const info = new Uint8Array(infoString.byteLength + uaPublic.byteLength + asPublic.byteLength); - info.set(infoString, 0); - info.set(uaPublic, infoString.byteLength); - info.set( - new Uint8Array(asPublic), - infoString.byteLength + uaPublic.byteLength - ); - const IKM = await crypto.subtle.deriveBits( - { - name: "HKDF", - hash: "SHA-256", - salt, - info - }, - ecdhSecret, - 32 << 3 - ); - return [asPublic, IKM]; - }; + module14.exports = { version: "8.19.0" }; } }); -var addSubscriptionToIndex; -var deleteSubscriptionFromIndex; -var saveSubscription; -var addChannelToSubscription; -var deleteChannelFromSubscription; -var removeSubscription; -var subscriptionInfoWrapper; -var encryptPayload; -var postEvent; -var pushServerActionhandlers; -var init_push = __esm({ - "src/serve/push.ts"() { +var require_proto = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports2, module14) { "use strict"; - init_encodings(); - init_encrypt(); - init_functions(); - init_pubsub(); - init_esm(); - init_database(); - init_instance_keys(); - init_rfc8291Ikm(); - init_vapid(); - addSubscriptionToIndex = appendToIndexFactory("_private_webpush_index"); - deleteSubscriptionFromIndex = removeFromIndexFactory("_private_webpush_index"); - saveSubscription = (server, subscriptionId) => { - return esm_default("chelonia.db/set", `_private_webpush_${subscriptionId}`, JSON.stringify({ - settings: server.pushSubscriptions[subscriptionId].settings, - subscriptionInfo: server.pushSubscriptions[subscriptionId], - channelIDs: [...server.pushSubscriptions[subscriptionId].subscriptions] - })).catch((e2) => { - console.error(e2, "Error saving subscription", subscriptionId); - throw e2; - }); + var { EventEmitter } = __require2("events"); + var { + lsCacheSym, + levelValSym, + setLevelSym, + getLevelSym, + chindingsSym, + parsedChindingsSym, + mixinSym, + asJsonSym, + writeSym, + mixinMergeStrategySym, + timeSym, + timeSliceIndexSym, + streamSym, + serializersSym, + formattersSym, + errorKeySym, + messageKeySym, + useOnlyCustomLevelsSym, + needsMetadataGsym, + redactFmtSym, + stringifySym, + formatOptsSym, + stringifiersSym, + msgPrefixSym + } = require_symbols(); + var { + getLevel, + setLevel, + isLevelEnabled, + mappings, + initialLsCache, + genLsCache, + assertNoLevelCollisions + } = require_levels(); + var { + asChindings, + asJson, + buildFormatters, + stringify: stringify2 + } = require_tools(); + var { + version: version3 + } = require_meta(); + var redaction = require_redaction(); + var constructor = class Pino { }; - addChannelToSubscription = (server, subscriptionId, channelID) => { - server.pushSubscriptions[subscriptionId].subscriptions.add(channelID); - return saveSubscription(server, subscriptionId); + var prototype = { + constructor, + child, + bindings, + setBindings, + flush, + isLevelEnabled, + version: version3, + get level() { + return this[getLevelSym](); + }, + set level(lvl) { + this[setLevelSym](lvl); + }, + get levelVal() { + return this[levelValSym]; + }, + set levelVal(n) { + throw Error("levelVal is read-only"); + }, + [lsCacheSym]: initialLsCache, + [writeSym]: write, + [asJsonSym]: asJson, + [getLevelSym]: getLevel, + [setLevelSym]: setLevel }; - deleteChannelFromSubscription = (server, subscriptionId, channelID) => { - server.pushSubscriptions[subscriptionId].subscriptions.delete(channelID); - return saveSubscription(server, subscriptionId); + Object.setPrototypeOf(prototype, EventEmitter.prototype); + module14.exports = function() { + return Object.create(prototype); }; - removeSubscription = async (subscriptionId) => { - try { - const server = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const subscription = server.pushSubscriptions[subscriptionId]; - if (subscription) { - delete server.pushSubscriptions[subscriptionId]; - if (server.subscribersByChannelID) { - subscription.subscriptions.forEach((channelID) => { - server.subscribersByChannelID[channelID]?.delete(subscription); - }); - } - } else { - } - await esm_default("chelonia.db/delete", `_private_webpush_${subscriptionId}`); - await deleteSubscriptionFromIndex(subscriptionId); - } catch (e2) { - console.error(e2, "Error removing subscription", subscriptionId); + var resetChildingsFormatter = (bindings2) => bindings2; + function child(bindings2, options2) { + if (!bindings2) { + throw Error("missing bindings for child Pino"); } - }; - subscriptionInfoWrapper = (subscriptionId, subscriptionInfo, extra) => { - subscriptionInfo.endpoint = new URL(subscriptionInfo.endpoint); - Object.defineProperties(subscriptionInfo, { - "id": { - get() { - return subscriptionId; - } - }, - // These encryption keys are used for encrypting push notification bodies - // and are unrelated to VAPID, which is used for provenance. - "encryptionKeys": { - get: /* @__PURE__ */ (() => { - let count = 0; - let resultPromise; - let salt; - let uaPublic; - return function() { - if ((count | 0) === 0) { - if (!salt) { - salt = Buffer14.from(this.keys.auth, "base64url"); - } - if (!uaPublic) { - uaPublic = Buffer14.from(this.keys.p256dh, "base64url"); - } - resultPromise = rfc8291Ikm_default(uaPublic, salt); - count = 1; - } else { - count++; - } - return resultPromise; - }; - })() - }, - "settings": { - value: extra.settings || {} - }, - "sockets": { - value: /* @__PURE__ */ new Set() - }, - "subscriptions": { - value: new Set(extra.channelIDs) + options2 = options2 || {}; + const serializers = this[serializersSym]; + const formatters = this[formattersSym]; + const instance = Object.create(this); + if (options2.hasOwnProperty("serializers") === true) { + instance[serializersSym] = /* @__PURE__ */ Object.create(null); + for (const k in serializers) { + instance[serializersSym][k] = serializers[k]; } - }); - Object.freeze(subscriptionInfo); - return subscriptionInfo; - }; - encryptPayload = async (subscription, data) => { - const readableStream = new Response(data).body; - if (!readableStream) throw new Error("Failed to create readable stream"); - const [asPublic, IKM] = await subscription.encryptionKeys; - return K(x2, readableStream, 32768, asPublic, IKM).then(async (bodyStream) => { - const chunks = []; - const reader = bodyStream.getReader(); - for (; ; ) { - const { done, value } = await reader.read(); - if (done) break; - chunks.push(new Uint8Array(value)); + const parentSymbols = Object.getOwnPropertySymbols(serializers); + for (var i2 = 0; i2 < parentSymbols.length; i2++) { + const ks = parentSymbols[i2]; + instance[serializersSym][ks] = serializers[ks]; } - return Buffer14.concat(chunks); - }); - }; - postEvent = async (subscription, event) => { - const authorization = await vapidAuthorization(subscription.endpoint); - const body = event ? await encryptPayload(subscription, event) : void 0; - const req = await fetch(subscription.endpoint, { - method: "POST", - headers: [ - ["authorization", authorization], - ...body ? [ - ["content-encoding", "aes128gcm"], - [ - "content-type", - "application/octet-stream" - ] - ] : [], - // ['push-receipt', ''], - ["ttl", "60"] - ], - body - }); - if (!req.ok) { - const endpointHost = new URL(subscription.endpoint).host; - console.info( - await req.text().then((response) => ({ response })).catch((e2) => `ERR: ${e2?.message}`), - `Error ${req.status} sending push notification to '${subscription.id}' via ${endpointHost}` - ); - if ([401, 404, 410].includes(req.status)) { - removeSubscription(subscription.id); - throw new Error(`Error sending push: ${req.status}`); + for (const bk in options2.serializers) { + instance[serializersSym][bk] = options2.serializers[bk]; } - if (req.status === 413) { - throw new Error("Payload too large"); + const bindingsSymbols = Object.getOwnPropertySymbols(options2.serializers); + for (var bi = 0; bi < bindingsSymbols.length; bi++) { + const bks = bindingsSymbols[bi]; + instance[serializersSym][bks] = options2.serializers[bks]; } + } else instance[serializersSym] = serializers; + if (options2.hasOwnProperty("formatters")) { + const { level, bindings: chindings, log: log2 } = options2.formatters; + instance[formattersSym] = buildFormatters( + level || formatters.level, + chindings || resetChildingsFormatter, + log2 || formatters.log + ); + } else { + instance[formattersSym] = buildFormatters( + formatters.level, + resetChildingsFormatter, + formatters.log + ); } - }; - pushServerActionhandlers = { - [PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY]() { - const socket = this; - socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); - }, - async [PUSH_SERVER_ACTION_TYPE.STORE_SUBSCRIPTION](payload) { - const socket = this; - const { server } = socket; - const { applicationServerKey, settings, subscriptionInfo } = payload; - if (applicationServerKey) { - const ourVapidPublicKey = getVapidPublicKey(); - const theirVapidPublicKey = Buffer14.from(applicationServerKey, "base64").toString("base64url"); - if (ourVapidPublicKey !== theirVapidPublicKey) { - socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); - console.warn({ ourVapidPublicKey, theirVapidPublicKey }, "Refusing to store subscription because the associated public VAPID key does not match ours"); - return; - } - } - let subscriptionId = null; - let host = ""; - let subscriptionWrapper = null; - try { - subscriptionId = await getSubscriptionId(subscriptionInfo); - subscriptionWrapper = server.pushSubscriptions[subscriptionId]; - if (!subscriptionWrapper) { - console.debug(`saving new push subscription '${subscriptionId}':`, subscriptionInfo); - server.pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { settings }); - subscriptionWrapper = server.pushSubscriptions[subscriptionId]; - host = subscriptionWrapper.endpoint.host; - await addSubscriptionToIndex(subscriptionId); - await saveSubscription(server, subscriptionId); - await postEvent(subscriptionWrapper, JSON.stringify({ type: "initial" })); - } else { - host = subscriptionWrapper.endpoint.host; - if (subscriptionWrapper.sockets.size === 0) { - subscriptionWrapper.subscriptions.forEach((channelID) => { - if (!server.subscribersByChannelID[channelID]) return; - server.subscribersByChannelID[channelID].delete(subscriptionWrapper); - }); - } - } - if (socket.pushSubscriptionId) { - if (socket.pushSubscriptionId === subscriptionId) return; - await removeSubscription(socket.pushSubscriptionId); - } - socket.pushSubscriptionId = subscriptionId; - subscriptionWrapper.subscriptions.forEach((channelID) => { - server.subscribersByChannelID[channelID]?.delete(subscriptionWrapper); - }); - subscriptionWrapper.sockets.add(socket); - socket.subscriptions?.forEach((channelID) => { - subscriptionWrapper.subscriptions.add(channelID); - }); - await saveSubscription(server, subscriptionId); - } catch (e2) { - console.error(e2, `[${socket.ip}] Failed to store subscription '${subscriptionId || "??"}' (${host}), removing it!`); - subscriptionId && removeSubscription(subscriptionId); - throw e2; + if (options2.hasOwnProperty("customLevels") === true) { + assertNoLevelCollisions(this.levels, options2.customLevels); + instance.levels = mappings(options2.customLevels, instance[useOnlyCustomLevelsSym]); + genLsCache(instance); + } + if (typeof options2.redact === "object" && options2.redact !== null || Array.isArray(options2.redact)) { + instance.redact = options2.redact; + const stringifiers = redaction(instance.redact, stringify2); + const formatOpts = { stringify: stringifiers[redactFmtSym] }; + instance[stringifySym] = stringify2; + instance[stringifiersSym] = stringifiers; + instance[formatOptsSym] = formatOpts; + } + if (typeof options2.msgPrefix === "string") { + instance[msgPrefixSym] = (this[msgPrefixSym] || "") + options2.msgPrefix; + } + instance[chindingsSym] = asChindings(instance, bindings2); + const childLevel = options2.level || this.level; + instance[setLevelSym](childLevel); + this.onChild(instance); + return instance; + } + function bindings() { + const chindings = this[chindingsSym]; + const chindingsJson = `{${chindings.substr(1)}}`; + const bindingsFromJson = JSON.parse(chindingsJson); + delete bindingsFromJson.pid; + delete bindingsFromJson.hostname; + return bindingsFromJson; + } + function setBindings(newBindings) { + const chindings = asChindings(this, newBindings); + this[chindingsSym] = chindings; + delete this[parsedChindingsSym]; + } + function defaultMixinMergeStrategy(mergeObject, mixinObject) { + return Object.assign(mixinObject, mergeObject); + } + function write(_obj, msg, num) { + const t = this[timeSym](); + const mixin3 = this[mixinSym]; + const errorKey = this[errorKeySym]; + const messageKey = this[messageKeySym]; + const mixinMergeStrategy = this[mixinMergeStrategySym] || defaultMixinMergeStrategy; + let obj; + if (_obj === void 0 || _obj === null) { + obj = {}; + } else if (_obj instanceof Error) { + obj = { [errorKey]: _obj }; + if (msg === void 0) { + msg = _obj.message; } - }, - [PUSH_SERVER_ACTION_TYPE.DELETE_SUBSCRIPTION]() { - const socket = this; - const { pushSubscriptionId: subscriptionId } = socket; - if (subscriptionId) { - return removeSubscription(subscriptionId); + } else { + obj = _obj; + if (msg === void 0 && _obj[messageKey] === void 0 && _obj[errorKey]) { + msg = _obj[errorKey].message; } } - }; + if (mixin3) { + obj = mixinMergeStrategy(obj, mixin3(obj, num, this)); + } + const s = this[asJsonSym](obj, msg, num, t); + const stream = this[streamSym]; + if (stream[needsMetadataGsym] === true) { + stream.lastLevel = num; + stream.lastObj = obj; + stream.lastMsg = msg; + stream.lastTime = t.slice(this[timeSliceIndexSym]); + stream.lastLogger = this; + } + stream.write(s); + } + function noop() { + } + function flush(cb) { + if (cb != null && typeof cb !== "function") { + throw Error("callback must be a function"); + } + const stream = this[streamSym]; + if (typeof stream.flush === "function") { + stream.flush(cb || noop); + } else if (cb) cb(); + } } }); -var require_stream = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/stream.js"(exports2, module14) { +var require_safe_stable_stringify = __commonJS({ + "node_modules/.deno/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports2, module14) { "use strict"; - var { Duplex } = __require2("stream"); - function emitClose(stream) { - stream.emit("close"); + var { hasOwnProperty } = Object.prototype; + var stringify2 = configure(); + stringify2.configure = configure; + stringify2.stringify = stringify2; + stringify2.default = stringify2; + exports2.stringify = stringify2; + exports2.configure = configure; + module14.exports = stringify2; + var strEscapeSequencesRegExp = /[\u0000-\u001f\u0022\u005c\ud800-\udfff]/; + function strEscape(str) { + if (str.length < 5e3 && !strEscapeSequencesRegExp.test(str)) { + return `"${str}"`; + } + return JSON.stringify(str); } - function duplexOnEnd() { - if (!this.destroyed && this._writableState.finished) { - this.destroy(); + function sort(array2, comparator) { + if (array2.length > 200 || comparator) { + return array2.sort(comparator); + } + for (let i2 = 1; i2 < array2.length; i2++) { + const currentValue = array2[i2]; + let position = i2; + while (position !== 0 && array2[position - 1] > currentValue) { + array2[position] = array2[position - 1]; + position--; + } + array2[position] = currentValue; } + return array2; } - function duplexOnError(err) { - this.removeListener("error", duplexOnError); - this.destroy(); - if (this.listenerCount("error") === 0) { - this.emit("error", err); + var typedArrayPrototypeGetSymbolToStringTag = Object.getOwnPropertyDescriptor( + Object.getPrototypeOf( + Object.getPrototypeOf( + new Int8Array() + ) + ), + Symbol.toStringTag + ).get; + function isTypedArrayWithEntries(value) { + return typedArrayPrototypeGetSymbolToStringTag.call(value) !== void 0 && value.length !== 0; + } + function stringifyTypedArray(array2, separator, maximumBreadth) { + if (array2.length < maximumBreadth) { + maximumBreadth = array2.length; + } + const whitespace = separator === "," ? "" : " "; + let res = `"0":${whitespace}${array2[0]}`; + for (let i2 = 1; i2 < maximumBreadth; i2++) { + res += `${separator}"${i2}":${whitespace}${array2[i2]}`; } + return res; } - function createWebSocketStream2(ws, options2) { - let terminateOnDestroy = true; - const duplex = new Duplex({ - ...options2, - autoDestroy: false, - emitClose: false, - objectMode: false, - writableObjectMode: false - }); - ws.on("message", function message(msg, isBinary) { - const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; - if (!duplex.push(data)) ws.pause(); - }); - ws.once("error", function error2(err) { - if (duplex.destroyed) return; - terminateOnDestroy = false; - duplex.destroy(err); - }); - ws.once("close", function close() { - if (duplex.destroyed) return; - duplex.push(null); - }); - duplex._destroy = function(err, callback) { - if (ws.readyState === ws.CLOSED) { - callback(err); - process.nextTick(emitClose, duplex); - return; - } - let called = false; - ws.once("error", function error2(err2) { - called = true; - callback(err2); - }); - ws.once("close", function close() { - if (!called) callback(err); - process.nextTick(emitClose, duplex); - }); - if (terminateOnDestroy) ws.terminate(); - }; - duplex._final = function(callback) { - if (ws.readyState === ws.CONNECTING) { - ws.once("open", function open2() { - duplex._final(callback); - }); - return; + function getCircularValueOption(options2) { + if (hasOwnProperty.call(options2, "circularValue")) { + const circularValue = options2.circularValue; + if (typeof circularValue === "string") { + return `"${circularValue}"`; } - if (ws._socket === null) return; - if (ws._socket._writableState.finished) { - callback(); - if (duplex._readableState.endEmitted) duplex.destroy(); - } else { - ws._socket.once("finish", function finish() { - callback(); - }); - ws.close(); + if (circularValue == null) { + return circularValue; } - }; - duplex._read = function() { - if (ws.isPaused) ws.resume(); - }; - duplex._write = function(chunk, encoding, callback) { - if (ws.readyState === ws.CONNECTING) { - ws.once("open", function open2() { - duplex._write(chunk, encoding, callback); - }); - return; + if (circularValue === Error || circularValue === TypeError) { + return { + toString() { + throw new TypeError("Converting circular structure to JSON"); + } + }; } - ws.send(chunk, callback); - }; - duplex.on("end", duplexOnEnd); - duplex.on("error", duplexOnError); - return duplex; - } - module14.exports = createWebSocketStream2; - } -}); -var require_constants2 = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/constants.js"(exports2, module14) { - "use strict"; - module14.exports = { - BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], - EMPTY_BUFFER: Buffer.alloc(0), - GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", - kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), - kListener: Symbol("kListener"), - kStatusCode: Symbol("status-code"), - kWebSocket: Symbol("websocket"), - NOOP: () => { - } - }; - } -}); -var require_buffer_util = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/buffer-util.js"(exports2, module14) { - "use strict"; - var { EMPTY_BUFFER } = require_constants2(); - function concat2(list, totalLength) { - if (list.length === 0) return EMPTY_BUFFER; - if (list.length === 1) return list[0]; - const target = Buffer.allocUnsafe(totalLength); - let offset = 0; - for (let i2 = 0; i2 < list.length; i2++) { - const buf2 = list[i2]; - target.set(buf2, offset); - offset += buf2.length; + throw new TypeError('The "circularValue" argument must be of type string or the value null or undefined'); } - if (offset < totalLength) return target.slice(0, offset); - return target; + return '"[Circular]"'; } - function _mask(source, mask, output, offset, length2) { - for (let i2 = 0; i2 < length2; i2++) { - output[offset + i2] = source[i2] ^ mask[i2 & 3]; + function getDeterministicOption(options2) { + let value; + if (hasOwnProperty.call(options2, "deterministic")) { + value = options2.deterministic; + if (typeof value !== "boolean" && typeof value !== "function") { + throw new TypeError('The "deterministic" argument must be of type boolean or comparator function'); + } } + return value === void 0 ? true : value; } - function _unmask(buffer, mask) { - for (let i2 = 0; i2 < buffer.length; i2++) { - buffer[i2] ^= mask[i2 & 3]; + function getBooleanOption(options2, key) { + let value; + if (hasOwnProperty.call(options2, key)) { + value = options2[key]; + if (typeof value !== "boolean") { + throw new TypeError(`The "${key}" argument must be of type boolean`); + } } + return value === void 0 ? true : value; } - function toArrayBuffer(buf2) { - if (buf2.byteLength === buf2.buffer.byteLength) { - return buf2.buffer; + function getPositiveIntegerOption(options2, key) { + let value; + if (hasOwnProperty.call(options2, key)) { + value = options2[key]; + if (typeof value !== "number") { + throw new TypeError(`The "${key}" argument must be of type number`); + } + if (!Number.isInteger(value)) { + throw new TypeError(`The "${key}" argument must be an integer`); + } + if (value < 1) { + throw new RangeError(`The "${key}" argument must be >= 1`); + } } - return buf2.buffer.slice(buf2.byteOffset, buf2.byteOffset + buf2.byteLength); + return value === void 0 ? Infinity : value; } - function toBuffer(data) { - toBuffer.readOnly = true; - if (Buffer.isBuffer(data)) return data; - let buf2; - if (data instanceof ArrayBuffer) { - buf2 = Buffer.from(data); - } else if (ArrayBuffer.isView(data)) { - buf2 = Buffer.from(data.buffer, data.byteOffset, data.byteLength); - } else { - buf2 = Buffer.from(data); - toBuffer.readOnly = false; + function getItemCount(number3) { + if (number3 === 1) { + return "1 item"; } - return buf2; + return `${number3} items`; } - try { - const bufferUtil = __require2("bufferutil"); - module14.exports = { - concat: concat2, - mask(source, mask, output, offset, length2) { - if (length2 < 48) _mask(source, mask, output, offset, length2); - else bufferUtil.mask(source, mask, output, offset, length2); - }, - toArrayBuffer, - toBuffer, - unmask(buffer, mask) { - if (buffer.length < 32) _unmask(buffer, mask); - else bufferUtil.unmask(buffer, mask); + function getUniqueReplacerSet(replacerArray) { + const replacerSet = /* @__PURE__ */ new Set(); + for (const value of replacerArray) { + if (typeof value === "string" || typeof value === "number") { + replacerSet.add(String(value)); } - }; - } catch (e2) { - module14.exports = { - concat: concat2, - mask: _mask, - toArrayBuffer, - toBuffer, - unmask: _unmask - }; - } - } -}); -var require_limiter = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/limiter.js"(exports2, module14) { - "use strict"; - var kDone = Symbol("kDone"); - var kRun = Symbol("kRun"); - var Limiter = class { - /** - * Creates a new `Limiter`. - * - * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed - * to run concurrently - */ - constructor(concurrency) { - this[kDone] = () => { - this.pending--; - this[kRun](); - }; - this.concurrency = concurrency || Infinity; - this.jobs = []; - this.pending = 0; } - /** - * Adds a job to the queue. - * - * @param {Function} job The job to run - * @public - */ - add(job) { - this.jobs.push(job); - this[kRun](); + return replacerSet; + } + function getStrictOption(options2) { + if (hasOwnProperty.call(options2, "strict")) { + const value = options2.strict; + if (typeof value !== "boolean") { + throw new TypeError('The "strict" argument must be of type boolean'); + } + if (value) { + return (value2) => { + let message = `Object can not safely be stringified. Received type ${typeof value2}`; + if (typeof value2 !== "function") message += ` (${value2.toString()})`; + throw new Error(message); + }; + } } - /** - * Removes a job from the queue and runs it if possible. - * - * @private - */ - [kRun]() { - if (this.pending === this.concurrency) return; - if (this.jobs.length) { - const job = this.jobs.shift(); - this.pending++; - job(this[kDone]); + } + function configure(options2) { + options2 = { ...options2 }; + const fail = getStrictOption(options2); + if (fail) { + if (options2.bigint === void 0) { + options2.bigint = false; + } + if (!("circularValue" in options2)) { + options2.circularValue = Error; } } - }; - module14.exports = Limiter; - } -}); -var require_permessage_deflate = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module14) { - "use strict"; - var zlib = __require2("zlib"); - var bufferUtil = require_buffer_util(); - var Limiter = require_limiter(); - var { kStatusCode } = require_constants2(); - var TRAILER = Buffer.from([0, 0, 255, 255]); - var kPerMessageDeflate = Symbol("permessage-deflate"); - var kTotalLength = Symbol("total-length"); - var kCallback = Symbol("callback"); - var kBuffers = Symbol("buffers"); - var kError = Symbol("error"); - var zlibLimiter; - var PerMessageDeflate = class { - /** - * Creates a PerMessageDeflate instance. - * - * @param {Object} [options] Configuration options - * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support - * for, or request, a custom client window size - * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ - * acknowledge disabling of client context takeover - * @param {Number} [options.concurrencyLimit=10] The number of concurrent - * calls to zlib - * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the - * use of a custom server window size - * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept - * disabling of server context takeover - * @param {Number} [options.threshold=1024] Size (in bytes) below which - * messages should not be compressed if context takeover is disabled - * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on - * deflate - * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on - * inflate - * @param {Boolean} [isServer=false] Create the instance in either server or - * client mode - * @param {Number} [maxPayload=0] The maximum allowed message length - */ - constructor(options2, isServer, maxPayload) { - this._maxPayload = maxPayload | 0; - this._options = options2 || {}; - this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; - this._isServer = !!isServer; - this._deflate = null; - this._inflate = null; - this.params = null; - if (!zlibLimiter) { - const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; - zlibLimiter = new Limiter(concurrency); - } - } - /** - * @type {String} - */ - static get extensionName() { - return "permessage-deflate"; - } - /** - * Create an extension negotiation offer. - * - * @return {Object} Extension parameters - * @public - */ - offer() { - const params = {}; - if (this._options.serverNoContextTakeover) { - params.server_no_context_takeover = true; - } - if (this._options.clientNoContextTakeover) { - params.client_no_context_takeover = true; - } - if (this._options.serverMaxWindowBits) { - params.server_max_window_bits = this._options.serverMaxWindowBits; - } - if (this._options.clientMaxWindowBits) { - params.client_max_window_bits = this._options.clientMaxWindowBits; - } else if (this._options.clientMaxWindowBits == null) { - params.client_max_window_bits = true; - } - return params; - } - /** - * Accept an extension negotiation offer/response. - * - * @param {Array} configurations The extension negotiation offers/reponse - * @return {Object} Accepted configuration - * @public - */ - accept(configurations) { - configurations = this.normalizeParams(configurations); - this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); - return this.params; - } - /** - * Releases all resources used by the extension. - * - * @public - */ - cleanup() { - if (this._inflate) { - this._inflate.close(); - this._inflate = null; - } - if (this._deflate) { - const callback = this._deflate[kCallback]; - this._deflate.close(); - this._deflate = null; - if (callback) { - callback( - new Error( - "The deflate stream was closed while data was being processed" - ) - ); - } + const circularValue = getCircularValueOption(options2); + const bigint2 = getBooleanOption(options2, "bigint"); + const deterministic = getDeterministicOption(options2); + const comparator = typeof deterministic === "function" ? deterministic : void 0; + const maximumDepth = getPositiveIntegerOption(options2, "maximumDepth"); + const maximumBreadth = getPositiveIntegerOption(options2, "maximumBreadth"); + function stringifyFnReplacer(key, parent, stack, replacer, spacer, indentation) { + let value = parent[key]; + if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { + value = value.toJSON(key); } - } - /** - * Accept an extension negotiation offer. - * - * @param {Array} offers The extension negotiation offers - * @return {Object} Accepted configuration - * @private - */ - acceptAsServer(offers) { - const opts = this._options; - const accepted = offers.find((params) => { - if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { - return false; + value = replacer.call(parent, key, value); + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; + } + if (stack.indexOf(value) !== -1) { + return circularValue; + } + let res = ""; + let join10 = ","; + const originalIndentation = indentation; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + if (spacer !== "") { + indentation += spacer; + res += ` +${indentation}`; + join10 = `, +${indentation}`; + } + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += join10; + } + const tmp = stringifyFnReplacer(String(i2), value, stack, replacer, spacer, indentation); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; + } + if (spacer !== "") { + res += ` +${originalIndentation}`; + } + stack.pop(); + return `[${res}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + let whitespace = ""; + let separator = ""; + if (spacer !== "") { + indentation += spacer; + join10 = `, +${indentation}`; + whitespace = " "; + } + const maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (deterministic && !isTypedArrayWithEntries(value)) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; + separator = join10; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`; + separator = join10; + } + if (spacer !== "" && separator.length > 1) { + res = ` +${indentation}${res} +${originalIndentation}`; + } + stack.pop(); + return `{${res}}`; } - return true; - }); - if (!accepted) { - throw new Error("None of the extension offers can be accepted"); - } - if (opts.serverNoContextTakeover) { - accepted.server_no_context_takeover = true; - } - if (opts.clientNoContextTakeover) { - accepted.client_no_context_takeover = true; - } - if (typeof opts.serverMaxWindowBits === "number") { - accepted.server_max_window_bits = opts.serverMaxWindowBits; - } - if (typeof opts.clientMaxWindowBits === "number") { - accepted.client_max_window_bits = opts.clientMaxWindowBits; - } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { - delete accepted.client_max_window_bits; + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; } - return accepted; } - /** - * Accept the extension negotiation response. - * - * @param {Array} response The extension negotiation response - * @return {Object} Accepted configuration - * @private - */ - acceptAsClient(response) { - const params = response[0]; - if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { - throw new Error('Unexpected parameter "client_no_context_takeover"'); - } - if (!params.client_max_window_bits) { - if (typeof this._options.clientMaxWindowBits === "number") { - params.client_max_window_bits = this._options.clientMaxWindowBits; - } - } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { - throw new Error( - 'Unexpected or invalid parameter "client_max_window_bits"' - ); + function stringifyArrayReplacer(key, value, stack, replacer, spacer, indentation) { + if (typeof value === "object" && value !== null && typeof value.toJSON === "function") { + value = value.toJSON(key); } - return params; - } - /** - * Normalize parameters. - * - * @param {Array} configurations The extension negotiation offers/reponse - * @return {Array} The offers/response with normalized parameters - * @private - */ - normalizeParams(configurations) { - configurations.forEach((params) => { - Object.keys(params).forEach((key) => { - let value = params[key]; - if (value.length > 1) { - throw new Error(`Parameter "${key}" must have only a single value`); + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; } - value = value[0]; - if (key === "client_max_window_bits") { - if (value !== true) { - const num = +value; - if (!Number.isInteger(num) || num < 8 || num > 15) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); - } - value = num; - } else if (!this._isServer) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); + if (stack.indexOf(value) !== -1) { + return circularValue; + } + const originalIndentation = indentation; + let res = ""; + let join10 = ","; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; } - } else if (key === "server_max_window_bits") { - const num = +value; - if (!Number.isInteger(num) || num < 8 || num > 15) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; } - value = num; - } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { - if (value !== true) { - throw new TypeError( - `Invalid value for parameter "${key}": ${value}` - ); + stack.push(value); + if (spacer !== "") { + indentation += spacer; + res += ` +${indentation}`; + join10 = `, +${indentation}`; } - } else { - throw new Error(`Unknown parameter "${key}"`); + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += join10; + } + const tmp = stringifyArrayReplacer(String(i2), value[i2], stack, replacer, spacer, indentation); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `${join10}"... ${getItemCount(removedKeys)} not stringified"`; + } + if (spacer !== "") { + res += ` +${originalIndentation}`; + } + stack.pop(); + return `[${res}]`; } - params[key] = value; - }); - }); - return configurations; - } - /** - * Decompress data. Concurrency limited. - * - * @param {Buffer} data Compressed data - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @public - */ - decompress(data, fin, callback) { - zlibLimiter.add((done) => { - this._decompress(data, fin, (err, result) => { - done(); - callback(err, result); - }); - }); - } - /** - * Compress data. Concurrency limited. - * - * @param {(Buffer|String)} data Data to compress - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @public - */ - compress(data, fin, callback) { - zlibLimiter.add((done) => { - this._compress(data, fin, (err, result) => { - done(); - callback(err, result); - }); - }); - } - /** - * Decompress data. - * - * @param {Buffer} data Compressed data - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @private - */ - _decompress(data, fin, callback) { - const endpoint = this._isServer ? "client" : "server"; - if (!this._inflate) { - const key = `${endpoint}_max_window_bits`; - const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; - this._inflate = zlib.createInflateRaw({ - ...this._options.zlibInflateOptions, - windowBits - }); - this._inflate[kPerMessageDeflate] = this; - this._inflate[kTotalLength] = 0; - this._inflate[kBuffers] = []; - this._inflate.on("error", inflateOnError); - this._inflate.on("data", inflateOnData); - } - this._inflate[kCallback] = callback; - this._inflate.write(data); - if (fin) this._inflate.write(TRAILER); - this._inflate.flush(() => { - const err = this._inflate[kError]; - if (err) { - this._inflate.close(); - this._inflate = null; - callback(err); - return; - } - const data2 = bufferUtil.concat( - this._inflate[kBuffers], - this._inflate[kTotalLength] - ); - if (this._inflate._readableState.endEmitted) { - this._inflate.close(); - this._inflate = null; - } else { - this._inflate[kTotalLength] = 0; - this._inflate[kBuffers] = []; - if (fin && this.params[`${endpoint}_no_context_takeover`]) { - this._inflate.reset(); + stack.push(value); + let whitespace = ""; + if (spacer !== "") { + indentation += spacer; + join10 = `, +${indentation}`; + whitespace = " "; + } + let separator = ""; + for (const key2 of replacer) { + const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`; + separator = join10; + } + } + if (spacer !== "" && separator.length > 1) { + res = ` +${indentation}${res} +${originalIndentation}`; } + stack.pop(); + return `{${res}}`; } - callback(null, data2); - }); - } - /** - * Compress data. - * - * @param {(Buffer|String)} data Data to compress - * @param {Boolean} fin Specifies whether or not this is the last fragment - * @param {Function} callback Callback - * @private - */ - _compress(data, fin, callback) { - const endpoint = this._isServer ? "server" : "client"; - if (!this._deflate) { - const key = `${endpoint}_max_window_bits`; - const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; - this._deflate = zlib.createDeflateRaw({ - ...this._options.zlibDeflateOptions, - windowBits - }); - this._deflate[kTotalLength] = 0; - this._deflate[kBuffers] = []; - this._deflate.on("data", deflateOnData); + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; } - this._deflate[kCallback] = callback; - this._deflate.write(data); - this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { - if (!this._deflate) { - return; - } - let data2 = bufferUtil.concat( - this._deflate[kBuffers], - this._deflate[kTotalLength] - ); - if (fin) data2 = data2.slice(0, data2.length - 4); - this._deflate[kCallback] = null; - this._deflate[kTotalLength] = 0; - this._deflate[kBuffers] = []; - if (fin && this.params[`${endpoint}_no_context_takeover`]) { - this._deflate.reset(); - } - callback(null, data2); - }); } - }; - module14.exports = PerMessageDeflate; - function deflateOnData(chunk) { - this[kBuffers].push(chunk); - this[kTotalLength] += chunk.length; - } - function inflateOnData(chunk) { - this[kTotalLength] += chunk.length; - if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { - this[kBuffers].push(chunk); - return; + function stringifyIndent(key, value, stack, spacer, indentation) { + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; + } + if (typeof value.toJSON === "function") { + value = value.toJSON(key); + if (typeof value !== "object") { + return stringifyIndent(key, value, stack, spacer, indentation); + } + if (value === null) { + return "null"; + } + } + if (stack.indexOf(value) !== -1) { + return circularValue; + } + const originalIndentation = indentation; + if (Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + indentation += spacer; + let res2 = ` +${indentation}`; + const join11 = `, +${indentation}`; + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); + res2 += tmp2 !== void 0 ? tmp2 : "null"; + res2 += join11; + } + const tmp = stringifyIndent(String(i2), value[i2], stack, spacer, indentation); + res2 += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res2 += `${join11}"... ${getItemCount(removedKeys)} not stringified"`; + } + res2 += ` +${originalIndentation}`; + stack.pop(); + return `[${res2}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + indentation += spacer; + const join10 = `, +${indentation}`; + let res = ""; + let separator = ""; + let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (isTypedArrayWithEntries(value)) { + res += stringifyTypedArray(value, join10, maximumBreadth); + keys = keys.slice(value.length); + maximumPropertiesToStringify -= value.length; + separator = join10; + } + if (deterministic) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}: ${tmp}`; + separator = join10; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`; + separator = join10; + } + if (separator !== "") { + res = ` +${indentation}${res} +${originalIndentation}`; + } + stack.pop(); + return `{${res}}`; + } + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; + } } - this[kError] = new RangeError("Max payload size exceeded"); - this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; - this[kError][kStatusCode] = 1009; - this.removeListener("data", inflateOnData); - this.reset(); - } - function inflateOnError(err) { - this[kPerMessageDeflate]._inflate = null; - err[kStatusCode] = 1007; - this[kCallback](err); - } - } -}); -var require_validation = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/validation.js"(exports2, module14) { - "use strict"; - var tokenChars = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // 0 - 15 - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - // 16 - 31 - 0, - 1, - 0, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 1, - 1, - 0, - 1, - 1, - 0, - // 32 - 47 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 0, - 0, - 0, - // 48 - 63 - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - // 64 - 79 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 0, - 0, - 1, - 1, - // 80 - 95 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - // 96 - 111 - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 0, - 1, - 0, - 1, - 0 - // 112 - 127 - ]; - function isValidStatusCode(code2) { - return code2 >= 1e3 && code2 <= 1014 && code2 !== 1004 && code2 !== 1005 && code2 !== 1006 || code2 >= 3e3 && code2 <= 4999; - } - function _isValidUTF8(buf2) { - const len = buf2.length; - let i2 = 0; - while (i2 < len) { - if ((buf2[i2] & 128) === 0) { - i2++; - } else if ((buf2[i2] & 224) === 192) { - if (i2 + 1 === len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2] & 254) === 192) { - return false; + function stringifySimple(key, value, stack) { + switch (typeof value) { + case "string": + return strEscape(value); + case "object": { + if (value === null) { + return "null"; + } + if (typeof value.toJSON === "function") { + value = value.toJSON(key); + if (typeof value !== "object") { + return stringifySimple(key, value, stack); + } + if (value === null) { + return "null"; + } + } + if (stack.indexOf(value) !== -1) { + return circularValue; + } + let res = ""; + const hasLength = value.length !== void 0; + if (hasLength && Array.isArray(value)) { + if (value.length === 0) { + return "[]"; + } + if (maximumDepth < stack.length + 1) { + return '"[Array]"'; + } + stack.push(value); + const maximumValuesToStringify = Math.min(value.length, maximumBreadth); + let i2 = 0; + for (; i2 < maximumValuesToStringify - 1; i2++) { + const tmp2 = stringifySimple(String(i2), value[i2], stack); + res += tmp2 !== void 0 ? tmp2 : "null"; + res += ","; + } + const tmp = stringifySimple(String(i2), value[i2], stack); + res += tmp !== void 0 ? tmp : "null"; + if (value.length - 1 > maximumBreadth) { + const removedKeys = value.length - maximumBreadth - 1; + res += `,"... ${getItemCount(removedKeys)} not stringified"`; + } + stack.pop(); + return `[${res}]`; + } + let keys = Object.keys(value); + const keyLength = keys.length; + if (keyLength === 0) { + return "{}"; + } + if (maximumDepth < stack.length + 1) { + return '"[Object]"'; + } + let separator = ""; + let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth); + if (hasLength && isTypedArrayWithEntries(value)) { + res += stringifyTypedArray(value, ",", maximumBreadth); + keys = keys.slice(value.length); + maximumPropertiesToStringify -= value.length; + separator = ","; + } + if (deterministic) { + keys = sort(keys, comparator); + } + stack.push(value); + for (let i2 = 0; i2 < maximumPropertiesToStringify; i2++) { + const key2 = keys[i2]; + const tmp = stringifySimple(key2, value[key2], stack); + if (tmp !== void 0) { + res += `${separator}${strEscape(key2)}:${tmp}`; + separator = ","; + } + } + if (keyLength > maximumBreadth) { + const removedKeys = keyLength - maximumBreadth; + res += `${separator}"...":"${getItemCount(removedKeys)} not stringified"`; + } + stack.pop(); + return `{${res}}`; } - i2 += 2; - } else if ((buf2[i2] & 240) === 224) { - if (i2 + 2 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || buf2[i2] === 224 && (buf2[i2 + 1] & 224) === 128 || // Overlong - buf2[i2] === 237 && (buf2[i2 + 1] & 224) === 160) { - return false; + case "number": + return isFinite(value) ? String(value) : fail ? fail(value) : "null"; + case "boolean": + return value === true ? "true" : "false"; + case "undefined": + return void 0; + case "bigint": + if (bigint2) { + return String(value); + } + // fallthrough + default: + return fail ? fail(value) : void 0; + } + } + function stringify3(value, replacer, space) { + if (arguments.length > 1) { + let spacer = ""; + if (typeof space === "number") { + spacer = " ".repeat(Math.min(space, 10)); + } else if (typeof space === "string") { + spacer = space.slice(0, 10); } - i2 += 3; - } else if ((buf2[i2] & 248) === 240) { - if (i2 + 3 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || (buf2[i2 + 3] & 192) !== 128 || buf2[i2] === 240 && (buf2[i2 + 1] & 240) === 128 || // Overlong - buf2[i2] === 244 && buf2[i2 + 1] > 143 || buf2[i2] > 244) { - return false; + if (replacer != null) { + if (typeof replacer === "function") { + return stringifyFnReplacer("", { "": value }, [], replacer, spacer, ""); + } + if (Array.isArray(replacer)) { + return stringifyArrayReplacer("", value, [], getUniqueReplacerSet(replacer), spacer, ""); + } + } + if (spacer.length !== 0) { + return stringifyIndent("", value, [], spacer, ""); } - i2 += 4; - } else { - return false; } + return stringifySimple("", value, []); } - return true; - } - try { - const isValidUTF8 = __require2("utf-8-validate"); - module14.exports = { - isValidStatusCode, - isValidUTF8(buf2) { - return buf2.length < 150 ? _isValidUTF8(buf2) : isValidUTF8(buf2); - }, - tokenChars - }; - } catch (e2) { - module14.exports = { - isValidStatusCode, - isValidUTF8: _isValidUTF8, - tokenChars - }; + return stringify3; } } }); -var require_receiver = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/receiver.js"(exports2, module14) { +var require_multistream = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/multistream.js"(exports2, module14) { "use strict"; - var { Writable } = __require2("stream"); - var PerMessageDeflate = require_permessage_deflate(); - var { - BINARY_TYPES, - EMPTY_BUFFER, - kStatusCode, - kWebSocket - } = require_constants2(); - var { concat: concat2, toArrayBuffer, unmask } = require_buffer_util(); - var { isValidStatusCode, isValidUTF8 } = require_validation(); - var GET_INFO = 0; - var GET_PAYLOAD_LENGTH_16 = 1; - var GET_PAYLOAD_LENGTH_64 = 2; - var GET_MASK = 3; - var GET_DATA = 4; - var INFLATING = 5; - var Receiver2 = class extends Writable { - /** - * Creates a Receiver instance. - * - * @param {Object} [options] Options object - * @param {String} [options.binaryType=nodebuffer] The type for binary data - * @param {Object} [options.extensions] An object containing the negotiated - * extensions - * @param {Boolean} [options.isServer=false] Specifies whether to operate in - * client or server mode - * @param {Number} [options.maxPayload=0] The maximum allowed message length - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages - */ - constructor(options2 = {}) { - super(); - this._binaryType = options2.binaryType || BINARY_TYPES[0]; - this._extensions = options2.extensions || {}; - this._isServer = !!options2.isServer; - this._maxPayload = options2.maxPayload | 0; - this._skipUTF8Validation = !!options2.skipUTF8Validation; - this[kWebSocket] = void 0; - this._bufferedBytes = 0; - this._buffers = []; - this._compressed = false; - this._payloadLength = 0; - this._mask = void 0; - this._fragmented = 0; - this._masked = false; - this._fin = false; - this._opcode = 0; - this._totalPayloadLength = 0; - this._messageLength = 0; - this._fragments = []; - this._state = GET_INFO; - this._loop = false; - } - /** - * Implements `Writable.prototype._write()`. - * - * @param {Buffer} chunk The chunk of data to write - * @param {String} encoding The character encoding of `chunk` - * @param {Function} cb Callback - * @private - */ - _write(chunk, encoding, cb) { - if (this._opcode === 8 && this._state == GET_INFO) return cb(); - this._bufferedBytes += chunk.length; - this._buffers.push(chunk); - this.startLoop(cb); + var metadata = Symbol.for("pino.metadata"); + var { DEFAULT_LEVELS } = require_constants(); + var DEFAULT_INFO_LEVEL = DEFAULT_LEVELS.info; + function multistream(streamsArray, opts) { + let counter = 0; + streamsArray = streamsArray || []; + opts = opts || { dedupe: false }; + const streamLevels = Object.create(DEFAULT_LEVELS); + streamLevels.silent = Infinity; + if (opts.levels && typeof opts.levels === "object") { + Object.keys(opts.levels).forEach((i2) => { + streamLevels[i2] = opts.levels[i2]; + }); } - /** - * Consumes `n` bytes from the buffered data. - * - * @param {Number} n The number of bytes to consume - * @return {Buffer} The consumed bytes - * @private - */ - consume(n) { - this._bufferedBytes -= n; - if (n === this._buffers[0].length) return this._buffers.shift(); - if (n < this._buffers[0].length) { - const buf2 = this._buffers[0]; - this._buffers[0] = buf2.slice(n); - return buf2.slice(0, n); - } - const dst = Buffer.allocUnsafe(n); - do { - const buf2 = this._buffers[0]; - const offset = dst.length - n; - if (n >= buf2.length) { - dst.set(this._buffers.shift(), offset); - } else { - dst.set(new Uint8Array(buf2.buffer, buf2.byteOffset, n), offset); - this._buffers[0] = buf2.slice(n); - } - n -= buf2.length; - } while (n > 0); - return dst; + const res = { + write, + add, + flushSync, + end, + minLevel: 0, + streams: [], + clone: clone2, + [metadata]: true, + streamLevels + }; + if (Array.isArray(streamsArray)) { + streamsArray.forEach(add, res); + } else { + add.call(res, streamsArray); } - /** - * Starts the parsing loop. - * - * @param {Function} cb Callback - * @private - */ - startLoop(cb) { - let err; - this._loop = true; - do { - switch (this._state) { - case GET_INFO: - err = this.getInfo(); - break; - case GET_PAYLOAD_LENGTH_16: - err = this.getPayloadLength16(); - break; - case GET_PAYLOAD_LENGTH_64: - err = this.getPayloadLength64(); - break; - case GET_MASK: - this.getMask(); - break; - case GET_DATA: - err = this.getData(cb); + streamsArray = null; + return res; + function write(data) { + let dest; + const level = this.lastLevel; + const { streams } = this; + let recordedLevel = 0; + let stream; + for (let i2 = initLoopVar(streams.length, opts.dedupe); checkLoopVar(i2, streams.length, opts.dedupe); i2 = adjustLoopVar(i2, opts.dedupe)) { + dest = streams[i2]; + if (dest.level <= level) { + if (recordedLevel !== 0 && recordedLevel !== dest.level) { break; - default: - this._loop = false; - return; - } - } while (this._loop); - cb(err); - } - /** - * Reads the first two bytes of a frame. - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getInfo() { - if (this._bufferedBytes < 2) { - this._loop = false; - return; - } - const buf2 = this.consume(2); - if ((buf2[0] & 48) !== 0) { - this._loop = false; - return error2( - RangeError, - "RSV2 and RSV3 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_2_3" - ); - } - const compressed = (buf2[0] & 64) === 64; - if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - this._fin = (buf2[0] & 128) === 128; - this._opcode = buf2[0] & 15; - this._payloadLength = buf2[1] & 127; - if (this._opcode === 0) { - if (compressed) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - if (!this._fragmented) { - this._loop = false; - return error2( - RangeError, - "invalid opcode 0", - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - this._opcode = this._fragmented; - } else if (this._opcode === 1 || this._opcode === 2) { - if (this._fragmented) { - this._loop = false; - return error2( - RangeError, - `invalid opcode ${this._opcode}`, - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - this._compressed = compressed; - } else if (this._opcode > 7 && this._opcode < 11) { - if (!this._fin) { - this._loop = false; - return error2( - RangeError, - "FIN must be set", - true, - 1002, - "WS_ERR_EXPECTED_FIN" - ); - } - if (compressed) { - this._loop = false; - return error2( - RangeError, - "RSV1 must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_RSV_1" - ); - } - if (this._payloadLength > 125) { - this._loop = false; - return error2( - RangeError, - `invalid payload length ${this._payloadLength}`, - true, - 1002, - "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" - ); - } - } else { - this._loop = false; - return error2( - RangeError, - `invalid opcode ${this._opcode}`, - true, - 1002, - "WS_ERR_INVALID_OPCODE" - ); - } - if (!this._fin && !this._fragmented) this._fragmented = this._opcode; - this._masked = (buf2[1] & 128) === 128; - if (this._isServer) { - if (!this._masked) { - this._loop = false; - return error2( - RangeError, - "MASK must be set", - true, - 1002, - "WS_ERR_EXPECTED_MASK" - ); + } + stream = dest.stream; + if (stream[metadata]) { + const { lastTime, lastMsg, lastObj, lastLogger } = this; + stream.lastLevel = level; + stream.lastTime = lastTime; + stream.lastMsg = lastMsg; + stream.lastObj = lastObj; + stream.lastLogger = lastLogger; + } + stream.write(data); + if (opts.dedupe) { + recordedLevel = dest.level; + } + } else if (!opts.dedupe) { + break; } - } else if (this._masked) { - this._loop = false; - return error2( - RangeError, - "MASK must be clear", - true, - 1002, - "WS_ERR_UNEXPECTED_MASK" - ); - } - if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; - else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; - else return this.haveLength(); - } - /** - * Gets extended payload length (7+16). - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getPayloadLength16() { - if (this._bufferedBytes < 2) { - this._loop = false; - return; - } - this._payloadLength = this.consume(2).readUInt16BE(0); - return this.haveLength(); - } - /** - * Gets extended payload length (7+64). - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - getPayloadLength64() { - if (this._bufferedBytes < 8) { - this._loop = false; - return; - } - const buf2 = this.consume(8); - const num = buf2.readUInt32BE(0); - if (num > Math.pow(2, 53 - 32) - 1) { - this._loop = false; - return error2( - RangeError, - "Unsupported WebSocket frame: payload length > 2^53 - 1", - false, - 1009, - "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" - ); } - this._payloadLength = num * Math.pow(2, 32) + buf2.readUInt32BE(4); - return this.haveLength(); } - /** - * Payload length has been read. - * - * @return {(RangeError|undefined)} A possible error - * @private - */ - haveLength() { - if (this._payloadLength && this._opcode < 8) { - this._totalPayloadLength += this._payloadLength; - if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { - this._loop = false; - return error2( - RangeError, - "Max payload size exceeded", - false, - 1009, - "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" - ); + function flushSync() { + for (const { stream } of this.streams) { + if (typeof stream.flushSync === "function") { + stream.flushSync(); } } - if (this._masked) this._state = GET_MASK; - else this._state = GET_DATA; - } - /** - * Reads mask bytes. - * - * @private - */ - getMask() { - if (this._bufferedBytes < 4) { - this._loop = false; - return; - } - this._mask = this.consume(4); - this._state = GET_DATA; } - /** - * Reads data bytes. - * - * @param {Function} cb Callback - * @return {(Error|RangeError|undefined)} A possible error - * @private - */ - getData(cb) { - let data = EMPTY_BUFFER; - if (this._payloadLength) { - if (this._bufferedBytes < this._payloadLength) { - this._loop = false; - return; - } - data = this.consume(this._payloadLength); - if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { - unmask(data, this._mask); - } + function add(dest) { + if (!dest) { + return res; } - if (this._opcode > 7) return this.controlMessage(data); - if (this._compressed) { - this._state = INFLATING; - this.decompress(data, cb); - return; + const isStream = typeof dest.write === "function" || dest.stream; + const stream_ = dest.write ? dest : dest.stream; + if (!isStream) { + throw Error("stream object needs to implement either StreamEntry or DestinationStream interface"); } - if (data.length) { - this._messageLength = this._totalPayloadLength; - this._fragments.push(data); + const { streams, streamLevels: streamLevels2 } = this; + let level; + if (typeof dest.levelVal === "number") { + level = dest.levelVal; + } else if (typeof dest.level === "string") { + level = streamLevels2[dest.level]; + } else if (typeof dest.level === "number") { + level = dest.level; + } else { + level = DEFAULT_INFO_LEVEL; } - return this.dataMessage(); - } - /** - * Decompresses data. - * - * @param {Buffer} data Compressed data - * @param {Function} cb Callback - * @private - */ - decompress(data, cb) { - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - perMessageDeflate.decompress(data, this._fin, (err, buf2) => { - if (err) return cb(err); - if (buf2.length) { - this._messageLength += buf2.length; - if (this._messageLength > this._maxPayload && this._maxPayload > 0) { - return cb( - error2( - RangeError, - "Max payload size exceeded", - false, - 1009, - "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" - ) - ); - } - this._fragments.push(buf2); - } - const er = this.dataMessage(); - if (er) return cb(er); - this.startLoop(cb); - }); + const dest_ = { + stream: stream_, + level, + levelVal: void 0, + id: counter++ + }; + streams.unshift(dest_); + streams.sort(compareByLevel); + this.minLevel = streams[0].level; + return res; } - /** - * Handles a data message. - * - * @return {(Error|undefined)} A possible error - * @private - */ - dataMessage() { - if (this._fin) { - const messageLength = this._messageLength; - const fragments = this._fragments; - this._totalPayloadLength = 0; - this._messageLength = 0; - this._fragmented = 0; - this._fragments = []; - if (this._opcode === 2) { - let data; - if (this._binaryType === "nodebuffer") { - data = concat2(fragments, messageLength); - } else if (this._binaryType === "arraybuffer") { - data = toArrayBuffer(concat2(fragments, messageLength)); - } else { - data = fragments; - } - this.emit("message", data, true); - } else { - const buf2 = concat2(fragments, messageLength); - if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { - this._loop = false; - return error2( - Error, - "invalid UTF-8 sequence", - true, - 1007, - "WS_ERR_INVALID_UTF8" - ); - } - this.emit("message", buf2, false); + function end() { + for (const { stream } of this.streams) { + if (typeof stream.flushSync === "function") { + stream.flushSync(); } + stream.end(); } - this._state = GET_INFO; } - /** - * Handles a control message. - * - * @param {Buffer} data Data to handle - * @return {(Error|RangeError|undefined)} A possible error - * @private - */ - controlMessage(data) { - if (this._opcode === 8) { - this._loop = false; - if (data.length === 0) { - this.emit("conclude", 1005, EMPTY_BUFFER); - this.end(); - } else if (data.length === 1) { - return error2( - RangeError, - "invalid payload length 1", - true, - 1002, - "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" - ); - } else { - const code2 = data.readUInt16BE(0); - if (!isValidStatusCode(code2)) { - return error2( - RangeError, - `invalid status code ${code2}`, - true, - 1002, - "WS_ERR_INVALID_CLOSE_CODE" - ); - } - const buf2 = data.slice(2); - if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { - return error2( - Error, - "invalid UTF-8 sequence", - true, - 1007, - "WS_ERR_INVALID_UTF8" - ); - } - this.emit("conclude", code2, buf2); - this.end(); - } - } else if (this._opcode === 9) { - this.emit("ping", data); - } else { - this.emit("pong", data); + function clone2(level) { + const streams = new Array(this.streams.length); + for (let i2 = 0; i2 < streams.length; i2++) { + streams[i2] = { + level, + stream: this.streams[i2].stream + }; } - this._state = GET_INFO; + return { + write, + add, + minLevel: level, + streams, + clone: clone2, + flushSync, + [metadata]: true + }; } - }; - module14.exports = Receiver2; - function error2(ErrorCtor, message, prefix, statusCode, errorCode) { - const err = new ErrorCtor( - prefix ? `Invalid WebSocket frame: ${message}` : message - ); - Error.captureStackTrace(err, error2); - err.code = errorCode; - err[kStatusCode] = statusCode; - return err; } + function compareByLevel(a, b) { + return a.level - b.level; + } + function initLoopVar(length2, dedupe) { + return dedupe ? length2 - 1 : 0; + } + function adjustLoopVar(i2, dedupe) { + return dedupe ? i2 - 1 : i2 + 1; + } + function checkLoopVar(i2, length2, dedupe) { + return dedupe ? i2 >= 0 : i2 < length2; + } + module14.exports = multistream; } }); -var require_sender = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/sender.js"(exports2, module14) { +var require_pino = __commonJS({ + "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports2, module14) { "use strict"; - var net = __require2("net"); - var tls = __require2("tls"); - var { randomFillSync } = __require2("crypto"); - var PerMessageDeflate = require_permessage_deflate(); - var { EMPTY_BUFFER } = require_constants2(); - var { isValidStatusCode } = require_validation(); - var { mask: applyMask, toBuffer } = require_buffer_util(); - var kByteLength = Symbol("kByteLength"); - var maskBuffer = Buffer.alloc(4); - var Sender2 = class _Sender { - /** - * Creates a Sender instance. - * - * @param {(net.Socket|tls.Socket)} socket The connection socket - * @param {Object} [extensions] An object containing the negotiated extensions - * @param {Function} [generateMask] The function used to generate the masking - * key - */ - constructor(socket, extensions, generateMask) { - this._extensions = extensions || {}; - if (generateMask) { - this._generateMask = generateMask; - this._maskBuffer = Buffer.alloc(4); - } - this._socket = socket; - this._firstFragment = true; - this._compress = false; - this._bufferedBytes = 0; - this._deflating = false; - this._queue = []; - } - /** - * Frames a piece of data according to the HyBi WebSocket protocol. - * - * @param {(Buffer|String)} data The data to frame - * @param {Object} options Options object - * @param {Boolean} [options.fin=false] Specifies whether or not to set the - * FIN bit - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Buffer} [options.maskBuffer] The buffer used to store the masking - * key - * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified - * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the - * RSV1 bit - * @return {(Buffer|String)[]} The framed data - * @public - */ - static frame(data, options2) { - let mask; - let merge3 = false; - let offset = 2; - let skipMasking = false; - if (options2.mask) { - mask = options2.maskBuffer || maskBuffer; - if (options2.generateMask) { - options2.generateMask(mask); - } else { - randomFillSync(mask, 0, 4); - } - skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; - offset = 6; + var os = __require2("os"); + var stdSerializers = require_pino_std_serializers(); + var caller = require_caller(); + var redaction = require_redaction(); + var time3 = require_time(); + var proto3 = require_proto(); + var symbols2 = require_symbols(); + var { configure } = require_safe_stable_stringify(); + var { assertDefaultLevelFound, mappings, genLsCache, genLevelComparison, assertLevelComparison } = require_levels(); + var { DEFAULT_LEVELS, SORTING_ORDER } = require_constants(); + var { + createArgsNormalizer, + asChindings, + buildSafeSonicBoom, + buildFormatters, + stringify: stringify2, + normalizeDestFileDescriptor, + noop + } = require_tools(); + var { version: version3 } = require_meta(); + var { + chindingsSym, + redactFmtSym, + serializersSym, + timeSym, + timeSliceIndexSym, + streamSym, + stringifySym, + stringifySafeSym, + stringifiersSym, + setLevelSym, + endSym, + formatOptsSym, + messageKeySym, + errorKeySym, + nestedKeySym, + mixinSym, + levelCompSym, + useOnlyCustomLevelsSym, + formattersSym, + hooksSym, + nestedKeyStrSym, + mixinMergeStrategySym, + msgPrefixSym + } = symbols2; + var { epochTime, nullTime } = time3; + var { pid } = process; + var hostname2 = os.hostname(); + var defaultErrorSerializer = stdSerializers.err; + var defaultOptions4 = { + level: "info", + levelComparison: SORTING_ORDER.ASC, + levels: DEFAULT_LEVELS, + messageKey: "msg", + errorKey: "err", + nestedKey: null, + enabled: true, + base: { pid, hostname: hostname2 }, + serializers: Object.assign(/* @__PURE__ */ Object.create(null), { + err: defaultErrorSerializer + }), + formatters: Object.assign(/* @__PURE__ */ Object.create(null), { + bindings(bindings) { + return bindings; + }, + level(label, number3) { + return { level: number3 }; } - let dataLength; - if (typeof data === "string") { - if ((!options2.mask || skipMasking) && options2[kByteLength] !== void 0) { - dataLength = options2[kByteLength]; - } else { - data = Buffer.from(data); - dataLength = data.length; - } + }), + hooks: { + logMethod: void 0 + }, + timestamp: epochTime, + name: void 0, + redact: null, + customLevels: null, + useOnlyCustomLevels: false, + depthLimit: 5, + edgeLimit: 100 + }; + var normalize32 = createArgsNormalizer(defaultOptions4); + var serializers = Object.assign(/* @__PURE__ */ Object.create(null), stdSerializers); + function pino2(...args) { + const instance = {}; + const { opts, stream } = normalize32(instance, caller(), ...args); + const { + redact, + crlf, + serializers: serializers2, + timestamp, + messageKey, + errorKey, + nestedKey, + base: base2, + name, + level, + customLevels, + levelComparison, + mixin: mixin3, + mixinMergeStrategy, + useOnlyCustomLevels, + formatters, + hooks, + depthLimit, + edgeLimit, + onChild, + msgPrefix + } = opts; + const stringifySafe = configure({ + maximumDepth: depthLimit, + maximumBreadth: edgeLimit + }); + const allFormatters = buildFormatters( + formatters.level, + formatters.bindings, + formatters.log + ); + const stringifyFn = stringify2.bind({ + [stringifySafeSym]: stringifySafe + }); + const stringifiers = redact ? redaction(redact, stringifyFn) : {}; + const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn }; + const end = "}" + (crlf ? "\r\n" : "\n"); + const coreChindings = asChindings.bind(null, { + [chindingsSym]: "", + [serializersSym]: serializers2, + [stringifiersSym]: stringifiers, + [stringifySym]: stringify2, + [stringifySafeSym]: stringifySafe, + [formattersSym]: allFormatters + }); + let chindings = ""; + if (base2 !== null) { + if (name === void 0) { + chindings = coreChindings(base2); } else { - dataLength = data.length; - merge3 = options2.mask && options2.readOnly && !skipMasking; - } - let payloadLength = dataLength; - if (dataLength >= 65536) { - offset += 8; - payloadLength = 127; - } else if (dataLength > 125) { - offset += 2; - payloadLength = 126; - } - const target = Buffer.allocUnsafe(merge3 ? dataLength + offset : offset); - target[0] = options2.fin ? options2.opcode | 128 : options2.opcode; - if (options2.rsv1) target[0] |= 64; - target[1] = payloadLength; - if (payloadLength === 126) { - target.writeUInt16BE(dataLength, 2); - } else if (payloadLength === 127) { - target[2] = target[3] = 0; - target.writeUIntBE(dataLength, 4, 6); - } - if (!options2.mask) return [target, data]; - target[1] |= 128; - target[offset - 4] = mask[0]; - target[offset - 3] = mask[1]; - target[offset - 2] = mask[2]; - target[offset - 1] = mask[3]; - if (skipMasking) return [target, data]; - if (merge3) { - applyMask(data, mask, target, offset, dataLength); - return [target]; + chindings = coreChindings(Object.assign({}, base2, { name })); } - applyMask(data, mask, data, 0, dataLength); - return [target, data]; } - /** - * Sends a close message to the other peer. - * - * @param {Number} [code] The status code component of the body - * @param {(String|Buffer)} [data] The message component of the body - * @param {Boolean} [mask=false] Specifies whether or not to mask the message - * @param {Function} [cb] Callback - * @public - */ - close(code2, data, mask, cb) { - let buf2; - if (code2 === void 0) { - buf2 = EMPTY_BUFFER; - } else if (typeof code2 !== "number" || !isValidStatusCode(code2)) { - throw new TypeError("First argument must be a valid error code number"); - } else if (data === void 0 || !data.length) { - buf2 = Buffer.allocUnsafe(2); - buf2.writeUInt16BE(code2, 0); - } else { - const length2 = Buffer.byteLength(data); - if (length2 > 123) { - throw new RangeError("The message must not be greater than 123 bytes"); - } - buf2 = Buffer.allocUnsafe(2 + length2); - buf2.writeUInt16BE(code2, 0); - if (typeof data === "string") { - buf2.write(data, 2); - } else { - buf2.set(data, 2); - } - } - const options2 = { - [kByteLength]: buf2.length, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 8, - readOnly: false, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, buf2, false, options2, cb]); - } else { - this.sendFrame(_Sender.frame(buf2, options2), cb); - } + const time4 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime; + const timeSliceIndex = time4().indexOf(":") + 1; + if (useOnlyCustomLevels && !customLevels) throw Error("customLevels is required if useOnlyCustomLevels is set true"); + if (mixin3 && typeof mixin3 !== "function") throw Error(`Unknown mixin type "${typeof mixin3}" - expected "function"`); + if (msgPrefix && typeof msgPrefix !== "string") throw Error(`Unknown msgPrefix type "${typeof msgPrefix}" - expected "string"`); + assertDefaultLevelFound(level, customLevels, useOnlyCustomLevels); + const levels = mappings(customLevels, useOnlyCustomLevels); + assertLevelComparison(levelComparison); + const levelCompFunc = genLevelComparison(levelComparison); + Object.assign(instance, { + levels, + [levelCompSym]: levelCompFunc, + [useOnlyCustomLevelsSym]: useOnlyCustomLevels, + [streamSym]: stream, + [timeSym]: time4, + [timeSliceIndexSym]: timeSliceIndex, + [stringifySym]: stringify2, + [stringifySafeSym]: stringifySafe, + [stringifiersSym]: stringifiers, + [endSym]: end, + [formatOptsSym]: formatOpts, + [messageKeySym]: messageKey, + [errorKeySym]: errorKey, + [nestedKeySym]: nestedKey, + // protect against injection + [nestedKeyStrSym]: nestedKey ? `,${JSON.stringify(nestedKey)}:{` : "", + [serializersSym]: serializers2, + [mixinSym]: mixin3, + [mixinMergeStrategySym]: mixinMergeStrategy, + [chindingsSym]: chindings, + [formattersSym]: allFormatters, + [hooksSym]: hooks, + silent: noop, + onChild, + [msgPrefixSym]: msgPrefix + }); + Object.setPrototypeOf(instance, proto3()); + genLsCache(instance); + instance[setLevelSym](level); + return instance; + } + module14.exports = pino2; + module14.exports.destination = (dest = process.stdout.fd) => { + if (typeof dest === "object") { + dest.dest = normalizeDestFileDescriptor(dest.dest || process.stdout.fd); + return buildSafeSonicBoom(dest); + } else { + return buildSafeSonicBoom({ dest: normalizeDestFileDescriptor(dest), minLength: 0 }); } - /** - * Sends a ping message to the other peer. - * - * @param {*} data The message to send - * @param {Boolean} [mask=false] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback - * @public - */ - ping(data, mask, cb) { - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; - } - if (byteLength > 125) { - throw new RangeError("The data size must not be greater than 125 bytes"); - } - const options2 = { - [kByteLength]: byteLength, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 9, - readOnly, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, false, options2, cb]); - } else { - this.sendFrame(_Sender.frame(data, options2), cb); - } + }; + module14.exports.transport = require_transport(); + module14.exports.multistream = require_multistream(); + module14.exports.levels = mappings(); + module14.exports.stdSerializers = serializers; + module14.exports.stdTimeFunctions = Object.assign({}, time3); + module14.exports.symbols = symbols2; + module14.exports.version = version3; + module14.exports.default = pino2; + module14.exports.pino = pino2; + } +}); +var require_stream = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/stream.js"(exports2, module14) { + "use strict"; + var { Duplex } = __require2("stream"); + function emitClose(stream) { + stream.emit("close"); + } + function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); } - /** - * Sends a pong message to the other peer. - * - * @param {*} data The message to send - * @param {Boolean} [mask=false] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback - * @public - */ - pong(data, mask, cb) { - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; + } + function duplexOnError(err) { + this.removeListener("error", duplexOnError); + this.destroy(); + if (this.listenerCount("error") === 0) { + this.emit("error", err); + } + } + function createWebSocketStream2(ws, options2) { + let terminateOnDestroy = true; + const duplex = new Duplex({ + ...options2, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + ws.on("message", function message(msg, isBinary) { + const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + if (!duplex.push(data)) ws.pause(); + }); + ws.once("error", function error2(err) { + if (duplex.destroyed) return; + terminateOnDestroy = false; + duplex.destroy(err); + }); + ws.once("close", function close() { + if (duplex.destroyed) return; + duplex.push(null); + }); + duplex._destroy = function(err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose, duplex); + return; } - if (byteLength > 125) { - throw new RangeError("The data size must not be greater than 125 bytes"); + let called = false; + ws.once("error", function error2(err2) { + called = true; + callback(err2); + }); + ws.once("close", function close() { + if (!called) callback(err); + process.nextTick(emitClose, duplex); + }); + if (terminateOnDestroy) ws.terminate(); + }; + duplex._final = function(callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open2() { + duplex._final(callback); + }); + return; } - const options2 = { - [kByteLength]: byteLength, - fin: true, - generateMask: this._generateMask, - mask, - maskBuffer: this._maskBuffer, - opcode: 10, - readOnly, - rsv1: false - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, false, options2, cb]); + if (ws._socket === null) return; + if (ws._socket._writableState.finished) { + callback(); + if (duplex._readableState.endEmitted) duplex.destroy(); } else { - this.sendFrame(_Sender.frame(data, options2), cb); + ws._socket.once("finish", function finish() { + callback(); + }); + ws.close(); } - } - /** - * Sends a data message to the other peer. - * - * @param {*} data The message to send - * @param {Object} options Options object - * @param {Boolean} [options.binary=false] Specifies whether `data` is binary - * or text - * @param {Boolean} [options.compress=false] Specifies whether or not to - * compress `data` - * @param {Boolean} [options.fin=false] Specifies whether the fragment is the - * last one - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Function} [cb] Callback - * @public - */ - send(data, options2, cb) { - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - let opcode = options2.binary ? 2 : 1; - let rsv1 = options2.compress; - let byteLength; - let readOnly; - if (typeof data === "string") { - byteLength = Buffer.byteLength(data); - readOnly = false; - } else { - data = toBuffer(data); - byteLength = data.length; - readOnly = toBuffer.readOnly; - } - if (this._firstFragment) { - this._firstFragment = false; - if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { - rsv1 = byteLength >= perMessageDeflate._threshold; - } - this._compress = rsv1; - } else { - rsv1 = false; - opcode = 0; - } - if (options2.fin) this._firstFragment = true; - if (perMessageDeflate) { - const opts = { - [kByteLength]: byteLength, - fin: options2.fin, - generateMask: this._generateMask, - mask: options2.mask, - maskBuffer: this._maskBuffer, - opcode, - readOnly, - rsv1 - }; - if (this._deflating) { - this.enqueue([this.dispatch, data, this._compress, opts, cb]); - } else { - this.dispatch(data, this._compress, opts, cb); - } - } else { - this.sendFrame( - _Sender.frame(data, { - [kByteLength]: byteLength, - fin: options2.fin, - generateMask: this._generateMask, - mask: options2.mask, - maskBuffer: this._maskBuffer, - opcode, - readOnly, - rsv1: false - }), - cb - ); - } - } - /** - * Dispatches a message. - * - * @param {(Buffer|String)} data The message to send - * @param {Boolean} [compress=false] Specifies whether or not to compress - * `data` - * @param {Object} options Options object - * @param {Boolean} [options.fin=false] Specifies whether or not to set the - * FIN bit - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Boolean} [options.mask=false] Specifies whether or not to mask - * `data` - * @param {Buffer} [options.maskBuffer] The buffer used to store the masking - * key - * @param {Number} options.opcode The opcode - * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be - * modified - * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the - * RSV1 bit - * @param {Function} [cb] Callback - * @private - */ - dispatch(data, compress, options2, cb) { - if (!compress) { - this.sendFrame(_Sender.frame(data, options2), cb); + }; + duplex._read = function() { + if (ws.isPaused) ws.resume(); + }; + duplex._write = function(chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once("open", function open2() { + duplex._write(chunk, encoding, callback); + }); return; } - const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; - this._bufferedBytes += options2[kByteLength]; - this._deflating = true; - perMessageDeflate.compress(data, options2.fin, (_, buf2) => { - if (this._socket.destroyed) { - const err = new Error( - "The socket was closed while data was being compressed" - ); - if (typeof cb === "function") cb(err); - for (let i2 = 0; i2 < this._queue.length; i2++) { - const params = this._queue[i2]; - const callback = params[params.length - 1]; - if (typeof callback === "function") callback(err); - } - return; - } - this._bufferedBytes -= options2[kByteLength]; - this._deflating = false; - options2.readOnly = false; - this.sendFrame(_Sender.frame(buf2, options2), cb); - this.dequeue(); - }); + ws.send(chunk, callback); + }; + duplex.on("end", duplexOnEnd); + duplex.on("error", duplexOnError); + return duplex; + } + module14.exports = createWebSocketStream2; + } +}); +var require_constants2 = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/constants.js"(exports2, module14) { + "use strict"; + module14.exports = { + BINARY_TYPES: ["nodebuffer", "arraybuffer", "fragments"], + EMPTY_BUFFER: Buffer.alloc(0), + GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + kForOnEventAttribute: Symbol("kIsForOnEventAttribute"), + kListener: Symbol("kListener"), + kStatusCode: Symbol("status-code"), + kWebSocket: Symbol("websocket"), + NOOP: () => { + } + }; + } +}); +var require_buffer_util = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/buffer-util.js"(exports2, module14) { + "use strict"; + var { EMPTY_BUFFER } = require_constants2(); + function concat2(list, totalLength) { + if (list.length === 0) return EMPTY_BUFFER; + if (list.length === 1) return list[0]; + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + for (let i2 = 0; i2 < list.length; i2++) { + const buf2 = list[i2]; + target.set(buf2, offset); + offset += buf2.length; + } + if (offset < totalLength) return target.slice(0, offset); + return target; + } + function _mask(source, mask, output, offset, length2) { + for (let i2 = 0; i2 < length2; i2++) { + output[offset + i2] = source[i2] ^ mask[i2 & 3]; + } + } + function _unmask(buffer, mask) { + for (let i2 = 0; i2 < buffer.length; i2++) { + buffer[i2] ^= mask[i2 & 3]; + } + } + function toArrayBuffer(buf2) { + if (buf2.byteLength === buf2.buffer.byteLength) { + return buf2.buffer; + } + return buf2.buffer.slice(buf2.byteOffset, buf2.byteOffset + buf2.byteLength); + } + function toBuffer(data) { + toBuffer.readOnly = true; + if (Buffer.isBuffer(data)) return data; + let buf2; + if (data instanceof ArrayBuffer) { + buf2 = Buffer.from(data); + } else if (ArrayBuffer.isView(data)) { + buf2 = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } else { + buf2 = Buffer.from(data); + toBuffer.readOnly = false; } + return buf2; + } + try { + const bufferUtil = __require2("bufferutil"); + module14.exports = { + concat: concat2, + mask(source, mask, output, offset, length2) { + if (length2 < 48) _mask(source, mask, output, offset, length2); + else bufferUtil.mask(source, mask, output, offset, length2); + }, + toArrayBuffer, + toBuffer, + unmask(buffer, mask) { + if (buffer.length < 32) _unmask(buffer, mask); + else bufferUtil.unmask(buffer, mask); + } + }; + } catch (e2) { + module14.exports = { + concat: concat2, + mask: _mask, + toArrayBuffer, + toBuffer, + unmask: _unmask + }; + } + } +}); +var require_limiter = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/limiter.js"(exports2, module14) { + "use strict"; + var kDone = Symbol("kDone"); + var kRun = Symbol("kRun"); + var Limiter = class { /** - * Executes queued send operations. + * Creates a new `Limiter`. * - * @private + * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed + * to run concurrently */ - dequeue() { - while (!this._deflating && this._queue.length) { - const params = this._queue.shift(); - this._bufferedBytes -= params[3][kByteLength]; - Reflect.apply(params[0], this, params.slice(1)); - } + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; } /** - * Enqueues a send operation. + * Adds a job to the queue. * - * @param {Array} params Send operation parameters. - * @private + * @param {Function} job The job to run + * @public */ - enqueue(params) { - this._bufferedBytes += params[3][kByteLength]; - this._queue.push(params); + add(job) { + this.jobs.push(job); + this[kRun](); } /** - * Sends a frame. + * Removes a job from the queue and runs it if possible. * - * @param {Buffer[]} list The frame to send - * @param {Function} [cb] Callback * @private */ - sendFrame(list, cb) { - if (list.length === 2) { - this._socket.cork(); - this._socket.write(list[0]); - this._socket.write(list[1], cb); - this._socket.uncork(); - } else { - this._socket.write(list[0], cb); + [kRun]() { + if (this.pending === this.concurrency) return; + if (this.jobs.length) { + const job = this.jobs.shift(); + this.pending++; + job(this[kDone]); } } }; - module14.exports = Sender2; + module14.exports = Limiter; } }); -var require_event_target = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/event-target.js"(exports2, module14) { +var require_permessage_deflate = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module14) { "use strict"; - var { kForOnEventAttribute, kListener } = require_constants2(); - var kCode = Symbol("kCode"); - var kData = Symbol("kData"); - var kError = Symbol("kError"); - var kMessage = Symbol("kMessage"); - var kReason = Symbol("kReason"); - var kTarget = Symbol("kTarget"); - var kType = Symbol("kType"); - var kWasClean = Symbol("kWasClean"); - var Event = class { + var zlib = __require2("zlib"); + var bufferUtil = require_buffer_util(); + var Limiter = require_limiter(); + var { kStatusCode } = require_constants2(); + var TRAILER = Buffer.from([0, 0, 255, 255]); + var kPerMessageDeflate = Symbol("permessage-deflate"); + var kTotalLength = Symbol("total-length"); + var kCallback = Symbol("callback"); + var kBuffers = Symbol("buffers"); + var kError = Symbol("error"); + var zlibLimiter; + var PerMessageDeflate = class { /** - * Create a new `Event`. + * Creates a PerMessageDeflate instance. * - * @param {String} type The name of the event - * @throws {TypeError} If the `type` argument is not specified - */ - constructor(type) { - this[kTarget] = null; - this[kType] = type; - } - /** - * @type {*} + * @param {Object} [options] Configuration options + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size + * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ + * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib + * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the + * use of a custom server window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled + * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on + * deflate + * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on + * inflate + * @param {Boolean} [isServer=false] Create the instance in either server or + * client mode + * @param {Number} [maxPayload=0] The maximum allowed message length */ - get target() { - return this[kTarget]; + constructor(options2, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; + this._options = options2 || {}; + this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024; + this._isServer = !!isServer; + this._deflate = null; + this._inflate = null; + this.params = null; + if (!zlibLimiter) { + const concurrency = this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10; + zlibLimiter = new Limiter(concurrency); + } } /** * @type {String} */ - get type() { - return this[kType]; + static get extensionName() { + return "permessage-deflate"; } - }; - Object.defineProperty(Event.prototype, "target", { enumerable: true }); - Object.defineProperty(Event.prototype, "type", { enumerable: true }); - var CloseEvent = class extends Event { /** - * Create a new `CloseEvent`. + * Create an extension negotiation offer. * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {Number} [options.code=0] The status code explaining why the - * connection was closed - * @param {String} [options.reason=''] A human-readable string explaining why - * the connection was closed - * @param {Boolean} [options.wasClean=false] Indicates whether or not the - * connection was cleanly closed - */ - constructor(type, options2 = {}) { - super(type); - this[kCode] = options2.code === void 0 ? 0 : options2.code; - this[kReason] = options2.reason === void 0 ? "" : options2.reason; - this[kWasClean] = options2.wasClean === void 0 ? false : options2.wasClean; - } - /** - * @type {Number} + * @return {Object} Extension parameters + * @public */ - get code() { - return this[kCode]; + offer() { + const params = {}; + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + return params; } /** - * @type {String} + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public */ - get reason() { - return this[kReason]; + accept(configurations) { + configurations = this.normalizeParams(configurations); + this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations); + return this.params; } /** - * @type {Boolean} + * Releases all resources used by the extension. + * + * @public */ - get wasClean() { - return this[kWasClean]; + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + if (this._deflate) { + const callback = this._deflate[kCallback]; + this._deflate.close(); + this._deflate = null; + if (callback) { + callback( + new Error( + "The deflate stream was closed while data was being processed" + ) + ); + } + } } - }; - Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); - Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); - Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); - var ErrorEvent = class extends Event { /** - * Create a new `ErrorEvent`. + * Accept an extension negotiation offer. * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {*} [options.error=null] The error that generated this event - * @param {String} [options.message=''] The error message + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private */ - constructor(type, options2 = {}) { - super(type); - this[kError] = options2.error === void 0 ? null : options2.error; - this[kMessage] = options2.message === void 0 ? "" : options2.message; + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) { + return false; + } + return true; + }); + if (!accepted) { + throw new Error("None of the extension offers can be accepted"); + } + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; + } + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (typeof opts.serverMaxWindowBits === "number") { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === "number") { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) { + delete accepted.client_max_window_bits; + } + return accepted; } /** - * @type {*} + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private */ - get error() { - return this[kError]; + acceptAsClient(response) { + const params = response[0]; + if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === "number") { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } + } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } + return params; } /** - * @type {String} + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private */ - get message() { - return this[kMessage]; + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + value = value[0]; + if (key === "client_max_window_bits") { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === "server_max_window_bits") { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + params[key] = value; + }); + }); + return configurations; } - }; - Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); - Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); - var MessageEvent2 = class extends Event { /** - * Create a new `MessageEvent`. + * Decompress data. Concurrency limited. * - * @param {String} type The name of the event - * @param {Object} [options] A dictionary object that allows for setting - * attributes via object members of the same name - * @param {*} [options.data=null] The message content + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public */ - constructor(type, options2 = {}) { - super(type); - this[kData] = options2.data === void 0 ? null : options2.data; + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); } /** - * @type {*} + * Compress data. Concurrency limited. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public */ - get data() { - return this[kData]; + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); } - }; - Object.defineProperty(MessageEvent2.prototype, "data", { enumerable: true }); - var EventTarget2 = { /** - * Register an event listener. + * Decompress data. * - * @param {String} type A string representing the event type to listen for - * @param {Function} listener The listener to add - * @param {Object} [options] An options object specifies characteristics about - * the event listener - * @param {Boolean} [options.once=false] A `Boolean` indicating that the - * listener should be invoked at most once after being added. If `true`, - * the listener would be automatically removed when invoked. - * @public + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private */ - addEventListener(type, listener, options2 = {}) { - let wrapper3; - if (type === "message") { - wrapper3 = function onMessage(data, isBinary) { - const event = new MessageEvent2("message", { - data: isBinary ? data : data.toString() - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "close") { - wrapper3 = function onClose(code2, message) { - const event = new CloseEvent("close", { - code: code2, - reason: message.toString(), - wasClean: this._closeFrameReceived && this._closeFrameSent - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "error") { - wrapper3 = function onError(error2) { - const event = new ErrorEvent("error", { - error: error2, - message: error2.message - }); - event[kTarget] = this; - listener.call(this, event); - }; - } else if (type === "open") { - wrapper3 = function onOpen() { - const event = new Event("open"); - event[kTarget] = this; - listener.call(this, event); - }; - } else { - return; - } - wrapper3[kForOnEventAttribute] = !!options2[kForOnEventAttribute]; - wrapper3[kListener] = listener; - if (options2.once) { - this.once(type, wrapper3); - } else { - this.on(type, wrapper3); + _decompress(data, fin, callback) { + const endpoint = this._isServer ? "client" : "server"; + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on("error", inflateOnError); + this._inflate.on("data", inflateOnData); } - }, + this._inflate[kCallback] = callback; + this._inflate.write(data); + if (fin) this._inflate.write(TRAILER); + this._inflate.flush(() => { + const err = this._inflate[kError]; + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; + } + const data2 = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + if (this._inflate._readableState.endEmitted) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.reset(); + } + } + callback(null, data2); + }); + } /** - * Remove an event listener. + * Compress data. * - * @param {String} type A string representing the event type to remove - * @param {Function} handler The listener to remove - * @public + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private */ - removeEventListener(type, handler) { - for (const listener of this.listeners(type)) { - if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { - this.removeListener(type, listener); - break; - } + _compress(data, fin, callback) { + const endpoint = this._isServer ? "server" : "client"; + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key]; + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + this._deflate.on("data", deflateOnData); } + this._deflate[kCallback] = callback; + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + return; + } + let data2 = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + if (fin) data2 = data2.slice(0, data2.length - 4); + this._deflate[kCallback] = null; + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.reset(); + } + callback(null, data2); + }); } }; - module14.exports = { - CloseEvent, - ErrorEvent, - Event, - EventTarget: EventTarget2, - MessageEvent: MessageEvent2 - }; + module14.exports = PerMessageDeflate; + function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; + } + function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) { + this[kBuffers].push(chunk); + return; + } + this[kError] = new RangeError("Max payload size exceeded"); + this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"; + this[kError][kStatusCode] = 1009; + this.removeListener("data", inflateOnData); + this.reset(); + } + function inflateOnError(err) { + this[kPerMessageDeflate]._inflate = null; + err[kStatusCode] = 1007; + this[kCallback](err); + } } }); -var require_extension = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/extension.js"(exports2, module14) { +var require_validation = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/validation.js"(exports2, module14) { "use strict"; - var { tokenChars } = require_validation(); - function push(dest, name, elem) { - if (dest[name] === void 0) dest[name] = [elem]; - else dest[name].push(elem); + var tokenChars = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 0 - 15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // 16 - 31 + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + // 32 - 47 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // 48 - 63 + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 64 - 79 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + // 80 - 95 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + // 96 - 111 + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 1, + 0 + // 112 - 127 + ]; + function isValidStatusCode(code2) { + return code2 >= 1e3 && code2 <= 1014 && code2 !== 1004 && code2 !== 1005 && code2 !== 1006 || code2 >= 3e3 && code2 <= 4999; } - function parse62(header) { - const offers = /* @__PURE__ */ Object.create(null); - let params = /* @__PURE__ */ Object.create(null); - let mustUnescape = false; - let isEscaping = false; - let inQuotes = false; - let extensionName; - let paramName; - let start = -1; - let code2 = -1; - let end = -1; + function _isValidUTF8(buf2) { + const len = buf2.length; let i2 = 0; - for (; i2 < header.length; i2++) { - code2 = header.charCodeAt(i2); - if (extensionName === void 0) { - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - const name = header.slice(start, end); - if (code2 === 44) { - push(offers, name, params); - params = /* @__PURE__ */ Object.create(null); - } else { - extensionName = name; - } - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); + while (i2 < len) { + if ((buf2[i2] & 128) === 0) { + i2++; + } else if ((buf2[i2] & 224) === 192) { + if (i2 + 1 === len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2] & 254) === 192) { + return false; } - } else if (paramName === void 0) { - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (code2 === 32 || code2 === 9) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - push(params, header.slice(start, end), true); - if (code2 === 44) { - push(offers, extensionName, params); - params = /* @__PURE__ */ Object.create(null); - extensionName = void 0; - } - start = end = -1; - } else if (code2 === 61 && start !== -1 && end === -1) { - paramName = header.slice(start, i2); - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); + i2 += 2; + } else if ((buf2[i2] & 240) === 224) { + if (i2 + 2 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || buf2[i2] === 224 && (buf2[i2 + 1] & 224) === 128 || // Overlong + buf2[i2] === 237 && (buf2[i2 + 1] & 224) === 160) { + return false; + } + i2 += 3; + } else if ((buf2[i2] & 248) === 240) { + if (i2 + 3 >= len || (buf2[i2 + 1] & 192) !== 128 || (buf2[i2 + 2] & 192) !== 128 || (buf2[i2 + 3] & 192) !== 128 || buf2[i2] === 240 && (buf2[i2 + 1] & 240) === 128 || // Overlong + buf2[i2] === 244 && buf2[i2 + 1] > 143 || buf2[i2] > 244) { + return false; } + i2 += 4; } else { - if (isEscaping) { - if (tokenChars[code2] !== 1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (start === -1) start = i2; - else if (!mustUnescape) mustUnescape = true; - isEscaping = false; - } else if (inQuotes) { - if (tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (code2 === 34 && start !== -1) { - inQuotes = false; - end = i2; - } else if (code2 === 92) { - isEscaping = true; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } else if (code2 === 34 && header.charCodeAt(i2 - 1) === 61) { - inQuotes = true; - } else if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (start !== -1 && (code2 === 32 || code2 === 9)) { - if (end === -1) end = i2; - } else if (code2 === 59 || code2 === 44) { - if (start === -1) { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - if (end === -1) end = i2; - let value = header.slice(start, end); - if (mustUnescape) { - value = value.replace(/\\/g, ""); - mustUnescape = false; - } - push(params, paramName, value); - if (code2 === 44) { - push(offers, extensionName, params); - params = /* @__PURE__ */ Object.create(null); - extensionName = void 0; - } - paramName = void 0; - start = end = -1; - } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); - } - } - } - if (start === -1 || inQuotes || code2 === 32 || code2 === 9) { - throw new SyntaxError("Unexpected end of input"); - } - if (end === -1) end = i2; - const token = header.slice(start, end); - if (extensionName === void 0) { - push(offers, token, params); - } else { - if (paramName === void 0) { - push(params, token, true); - } else if (mustUnescape) { - push(params, paramName, token.replace(/\\/g, "")); - } else { - push(params, paramName, token); + return false; } - push(offers, extensionName, params); } - return offers; + return true; } - function format52(extensions) { - return Object.keys(extensions).map((extension) => { - let configurations = extensions[extension]; - if (!Array.isArray(configurations)) configurations = [configurations]; - return configurations.map((params) => { - return [extension].concat( - Object.keys(params).map((k) => { - let values = params[k]; - if (!Array.isArray(values)) values = [values]; - return values.map((v2) => v2 === true ? k : `${k}=${v2}`).join("; "); - }) - ).join("; "); - }).join(", "); - }).join(", "); + try { + const isValidUTF8 = __require2("utf-8-validate"); + module14.exports = { + isValidStatusCode, + isValidUTF8(buf2) { + return buf2.length < 150 ? _isValidUTF8(buf2) : isValidUTF8(buf2); + }, + tokenChars + }; + } catch (e2) { + module14.exports = { + isValidStatusCode, + isValidUTF8: _isValidUTF8, + tokenChars + }; } - module14.exports = { format: format52, parse: parse62 }; } }); -var require_websocket = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket.js"(exports2, module14) { +var require_receiver = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/receiver.js"(exports2, module14) { "use strict"; - var EventEmitter = __require2("events"); - var https = __require2("https"); - var http = __require2("http"); - var net = __require2("net"); - var tls = __require2("tls"); - var { randomBytes: randomBytes3, createHash } = __require2("crypto"); - var { Readable: Readable4 } = __require2("stream"); - var { URL: URL2 } = __require2("url"); + var { Writable } = __require2("stream"); var PerMessageDeflate = require_permessage_deflate(); - var Receiver2 = require_receiver(); - var Sender2 = require_sender(); var { BINARY_TYPES, EMPTY_BUFFER, - GUID, - kForOnEventAttribute, - kListener, kStatusCode, - kWebSocket, - NOOP + kWebSocket } = require_constants2(); - var { - EventTarget: { addEventListener: addEventListener2, removeEventListener } - } = require_event_target(); - var { format: format52, parse: parse62 } = require_extension(); - var { toBuffer } = require_buffer_util(); - var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; - var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; - var protocolVersions = [8, 13]; - var closeTimeout = 30 * 1e3; - var WebSocket3 = class _WebSocket extends EventEmitter { + var { concat: concat2, toArrayBuffer, unmask } = require_buffer_util(); + var { isValidStatusCode, isValidUTF8 } = require_validation(); + var GET_INFO = 0; + var GET_PAYLOAD_LENGTH_16 = 1; + var GET_PAYLOAD_LENGTH_64 = 2; + var GET_MASK = 3; + var GET_DATA = 4; + var INFLATING = 5; + var Receiver2 = class extends Writable { /** - * Create a new `WebSocket`. + * Creates a Receiver instance. * - * @param {(String|URL)} address The URL to which to connect - * @param {(String|String[])} [protocols] The subprotocols - * @param {Object} [options] Connection options + * @param {Object} [options] Options object + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages */ - constructor(address, protocols, options2) { + constructor(options2 = {}) { super(); - this._binaryType = BINARY_TYPES[0]; - this._closeCode = 1006; - this._closeFrameReceived = false; - this._closeFrameSent = false; - this._closeMessage = EMPTY_BUFFER; - this._closeTimer = null; - this._extensions = {}; - this._paused = false; - this._protocol = ""; - this._readyState = _WebSocket.CONNECTING; - this._receiver = null; - this._sender = null; - this._socket = null; - if (address !== null) { - this._bufferedAmount = 0; - this._isServer = false; - this._redirects = 0; - if (protocols === void 0) { - protocols = []; - } else if (!Array.isArray(protocols)) { - if (typeof protocols === "object" && protocols !== null) { - options2 = protocols; - protocols = []; - } else { - protocols = [protocols]; - } - } - initAsClient(this, address, protocols, options2); - } else { - this._isServer = true; - } + this._binaryType = options2.binaryType || BINARY_TYPES[0]; + this._extensions = options2.extensions || {}; + this._isServer = !!options2.isServer; + this._maxPayload = options2.maxPayload | 0; + this._skipUTF8Validation = !!options2.skipUTF8Validation; + this[kWebSocket] = void 0; + this._bufferedBytes = 0; + this._buffers = []; + this._compressed = false; + this._payloadLength = 0; + this._mask = void 0; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragments = []; + this._state = GET_INFO; + this._loop = false; } /** - * This deviates from the WHATWG interface since ws doesn't support the - * required default "blob" type (instead we define a custom "nodebuffer" - * type). + * Implements `Writable.prototype._write()`. * - * @type {String} - */ - get binaryType() { - return this._binaryType; - } - set binaryType(type) { - if (!BINARY_TYPES.includes(type)) return; - this._binaryType = type; - if (this._receiver) this._receiver._binaryType = type; - } - /** - * @type {Number} - */ - get bufferedAmount() { - if (!this._socket) return this._bufferedAmount; - return this._socket._writableState.length + this._sender._bufferedBytes; - } - /** - * @type {String} - */ - get extensions() { - return Object.keys(this._extensions).join(); - } - /** - * @type {Boolean} + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + * @private */ - get isPaused() { - return this._paused; + _write(chunk, encoding, cb) { + if (this._opcode === 8 && this._state == GET_INFO) return cb(); + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); } /** - * @type {Function} + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private */ - /* istanbul ignore next */ - get onclose() { - return null; + consume(n) { + this._bufferedBytes -= n; + if (n === this._buffers[0].length) return this._buffers.shift(); + if (n < this._buffers[0].length) { + const buf2 = this._buffers[0]; + this._buffers[0] = buf2.slice(n); + return buf2.slice(0, n); + } + const dst = Buffer.allocUnsafe(n); + do { + const buf2 = this._buffers[0]; + const offset = dst.length - n; + if (n >= buf2.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf2.buffer, buf2.byteOffset, n), offset); + this._buffers[0] = buf2.slice(n); + } + n -= buf2.length; + } while (n > 0); + return dst; } /** - * @type {Function} + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private */ - /* istanbul ignore next */ - get onerror() { - return null; + startLoop(cb) { + let err; + this._loop = true; + do { + switch (this._state) { + case GET_INFO: + err = this.getInfo(); + break; + case GET_PAYLOAD_LENGTH_16: + err = this.getPayloadLength16(); + break; + case GET_PAYLOAD_LENGTH_64: + err = this.getPayloadLength64(); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + err = this.getData(cb); + break; + default: + this._loop = false; + return; + } + } while (this._loop); + cb(err); } /** - * @type {Function} + * Reads the first two bytes of a frame. + * + * @return {(RangeError|undefined)} A possible error + * @private */ - /* istanbul ignore next */ - get onopen() { - return null; + getInfo() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + const buf2 = this.consume(2); + if ((buf2[0] & 48) !== 0) { + this._loop = false; + return error2( + RangeError, + "RSV2 and RSV3 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_2_3" + ); + } + const compressed = (buf2[0] & 64) === 64; + if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + this._fin = (buf2[0] & 128) === 128; + this._opcode = buf2[0] & 15; + this._payloadLength = buf2[1] & 127; + if (this._opcode === 0) { + if (compressed) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + if (!this._fragmented) { + this._loop = false; + return error2( + RangeError, + "invalid opcode 0", + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + this._opcode = this._fragmented; + } else if (this._opcode === 1 || this._opcode === 2) { + if (this._fragmented) { + this._loop = false; + return error2( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + this._compressed = compressed; + } else if (this._opcode > 7 && this._opcode < 11) { + if (!this._fin) { + this._loop = false; + return error2( + RangeError, + "FIN must be set", + true, + 1002, + "WS_ERR_EXPECTED_FIN" + ); + } + if (compressed) { + this._loop = false; + return error2( + RangeError, + "RSV1 must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_RSV_1" + ); + } + if (this._payloadLength > 125) { + this._loop = false; + return error2( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + } + } else { + this._loop = false; + return error2( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + "WS_ERR_INVALID_OPCODE" + ); + } + if (!this._fin && !this._fragmented) this._fragmented = this._opcode; + this._masked = (buf2[1] & 128) === 128; + if (this._isServer) { + if (!this._masked) { + this._loop = false; + return error2( + RangeError, + "MASK must be set", + true, + 1002, + "WS_ERR_EXPECTED_MASK" + ); + } + } else if (this._masked) { + this._loop = false; + return error2( + RangeError, + "MASK must be clear", + true, + 1002, + "WS_ERR_UNEXPECTED_MASK" + ); + } + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; + else return this.haveLength(); } /** - * @type {Function} + * Gets extended payload length (7+16). + * + * @return {(RangeError|undefined)} A possible error + * @private */ - /* istanbul ignore next */ - get onmessage() { - return null; + getPayloadLength16() { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + this._payloadLength = this.consume(2).readUInt16BE(0); + return this.haveLength(); } /** - * @type {String} + * Gets extended payload length (7+64). + * + * @return {(RangeError|undefined)} A possible error + * @private */ - get protocol() { - return this._protocol; + getPayloadLength64() { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + const buf2 = this.consume(8); + const num = buf2.readUInt32BE(0); + if (num > Math.pow(2, 53 - 32) - 1) { + this._loop = false; + return error2( + RangeError, + "Unsupported WebSocket frame: payload length > 2^53 - 1", + false, + 1009, + "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH" + ); + } + this._payloadLength = num * Math.pow(2, 32) + buf2.readUInt32BE(4); + return this.haveLength(); } /** - * @type {Number} + * Payload length has been read. + * + * @return {(RangeError|undefined)} A possible error + * @private */ - get readyState() { - return this._readyState; + haveLength() { + if (this._payloadLength && this._opcode < 8) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + this._loop = false; + return error2( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ); + } + } + if (this._masked) this._state = GET_MASK; + else this._state = GET_DATA; } /** - * @type {String} + * Reads mask bytes. + * + * @private */ - get url() { - return this._url; + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + this._mask = this.consume(4); + this._state = GET_DATA; } /** - * Set up the socket and the internal resources. + * Reads data bytes. * - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Object} options Options object - * @param {Function} [options.generateMask] The function used to generate the - * masking key - * @param {Number} [options.maxPayload=0] The maximum allowed message size - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages + * @param {Function} cb Callback + * @return {(Error|RangeError|undefined)} A possible error * @private */ - setSocket(socket, head, options2) { - const receiver = new Receiver2({ - binaryType: this.binaryType, - extensions: this._extensions, - isServer: this._isServer, - maxPayload: options2.maxPayload, - skipUTF8Validation: options2.skipUTF8Validation - }); - this._sender = new Sender2(socket, this._extensions, options2.generateMask); - this._receiver = receiver; - this._socket = socket; - receiver[kWebSocket] = this; - socket[kWebSocket] = this; - receiver.on("conclude", receiverOnConclude); - receiver.on("drain", receiverOnDrain); - receiver.on("error", receiverOnError); - receiver.on("message", receiverOnMessage); - receiver.on("ping", receiverOnPing); - receiver.on("pong", receiverOnPong); - socket.setTimeout(0); - socket.setNoDelay(); - if (head.length > 0) socket.unshift(head); - socket.on("close", socketOnClose); - socket.on("data", socketOnData); - socket.on("end", socketOnEnd); - socket.on("error", socketOnError); - this._readyState = _WebSocket.OPEN; - this.emit("open"); + getData(cb) { + let data = EMPTY_BUFFER; + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; + } + data = this.consume(this._payloadLength); + if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) { + unmask(data, this._mask); + } + } + if (this._opcode > 7) return this.controlMessage(data); + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + if (data.length) { + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + return this.dataMessage(); } /** - * Emit the `'close'` event. + * Decompresses data. * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback * @private */ - emitClose() { - if (!this._socket) { - this._readyState = _WebSocket.CLOSED; - this.emit("close", this._closeCode, this._closeMessage); - return; - } - if (this._extensions[PerMessageDeflate.extensionName]) { - this._extensions[PerMessageDeflate.extensionName].cleanup(); - } - this._receiver.removeAllListeners(); - this._readyState = _WebSocket.CLOSED; - this.emit("close", this._closeCode, this._closeMessage); + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + perMessageDeflate.decompress(data, this._fin, (err, buf2) => { + if (err) return cb(err); + if (buf2.length) { + this._messageLength += buf2.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + return cb( + error2( + RangeError, + "Max payload size exceeded", + false, + 1009, + "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH" + ) + ); + } + this._fragments.push(buf2); + } + const er = this.dataMessage(); + if (er) return cb(er); + this.startLoop(cb); + }); } /** - * Start a closing handshake. - * - * +----------+ +-----------+ +----------+ - * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - - * | +----------+ +-----------+ +----------+ | - * +----------+ +-----------+ | - * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING - * +----------+ +-----------+ | - * | | | +---+ | - * +------------------------+-->|fin| - - - - - * | +---+ | +---+ - * - - - - -|fin|<---------------------+ - * +---+ + * Handles a data message. * - * @param {Number} [code] Status code explaining why the connection is closing - * @param {(String|Buffer)} [data] The reason why the connection is - * closing - * @public + * @return {(Error|undefined)} A possible error + * @private */ - close(code2, data) { - if (this.readyState === _WebSocket.CLOSED) return; - if (this.readyState === _WebSocket.CONNECTING) { - const msg = "WebSocket was closed before the connection was established"; - return abortHandshake(this, this._req, msg); - } - if (this.readyState === _WebSocket.CLOSING) { - if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { - this._socket.end(); + dataMessage() { + if (this._fin) { + const messageLength = this._messageLength; + const fragments = this._fragments; + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._fragments = []; + if (this._opcode === 2) { + let data; + if (this._binaryType === "nodebuffer") { + data = concat2(fragments, messageLength); + } else if (this._binaryType === "arraybuffer") { + data = toArrayBuffer(concat2(fragments, messageLength)); + } else { + data = fragments; + } + this.emit("message", data, true); + } else { + const buf2 = concat2(fragments, messageLength); + if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { + this._loop = false; + return error2( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("message", buf2, false); } - return; } - this._readyState = _WebSocket.CLOSING; - this._sender.close(code2, data, !this._isServer, (err) => { - if (err) return; - this._closeFrameSent = true; - if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { - this._socket.end(); - } - }); - this._closeTimer = setTimeout( - this._socket.destroy.bind(this._socket), - closeTimeout - ); + this._state = GET_INFO; } /** - * Pause the socket. + * Handles a control message. * - * @public + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private */ - pause() { - if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { - return; + controlMessage(data) { + if (this._opcode === 8) { + this._loop = false; + if (data.length === 0) { + this.emit("conclude", 1005, EMPTY_BUFFER); + this.end(); + } else if (data.length === 1) { + return error2( + RangeError, + "invalid payload length 1", + true, + 1002, + "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH" + ); + } else { + const code2 = data.readUInt16BE(0); + if (!isValidStatusCode(code2)) { + return error2( + RangeError, + `invalid status code ${code2}`, + true, + 1002, + "WS_ERR_INVALID_CLOSE_CODE" + ); + } + const buf2 = data.slice(2); + if (!this._skipUTF8Validation && !isValidUTF8(buf2)) { + return error2( + Error, + "invalid UTF-8 sequence", + true, + 1007, + "WS_ERR_INVALID_UTF8" + ); + } + this.emit("conclude", code2, buf2); + this.end(); + } + } else if (this._opcode === 9) { + this.emit("ping", data); + } else { + this.emit("pong", data); } - this._paused = true; - this._socket.pause(); + this._state = GET_INFO; } + }; + module14.exports = Receiver2; + function error2(ErrorCtor, message, prefix, statusCode, errorCode) { + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + Error.captureStackTrace(err, error2); + err.code = errorCode; + err[kStatusCode] = statusCode; + return err; + } + } +}); +var require_sender = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/sender.js"(exports2, module14) { + "use strict"; + var net = __require2("net"); + var tls = __require2("tls"); + var { randomFillSync } = __require2("crypto"); + var PerMessageDeflate = require_permessage_deflate(); + var { EMPTY_BUFFER } = require_constants2(); + var { isValidStatusCode } = require_validation(); + var { mask: applyMask, toBuffer } = require_buffer_util(); + var kByteLength = Symbol("kByteLength"); + var maskBuffer = Buffer.alloc(4); + var Sender2 = class _Sender { /** - * Send a ping. + * Creates a Sender instance. * - * @param {*} [data] The data to send - * @param {Boolean} [mask] Indicates whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when the ping is sent - * @public + * @param {(net.Socket|tls.Socket)} socket The connection socket + * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key */ - ping(data, mask, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); - } - if (typeof data === "function") { - cb = data; - data = mask = void 0; - } else if (typeof mask === "function") { - cb = mask; - mask = void 0; - } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; + constructor(socket, extensions, generateMask) { + this._extensions = extensions || {}; + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); } - if (mask === void 0) mask = !this._isServer; - this._sender.ping(data || EMPTY_BUFFER, mask, cb); + this._socket = socket; + this._firstFragment = true; + this._compress = false; + this._bufferedBytes = 0; + this._deflating = false; + this._queue = []; } /** - * Send a pong. + * Frames a piece of data according to the HyBi WebSocket protocol. * - * @param {*} [data] The data to send - * @param {Boolean} [mask] Indicates whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when the pong is sent + * @param {(Buffer|String)} data The data to frame + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @return {(Buffer|String)[]} The framed data * @public */ - pong(data, mask, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); + static frame(data, options2) { + let mask; + let merge3 = false; + let offset = 2; + let skipMasking = false; + if (options2.mask) { + mask = options2.maskBuffer || maskBuffer; + if (options2.generateMask) { + options2.generateMask(mask); + } else { + randomFillSync(mask, 0, 4); + } + skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; + offset = 6; } - if (typeof data === "function") { - cb = data; - data = mask = void 0; - } else if (typeof mask === "function") { - cb = mask; - mask = void 0; + let dataLength; + if (typeof data === "string") { + if ((!options2.mask || skipMasking) && options2[kByteLength] !== void 0) { + dataLength = options2[kByteLength]; + } else { + data = Buffer.from(data); + dataLength = data.length; + } + } else { + dataLength = data.length; + merge3 = options2.mask && options2.readOnly && !skipMasking; } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; + let payloadLength = dataLength; + if (dataLength >= 65536) { + offset += 8; + payloadLength = 127; + } else if (dataLength > 125) { + offset += 2; + payloadLength = 126; } - if (mask === void 0) mask = !this._isServer; - this._sender.pong(data || EMPTY_BUFFER, mask, cb); + const target = Buffer.allocUnsafe(merge3 ? dataLength + offset : offset); + target[0] = options2.fin ? options2.opcode | 128 : options2.opcode; + if (options2.rsv1) target[0] |= 64; + target[1] = payloadLength; + if (payloadLength === 126) { + target.writeUInt16BE(dataLength, 2); + } else if (payloadLength === 127) { + target[2] = target[3] = 0; + target.writeUIntBE(dataLength, 4, 6); + } + if (!options2.mask) return [target, data]; + target[1] |= 128; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + if (skipMasking) return [target, data]; + if (merge3) { + applyMask(data, mask, target, offset, dataLength); + return [target]; + } + applyMask(data, mask, data, 0, dataLength); + return [target, data]; } /** - * Resume the socket. + * Sends a close message to the other peer. * + * @param {Number} [code] The status code component of the body + * @param {(String|Buffer)} [data] The message component of the body + * @param {Boolean} [mask=false] Specifies whether or not to mask the message + * @param {Function} [cb] Callback * @public */ - resume() { - if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { - return; + close(code2, data, mask, cb) { + let buf2; + if (code2 === void 0) { + buf2 = EMPTY_BUFFER; + } else if (typeof code2 !== "number" || !isValidStatusCode(code2)) { + throw new TypeError("First argument must be a valid error code number"); + } else if (data === void 0 || !data.length) { + buf2 = Buffer.allocUnsafe(2); + buf2.writeUInt16BE(code2, 0); + } else { + const length2 = Buffer.byteLength(data); + if (length2 > 123) { + throw new RangeError("The message must not be greater than 123 bytes"); + } + buf2 = Buffer.allocUnsafe(2 + length2); + buf2.writeUInt16BE(code2, 0); + if (typeof data === "string") { + buf2.write(data, 2); + } else { + buf2.set(data, 2); + } + } + const options2 = { + [kByteLength]: buf2.length, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 8, + readOnly: false, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, buf2, false, options2, cb]); + } else { + this.sendFrame(_Sender.frame(buf2, options2), cb); } - this._paused = false; - if (!this._receiver._writableState.needDrain) this._socket.resume(); } /** - * Send a data message. + * Sends a ping message to the other peer. * * @param {*} data The message to send - * @param {Object} [options] Options object - * @param {Boolean} [options.binary] Specifies whether `data` is binary or - * text - * @param {Boolean} [options.compress] Specifies whether or not to compress - * `data` - * @param {Boolean} [options.fin=true] Specifies whether the fragment is the - * last one - * @param {Boolean} [options.mask] Specifies whether or not to mask `data` - * @param {Function} [cb] Callback which is executed when data is written out + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback * @public */ - send(data, options2, cb) { - if (this.readyState === _WebSocket.CONNECTING) { - throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); - } - if (typeof options2 === "function") { - cb = options2; - options2 = {}; + ping(data, mask, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - if (typeof data === "number") data = data.toString(); - if (this.readyState !== _WebSocket.OPEN) { - sendAfterClose(this, data, cb); - return; + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); } - const opts = { - binary: typeof data !== "string", - mask: !this._isServer, - compress: true, + const options2 = { + [kByteLength]: byteLength, fin: true, - ...options2 + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 9, + readOnly, + rsv1: false }; - if (!this._extensions[PerMessageDeflate.extensionName]) { - opts.compress = false; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options2, cb]); + } else { + this.sendFrame(_Sender.frame(data, options2), cb); } - this._sender.send(data || EMPTY_BUFFER, opts, cb); } /** - * Forcibly close the connection. + * Sends a pong message to the other peer. * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback * @public */ - terminate() { - if (this.readyState === _WebSocket.CLOSED) return; - if (this.readyState === _WebSocket.CONNECTING) { - const msg = "WebSocket was closed before the connection was established"; - return abortHandshake(this, this._req, msg); + pong(data, mask, cb) { + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - if (this._socket) { - this._readyState = _WebSocket.CLOSING; - this._socket.destroy(); + if (byteLength > 125) { + throw new RangeError("The data size must not be greater than 125 bytes"); } - } - }; - Object.defineProperty(WebSocket3, "CONNECTING", { - enumerable: true, - value: readyStates.indexOf("CONNECTING") - }); - Object.defineProperty(WebSocket3.prototype, "CONNECTING", { - enumerable: true, - value: readyStates.indexOf("CONNECTING") - }); - Object.defineProperty(WebSocket3, "OPEN", { - enumerable: true, - value: readyStates.indexOf("OPEN") - }); - Object.defineProperty(WebSocket3.prototype, "OPEN", { - enumerable: true, - value: readyStates.indexOf("OPEN") - }); - Object.defineProperty(WebSocket3, "CLOSING", { - enumerable: true, - value: readyStates.indexOf("CLOSING") - }); - Object.defineProperty(WebSocket3.prototype, "CLOSING", { - enumerable: true, - value: readyStates.indexOf("CLOSING") - }); - Object.defineProperty(WebSocket3, "CLOSED", { - enumerable: true, - value: readyStates.indexOf("CLOSED") - }); - Object.defineProperty(WebSocket3.prototype, "CLOSED", { - enumerable: true, - value: readyStates.indexOf("CLOSED") - }); - [ - "binaryType", - "bufferedAmount", - "extensions", - "isPaused", - "protocol", - "readyState", - "url" - ].forEach((property) => { - Object.defineProperty(WebSocket3.prototype, property, { enumerable: true }); - }); - ["open", "error", "close", "message"].forEach((method) => { - Object.defineProperty(WebSocket3.prototype, `on${method}`, { - enumerable: true, - get() { - for (const listener of this.listeners(method)) { - if (listener[kForOnEventAttribute]) return listener[kListener]; - } - return null; - }, - set(handler) { - for (const listener of this.listeners(method)) { - if (listener[kForOnEventAttribute]) { - this.removeListener(method, listener); - break; - } - } - if (typeof handler !== "function") return; - this.addEventListener(method, handler, { - [kForOnEventAttribute]: true - }); - } - }); - }); - WebSocket3.prototype.addEventListener = addEventListener2; - WebSocket3.prototype.removeEventListener = removeEventListener; - module14.exports = WebSocket3; - function initAsClient(websocket, address, protocols, options2) { - const opts = { - protocolVersion: protocolVersions[1], - maxPayload: 100 * 1024 * 1024, - skipUTF8Validation: false, - perMessageDeflate: true, - followRedirects: false, - maxRedirects: 10, - ...options2, - createConnection: void 0, - socketPath: void 0, - hostname: void 0, - protocol: void 0, - timeout: void 0, - method: void 0, - host: void 0, - path: void 0, - port: void 0 - }; - if (!protocolVersions.includes(opts.protocolVersion)) { - throw new RangeError( - `Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` - ); - } - let parsedUrl; - if (address instanceof URL2) { - parsedUrl = address; - websocket._url = address.href; - } else { - try { - parsedUrl = new URL2(address); - } catch (e2) { - throw new SyntaxError(`Invalid URL: ${address}`); - } - websocket._url = address; - } - const isSecure = parsedUrl.protocol === "wss:"; - const isUnixSocket = parsedUrl.protocol === "ws+unix:"; - let invalidURLMessage; - if (parsedUrl.protocol !== "ws:" && !isSecure && !isUnixSocket) { - invalidURLMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; - } else if (isUnixSocket && !parsedUrl.pathname) { - invalidURLMessage = "The URL's pathname is empty"; - } else if (parsedUrl.hash) { - invalidURLMessage = "The URL contains a fragment identifier"; - } - if (invalidURLMessage) { - const err = new SyntaxError(invalidURLMessage); - if (websocket._redirects === 0) { - throw err; + const options2 = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 10, + readOnly, + rsv1: false + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options2, cb]); } else { - emitErrorAndClose(websocket, err); - return; - } - } - const defaultPort = isSecure ? 443 : 80; - const key = randomBytes3(16).toString("base64"); - const get2 = isSecure ? https.get : http.get; - const protocolSet = /* @__PURE__ */ new Set(); - let perMessageDeflate; - opts.createConnection = isSecure ? tlsConnect : netConnect; - opts.defaultPort = opts.defaultPort || defaultPort; - opts.port = parsedUrl.port || defaultPort; - opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; - opts.headers = { - "Sec-WebSocket-Version": opts.protocolVersion, - "Sec-WebSocket-Key": key, - Connection: "Upgrade", - Upgrade: "websocket", - ...opts.headers - }; - opts.path = parsedUrl.pathname + parsedUrl.search; - opts.timeout = opts.handshakeTimeout; - if (opts.perMessageDeflate) { - perMessageDeflate = new PerMessageDeflate( - opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, - false, - opts.maxPayload - ); - opts.headers["Sec-WebSocket-Extensions"] = format52({ - [PerMessageDeflate.extensionName]: perMessageDeflate.offer() - }); - } - if (protocols.length) { - for (const protocol of protocols) { - if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { - throw new SyntaxError( - "An invalid or duplicated subprotocol was specified" - ); - } - protocolSet.add(protocol); + this.sendFrame(_Sender.frame(data, options2), cb); } - opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); } - if (opts.origin) { - if (opts.protocolVersion < 13) { - opts.headers["Sec-WebSocket-Origin"] = opts.origin; + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} [options.binary=false] Specifies whether `data` is binary + * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` + * @param {Boolean} [options.fin=false] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Function} [cb] Callback + * @public + */ + send(data, options2, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + let opcode = options2.binary ? 2 : 1; + let rsv1 = options2.compress; + let byteLength; + let readOnly; + if (typeof data === "string") { + byteLength = Buffer.byteLength(data); + readOnly = false; } else { - opts.headers.Origin = opts.origin; + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; } - } - if (parsedUrl.username || parsedUrl.password) { - opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; - } - if (isUnixSocket) { - const parts = opts.path.split(":"); - opts.socketPath = parts[0]; - opts.path = parts[1]; - } - if (opts.followRedirects) { - if (websocket._redirects === 0) { - websocket._originalHost = parsedUrl.host; - const headers = options2 && options2.headers; - options2 = { ...options2, headers: {} }; - if (headers) { - for (const [key2, value] of Object.entries(headers)) { - options2.headers[key2.toLowerCase()] = value; - } + if (this._firstFragment) { + this._firstFragment = false; + if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) { + rsv1 = byteLength >= perMessageDeflate._threshold; } - } else if (parsedUrl.host !== websocket._originalHost) { - delete opts.headers.authorization; - delete opts.headers.cookie; - delete opts.headers.host; - opts.auth = void 0; - } - if (opts.auth && !options2.headers.authorization) { - options2.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; } - } - let req = websocket._req = get2(opts); - if (opts.timeout) { - req.on("timeout", () => { - abortHandshake(websocket, req, "Opening handshake has timed out"); - }); - } - req.on("error", (err) => { - if (req === null || req.aborted) return; - req = websocket._req = null; - emitErrorAndClose(websocket, err); - }); - req.on("response", (res) => { - const location = res.headers.location; - const statusCode = res.statusCode; - if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { - if (++websocket._redirects > opts.maxRedirects) { - abortHandshake(websocket, req, "Maximum redirects exceeded"); - return; - } - req.abort(); - let addr; - try { - addr = new URL2(location, address); - } catch (e2) { - const err = new SyntaxError(`Invalid URL: ${location}`); - emitErrorAndClose(websocket, err); - return; + if (options2.fin) this._firstFragment = true; + if (perMessageDeflate) { + const opts = { + [kByteLength]: byteLength, + fin: options2.fin, + generateMask: this._generateMask, + mask: options2.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1 + }; + if (this._deflating) { + this.enqueue([this.dispatch, data, this._compress, opts, cb]); + } else { + this.dispatch(data, this._compress, opts, cb); } - initAsClient(websocket, addr, protocols, options2); - } else if (!websocket.emit("unexpected-response", req, res)) { - abortHandshake( - websocket, - req, - `Unexpected server response: ${res.statusCode}` + } else { + this.sendFrame( + _Sender.frame(data, { + [kByteLength]: byteLength, + fin: options2.fin, + generateMask: this._generateMask, + mask: options2.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1: false + }), + cb ); } - }); - req.on("upgrade", (res, socket, head) => { - websocket.emit("upgrade", res); - if (websocket.readyState !== WebSocket3.CONNECTING) return; - req = websocket._req = null; - const digest = createHash("sha1").update(key + GUID).digest("base64"); - if (res.headers["sec-websocket-accept"] !== digest) { - abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header"); - return; - } - const serverProt = res.headers["sec-websocket-protocol"]; - let protError; - if (serverProt !== void 0) { - if (!protocolSet.size) { - protError = "Server sent a subprotocol but none was requested"; - } else if (!protocolSet.has(serverProt)) { - protError = "Server sent an invalid subprotocol"; - } - } else if (protocolSet.size) { - protError = "Server sent no subprotocol"; - } - if (protError) { - abortHandshake(websocket, socket, protError); + } + /** + * Dispatches a message. + * + * @param {(Buffer|String)} data The message to send + * @param {Boolean} [compress=false] Specifies whether or not to compress + * `data` + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + dispatch(data, compress, options2, cb) { + if (!compress) { + this.sendFrame(_Sender.frame(data, options2), cb); return; } - if (serverProt) websocket._protocol = serverProt; - const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; - if (secWebSocketExtensions !== void 0) { - if (!perMessageDeflate) { - const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; - abortHandshake(websocket, socket, message); - return; - } - let extensions; - try { - extensions = parse62(secWebSocketExtensions); - } catch (err) { - const message = "Invalid Sec-WebSocket-Extensions header"; - abortHandshake(websocket, socket, message); - return; - } - const extensionNames = Object.keys(extensions); - if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) { - const message = "Server indicated an extension that was not requested"; - abortHandshake(websocket, socket, message); - return; - } - try { - perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); - } catch (err) { - const message = "Invalid Sec-WebSocket-Extensions header"; - abortHandshake(websocket, socket, message); + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + this._bufferedBytes += options2[kByteLength]; + this._deflating = true; + perMessageDeflate.compress(data, options2.fin, (_, buf2) => { + if (this._socket.destroyed) { + const err = new Error( + "The socket was closed while data was being compressed" + ); + if (typeof cb === "function") cb(err); + for (let i2 = 0; i2 < this._queue.length; i2++) { + const params = this._queue[i2]; + const callback = params[params.length - 1]; + if (typeof callback === "function") callback(err); + } return; } - websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; - } - websocket.setSocket(socket, head, { - generateMask: opts.generateMask, - maxPayload: opts.maxPayload, - skipUTF8Validation: opts.skipUTF8Validation + this._bufferedBytes -= options2[kByteLength]; + this._deflating = false; + options2.readOnly = false; + this.sendFrame(_Sender.frame(buf2, options2), cb); + this.dequeue(); }); - }); - } - function emitErrorAndClose(websocket, err) { - websocket._readyState = WebSocket3.CLOSING; - websocket.emit("error", err); - websocket.emitClose(); - } - function netConnect(options2) { - options2.path = options2.socketPath; - return net.connect(options2); - } - function tlsConnect(options2) { - options2.path = void 0; - if (!options2.servername && options2.servername !== "") { - options2.servername = net.isIP(options2.host) ? "" : options2.host; } - return tls.connect(options2); - } - function abortHandshake(websocket, stream, message) { - websocket._readyState = WebSocket3.CLOSING; - const err = new Error(message); - Error.captureStackTrace(err, abortHandshake); - if (stream.setHeader) { - stream.abort(); - if (stream.socket && !stream.socket.destroyed) { - stream.socket.destroy(); + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (!this._deflating && this._queue.length) { + const params = this._queue.shift(); + this._bufferedBytes -= params[3][kByteLength]; + Reflect.apply(params[0], this, params.slice(1)); } - stream.once("abort", websocket.emitClose.bind(websocket)); - websocket.emit("error", err); - } else { - stream.destroy(err); - stream.once("error", websocket.emit.bind(websocket, "error")); - stream.once("close", websocket.emitClose.bind(websocket)); - } - } - function sendAfterClose(websocket, data, cb) { - if (data) { - const length2 = toBuffer(data).length; - if (websocket._socket) websocket._sender._bufferedBytes += length2; - else websocket._bufferedAmount += length2; } - if (cb) { - const err = new Error( - `WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})` - ); - cb(err); + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[3][kByteLength]; + this._queue.push(params); } - } - function receiverOnConclude(code2, reason) { - const websocket = this[kWebSocket]; - websocket._closeFrameReceived = true; - websocket._closeMessage = reason; - websocket._closeCode = code2; - if (websocket._socket[kWebSocket] === void 0) return; - websocket._socket.removeListener("data", socketOnData); - process.nextTick(resume, websocket._socket); - if (code2 === 1005) websocket.close(); - else websocket.close(code2, reason); - } - function receiverOnDrain() { - const websocket = this[kWebSocket]; - if (!websocket.isPaused) websocket._socket.resume(); - } - function receiverOnError(err) { - const websocket = this[kWebSocket]; - if (websocket._socket[kWebSocket] !== void 0) { - websocket._socket.removeListener("data", socketOnData); - process.nextTick(resume, websocket._socket); - websocket.close(err[kStatusCode]); + /** + * Sends a frame. + * + * @param {Buffer[]} list The frame to send + * @param {Function} [cb] Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); + } } - websocket.emit("error", err); - } - function receiverOnFinish() { - this[kWebSocket].emitClose(); - } - function receiverOnMessage(data, isBinary) { - this[kWebSocket].emit("message", data, isBinary); - } - function receiverOnPing(data) { - const websocket = this[kWebSocket]; - websocket.pong(data, !websocket._isServer, NOOP); - websocket.emit("ping", data); - } - function receiverOnPong(data) { - this[kWebSocket].emit("pong", data); - } - function resume(stream) { - stream.resume(); - } - function socketOnClose() { - const websocket = this[kWebSocket]; - this.removeListener("close", socketOnClose); - this.removeListener("data", socketOnData); - this.removeListener("end", socketOnEnd); - websocket._readyState = WebSocket3.CLOSING; - let chunk; - if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && (chunk = websocket._socket.read()) !== null) { - websocket._receiver.write(chunk); + }; + module14.exports = Sender2; + } +}); +var require_event_target = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/event-target.js"(exports2, module14) { + "use strict"; + var { kForOnEventAttribute, kListener } = require_constants2(); + var kCode = Symbol("kCode"); + var kData = Symbol("kData"); + var kError = Symbol("kError"); + var kMessage = Symbol("kMessage"); + var kReason = Symbol("kReason"); + var kTarget = Symbol("kTarget"); + var kType = Symbol("kType"); + var kWasClean = Symbol("kWasClean"); + var Event = class { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @throws {TypeError} If the `type` argument is not specified + */ + constructor(type) { + this[kTarget] = null; + this[kType] = type; } - websocket._receiver.end(); - this[kWebSocket] = void 0; - clearTimeout(websocket._closeTimer); - if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) { - websocket.emitClose(); - } else { - websocket._receiver.on("error", receiverOnFinish); - websocket._receiver.on("finish", receiverOnFinish); + /** + * @type {*} + */ + get target() { + return this[kTarget]; } - } - function socketOnData(chunk) { - if (!this[kWebSocket]._receiver.write(chunk)) { - this.pause(); + /** + * @type {String} + */ + get type() { + return this[kType]; } - } - function socketOnEnd() { - const websocket = this[kWebSocket]; - websocket._readyState = WebSocket3.CLOSING; - websocket._receiver.end(); - this.end(); - } - function socketOnError() { - const websocket = this[kWebSocket]; - this.removeListener("error", socketOnError); - this.on("error", NOOP); - if (websocket) { - websocket._readyState = WebSocket3.CLOSING; - this.destroy(); + }; + Object.defineProperty(Event.prototype, "target", { enumerable: true }); + Object.defineProperty(Event.prototype, "type", { enumerable: true }); + var CloseEvent = class extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options2 = {}) { + super(type); + this[kCode] = options2.code === void 0 ? 0 : options2.code; + this[kReason] = options2.reason === void 0 ? "" : options2.reason; + this[kWasClean] = options2.wasClean === void 0 ? false : options2.wasClean; } - } + /** + * @type {Number} + */ + get code() { + return this[kCode]; + } + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; + } + }; + Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true }); + Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true }); + Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true }); + var ErrorEvent = class extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message + */ + constructor(type, options2 = {}) { + super(type); + this[kError] = options2.error === void 0 ? null : options2.error; + this[kMessage] = options2.message === void 0 ? "" : options2.message; + } + /** + * @type {*} + */ + get error() { + return this[kError]; + } + /** + * @type {String} + */ + get message() { + return this[kMessage]; + } + }; + Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true }); + Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true }); + var MessageEvent2 = class extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content + */ + constructor(type, options2 = {}) { + super(type); + this[kData] = options2.data === void 0 ? null : options2.data; + } + /** + * @type {*} + */ + get data() { + return this[kData]; + } + }; + Object.defineProperty(MessageEvent2.prototype, "data", { enumerable: true }); + var EventTarget2 = { + /** + * Register an event listener. + * + * @param {String} type A string representing the event type to listen for + * @param {Function} listener The listener to add + * @param {Object} [options] An options object specifies characteristics about + * the event listener + * @param {Boolean} [options.once=false] A `Boolean` indicating that the + * listener should be invoked at most once after being added. If `true`, + * the listener would be automatically removed when invoked. + * @public + */ + addEventListener(type, listener, options2 = {}) { + let wrapper3; + if (type === "message") { + wrapper3 = function onMessage(data, isBinary) { + const event = new MessageEvent2("message", { + data: isBinary ? data : data.toString() + }); + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === "close") { + wrapper3 = function onClose(code2, message) { + const event = new CloseEvent("close", { + code: code2, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent + }); + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === "error") { + wrapper3 = function onError(error2) { + const event = new ErrorEvent("error", { + error: error2, + message: error2.message + }); + event[kTarget] = this; + listener.call(this, event); + }; + } else if (type === "open") { + wrapper3 = function onOpen() { + const event = new Event("open"); + event[kTarget] = this; + listener.call(this, event); + }; + } else { + return; + } + wrapper3[kForOnEventAttribute] = !!options2[kForOnEventAttribute]; + wrapper3[kListener] = listener; + if (options2.once) { + this.once(type, wrapper3); + } else { + this.on(type, wrapper3); + } + }, + /** + * Remove an event listener. + * + * @param {String} type A string representing the event type to remove + * @param {Function} handler The listener to remove + * @public + */ + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { + this.removeListener(type, listener); + break; + } + } + } + }; + module14.exports = { + CloseEvent, + ErrorEvent, + Event, + EventTarget: EventTarget2, + MessageEvent: MessageEvent2 + }; } }); -var require_subprotocol = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/subprotocol.js"(exports2, module14) { +var require_extension = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/extension.js"(exports2, module14) { "use strict"; var { tokenChars } = require_validation(); + function push(dest, name, elem) { + if (dest[name] === void 0) dest[name] = [elem]; + else dest[name].push(elem); + } function parse62(header) { - const protocols = /* @__PURE__ */ new Set(); + const offers = /* @__PURE__ */ Object.create(null); + let params = /* @__PURE__ */ Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; let start = -1; + let code2 = -1; let end = -1; let i2 = 0; - for (i2; i2 < header.length; i2++) { - const code2 = header.charCodeAt(i2); - if (end === -1 && tokenChars[code2] === 1) { - if (start === -1) start = i2; - } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { - if (end === -1 && start !== -1) end = i2; - } else if (code2 === 44) { - if (start === -1) { + for (; i2 < header.length; i2++) { + code2 = header.charCodeAt(i2); + if (extensionName === void 0) { + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (end === -1) end = i2; + const name = header.slice(start, end); + if (code2 === 44) { + push(offers, name, params); + params = /* @__PURE__ */ Object.create(null); + } else { + extensionName = name; + } + start = end = -1; + } else { throw new SyntaxError(`Unexpected character at index ${i2}`); } - if (end === -1) end = i2; - const protocol2 = header.slice(start, end); - if (protocols.has(protocol2)) { - throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); + } else if (paramName === void 0) { + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (code2 === 32 || code2 === 9) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (end === -1) end = i2; + push(params, header.slice(start, end), true); + if (code2 === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + start = end = -1; + } else if (code2 === 61 && start !== -1 && end === -1) { + paramName = header.slice(start, i2); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i2}`); } - protocols.add(protocol2); - start = end = -1; } else { - throw new SyntaxError(`Unexpected character at index ${i2}`); + if (isEscaping) { + if (tokenChars[code2] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (start === -1) start = i2; + else if (!mustUnescape) mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (code2 === 34 && start !== -1) { + inQuotes = false; + end = i2; + } else if (code2 === 92) { + isEscaping = true; + } else { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + } else if (code2 === 34 && header.charCodeAt(i2 - 1) === 61) { + inQuotes = true; + } else if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (start !== -1 && (code2 === 32 || code2 === 9)) { + if (end === -1) end = i2; + } else if (code2 === 59 || code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } + if (end === -1) end = i2; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ""); + mustUnescape = false; + } + push(params, paramName, value); + if (code2 === 44) { + push(offers, extensionName, params); + params = /* @__PURE__ */ Object.create(null); + extensionName = void 0; + } + paramName = void 0; + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i2}`); + } } } - if (start === -1 || end !== -1) { + if (start === -1 || inQuotes || code2 === 32 || code2 === 9) { throw new SyntaxError("Unexpected end of input"); } - const protocol = header.slice(start, i2); - if (protocols.has(protocol)) { - throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + if (end === -1) end = i2; + const token = header.slice(start, end); + if (extensionName === void 0) { + push(offers, token, params); + } else { + if (paramName === void 0) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, "")); + } else { + push(params, paramName, token); + } + push(offers, extensionName, params); } - protocols.add(protocol); - return protocols; + return offers; } - module14.exports = { parse: parse62 }; + function format52(extensions) { + return Object.keys(extensions).map((extension) => { + let configurations = extensions[extension]; + if (!Array.isArray(configurations)) configurations = [configurations]; + return configurations.map((params) => { + return [extension].concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) values = [values]; + return values.map((v2) => v2 === true ? k : `${k}=${v2}`).join("; "); + }) + ).join("; "); + }).join(", "); + }).join(", "); + } + module14.exports = { format: format52, parse: parse62 }; } }); -var require_websocket_server = __commonJS({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket-server.js"(exports2, module14) { +var require_websocket = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket.js"(exports2, module14) { "use strict"; var EventEmitter = __require2("events"); - var http = __require2("http"); var https = __require2("https"); + var http = __require2("http"); var net = __require2("net"); var tls = __require2("tls"); - var { createHash } = __require2("crypto"); - var extension = require_extension(); + var { randomBytes: randomBytes3, createHash } = __require2("crypto"); + var { Readable: Readable4 } = __require2("stream"); + var { URL: URL2 } = __require2("url"); var PerMessageDeflate = require_permessage_deflate(); - var subprotocol = require_subprotocol(); - var WebSocket3 = require_websocket(); - var { GUID, kWebSocket } = require_constants2(); - var keyRegex = /^[+/0-9A-Za-z]{22}==$/; - var RUNNING = 0; - var CLOSING = 1; - var CLOSED = 2; - var WebSocketServer2 = class extends EventEmitter { + var Receiver2 = require_receiver(); + var Sender2 = require_sender(); + var { + BINARY_TYPES, + EMPTY_BUFFER, + GUID, + kForOnEventAttribute, + kListener, + kStatusCode, + kWebSocket, + NOOP + } = require_constants2(); + var { + EventTarget: { addEventListener: addEventListener2, removeEventListener } + } = require_event_target(); + var { format: format52, parse: parse62 } = require_extension(); + var { toBuffer } = require_buffer_util(); + var readyStates = ["CONNECTING", "OPEN", "CLOSING", "CLOSED"]; + var subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; + var protocolVersions = [8, 13]; + var closeTimeout = 30 * 1e3; + var WebSocket3 = class _WebSocket extends EventEmitter { /** - * Create a `WebSocketServer` instance. + * Create a new `WebSocket`. * - * @param {Object} options Configuration options - * @param {Number} [options.backlog=511] The maximum length of the queue of - * pending connections - * @param {Boolean} [options.clientTracking=true] Specifies whether or not to - * track clients - * @param {Function} [options.handleProtocols] A hook to handle protocols - * @param {String} [options.host] The hostname where to bind the server - * @param {Number} [options.maxPayload=104857600] The maximum allowed message - * size - * @param {Boolean} [options.noServer=false] Enable no server mode - * @param {String} [options.path] Accept only connections matching this path - * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable - * permessage-deflate - * @param {Number} [options.port] The port where to bind the server - * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S - * server to use - * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or - * not to skip UTF-8 validation for text and close messages - * @param {Function} [options.verifyClient] A hook to reject connections - * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` - * class to use. It must be the `WebSocket` class or class that extends it - * @param {Function} [callback] A listener for the `listening` event + * @param {(String|URL)} address The URL to which to connect + * @param {(String|String[])} [protocols] The subprotocols + * @param {Object} [options] Connection options */ - constructor(options2, callback) { + constructor(address, protocols, options2) { super(); - options2 = { - maxPayload: 100 * 1024 * 1024, - skipUTF8Validation: false, - perMessageDeflate: false, - handleProtocols: null, - clientTracking: true, - verifyClient: null, - noServer: false, - backlog: null, - // use default (511 as implemented in net.js) - server: null, - host: null, - path: null, - port: null, - WebSocket: WebSocket3, - ...options2 - }; - if (options2.port == null && !options2.server && !options2.noServer || options2.port != null && (options2.server || options2.noServer) || options2.server && options2.noServer) { - throw new TypeError( - 'One and only one of the "port", "server", or "noServer" options must be specified' - ); - } - if (options2.port != null) { - this._server = http.createServer((req, res) => { - const body = http.STATUS_CODES[426]; - res.writeHead(426, { - "Content-Length": body.length, - "Content-Type": "text/plain" - }); - res.end(body); - }); - this._server.listen( - options2.port, - options2.host, - options2.backlog, - callback - ); - } else if (options2.server) { - this._server = options2.server; - } - if (this._server) { - const emitConnection = this.emit.bind(this, "connection"); - this._removeListeners = addListeners(this._server, { - listening: this.emit.bind(this, "listening"), - error: this.emit.bind(this, "error"), - upgrade: (req, socket, head) => { - this.handleUpgrade(req, socket, head, emitConnection); + this._binaryType = BINARY_TYPES[0]; + this._closeCode = 1006; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = EMPTY_BUFFER; + this._closeTimer = null; + this._extensions = {}; + this._paused = false; + this._protocol = ""; + this._readyState = _WebSocket.CONNECTING; + this._receiver = null; + this._sender = null; + this._socket = null; + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + if (protocols === void 0) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === "object" && protocols !== null) { + options2 = protocols; + protocols = []; + } else { + protocols = [protocols]; } - }); - } - if (options2.perMessageDeflate === true) options2.perMessageDeflate = {}; - if (options2.clientTracking) { - this.clients = /* @__PURE__ */ new Set(); - this._shouldEmitClose = false; + } + initAsClient(this, address, protocols, options2); + } else { + this._isServer = true; } - this.options = options2; - this._state = RUNNING; } /** - * Returns the bound address, the address family name, and port of the server - * as reported by the operating system if listening on an IP socket. - * If the server is listening on a pipe or UNIX domain socket, the name is - * returned as a string. + * This deviates from the WHATWG interface since ws doesn't support the + * required default "blob" type (instead we define a custom "nodebuffer" + * type). * - * @return {(Object|String|null)} The address of the server - * @public + * @type {String} */ - address() { - if (this.options.noServer) { - throw new Error('The server is operating in "noServer" mode'); + get binaryType() { + return this._binaryType; + } + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) return; + this._binaryType = type; + if (this._receiver) this._receiver._binaryType = type; + } + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) return this._bufferedAmount; + return this._socket._writableState.length + this._sender._bufferedBytes; + } + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onclose() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onerror() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onopen() { + return null; + } + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onmessage() { + return null; + } + /** + * @type {String} + */ + get protocol() { + return this._protocol; + } + /** + * @type {Number} + */ + get readyState() { + return this._readyState; + } + /** + * @type {String} + */ + get url() { + return this._url; + } + /** + * Set up the socket and the internal resources. + * + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Object} options Options object + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ + setSocket(socket, head, options2) { + const receiver = new Receiver2({ + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: options2.maxPayload, + skipUTF8Validation: options2.skipUTF8Validation + }); + this._sender = new Sender2(socket, this._extensions, options2.generateMask); + this._receiver = receiver; + this._socket = socket; + receiver[kWebSocket] = this; + socket[kWebSocket] = this; + receiver.on("conclude", receiverOnConclude); + receiver.on("drain", receiverOnDrain); + receiver.on("error", receiverOnError); + receiver.on("message", receiverOnMessage); + receiver.on("ping", receiverOnPing); + receiver.on("pong", receiverOnPong); + socket.setTimeout(0); + socket.setNoDelay(); + if (head.length > 0) socket.unshift(head); + socket.on("close", socketOnClose); + socket.on("data", socketOnData); + socket.on("end", socketOnEnd); + socket.on("error", socketOnError); + this._readyState = _WebSocket.OPEN; + this.emit("open"); + } + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this._readyState = _WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); + return; } - if (!this._server) return null; - return this._server.address(); + if (this._extensions[PerMessageDeflate.extensionName]) { + this._extensions[PerMessageDeflate.extensionName].cleanup(); + } + this._receiver.removeAllListeners(); + this._readyState = _WebSocket.CLOSED; + this.emit("close", this._closeCode, this._closeMessage); } /** - * Stop the server from accepting new connections and emit the `'close'` event - * when all existing connections are closed. + * Start a closing handshake. * - * @param {Function} [cb] A one-time listener for the `'close'` event + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} [code] Status code explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing * @public */ - close(cb) { - if (this._state === CLOSED) { - if (cb) { - this.once("close", () => { - cb(new Error("The server is not running")); - }); + close(code2, data) { + if (this.readyState === _WebSocket.CLOSED) return; + if (this.readyState === _WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + return abortHandshake(this, this._req, msg); + } + if (this.readyState === _WebSocket.CLOSING) { + if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) { + this._socket.end(); } - process.nextTick(emitClose, this); return; } - if (cb) this.once("close", cb); - if (this._state === CLOSING) return; - this._state = CLOSING; - if (this.options.noServer || this.options.server) { - if (this._server) { - this._removeListeners(); - this._removeListeners = this._server = null; - } - if (this.clients) { - if (!this.clients.size) { - process.nextTick(emitClose, this); - } else { - this._shouldEmitClose = true; - } - } else { - process.nextTick(emitClose, this); + this._readyState = _WebSocket.CLOSING; + this._sender.close(code2, data, !this._isServer, (err) => { + if (err) return; + this._closeFrameSent = true; + if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) { + this._socket.end(); } - } else { - const server = this._server; - this._removeListeners(); - this._removeListeners = this._server = null; - server.close(() => { - emitClose(this); - }); + }); + this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + closeTimeout + ); + } + /** + * Pause the socket. + * + * @public + */ + pause() { + if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { + return; } + this._paused = true; + this._socket.pause(); } /** - * See if a given request should be handled by this server instance. + * Send a ping. * - * @param {http.IncomingMessage} req Request object to inspect - * @return {Boolean} `true` if the request is valid, else `false` + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the ping is sent * @public */ - shouldHandle(req) { - if (this.options.path) { - const index = req.url.indexOf("?"); - const pathname = index !== -1 ? req.url.slice(0, index) : req.url; - if (pathname !== this.options.path) return false; + ping(data, mask, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); } - return true; + if (typeof data === "function") { + cb = data; + data = mask = void 0; + } else if (typeof mask === "function") { + cb = mask; + mask = void 0; + } + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + if (mask === void 0) mask = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask, cb); } /** - * Handle a HTTP Upgrade request. + * Send a pong. * - * @param {http.IncomingMessage} req The request object - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Function} cb Callback + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the pong is sent * @public */ - handleUpgrade(req, socket, head, cb) { - socket.on("error", socketOnError); - const key = req.headers["sec-websocket-key"] !== void 0 ? req.headers["sec-websocket-key"] : false; - const version3 = +req.headers["sec-websocket-version"]; - if (req.method !== "GET" || req.headers.upgrade.toLowerCase() !== "websocket" || !key || !keyRegex.test(key) || version3 !== 8 && version3 !== 13 || !this.shouldHandle(req)) { - return abortHandshake(socket, 400); + pong(data, mask, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); } - const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; - let protocols = /* @__PURE__ */ new Set(); - if (secWebSocketProtocol !== void 0) { - try { - protocols = subprotocol.parse(secWebSocketProtocol); - } catch (err) { - return abortHandshake(socket, 400); - } + if (typeof data === "function") { + cb = data; + data = mask = void 0; + } else if (typeof mask === "function") { + cb = mask; + mask = void 0; } - const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; - const extensions = {}; - if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { - const perMessageDeflate = new PerMessageDeflate( - this.options.perMessageDeflate, - true, - this.options.maxPayload - ); - try { - const offers = extension.parse(secWebSocketExtensions); - if (offers[PerMessageDeflate.extensionName]) { - perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); - extensions[PerMessageDeflate.extensionName] = perMessageDeflate; - } - } catch (err) { - return abortHandshake(socket, 400); - } + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; } - if (this.options.verifyClient) { - const info = { - origin: req.headers[`${version3 === 8 ? "sec-websocket-origin" : "origin"}`], - secure: !!(req.socket.authorized || req.socket.encrypted), - req - }; - if (this.options.verifyClient.length === 2) { - this.options.verifyClient(info, (verified, code2, message, headers) => { - if (!verified) { - return abortHandshake(socket, code2 || 401, message, headers); - } - this.completeUpgrade( - extensions, - key, - protocols, - req, - socket, - head, - cb - ); - }); - return; - } - if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); + if (mask === void 0) mask = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask, cb); + } + /** + * Resume the socket. + * + * @public + */ + resume() { + if (this.readyState === _WebSocket.CONNECTING || this.readyState === _WebSocket.CLOSED) { + return; } - this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); + this._paused = false; + if (!this._receiver._writableState.needDrain) this._socket.resume(); } /** - * Upgrade the connection to WebSocket. + * Send a data message. * - * @param {Object} extensions The accepted extensions - * @param {String} key The value of the `Sec-WebSocket-Key` header - * @param {Set} protocols The subprotocols - * @param {http.IncomingMessage} req The request object - * @param {(net.Socket|tls.Socket)} socket The network socket between the - * server and client - * @param {Buffer} head The first packet of the upgraded stream - * @param {Function} cb Callback - * @throws {Error} If called more than once with the same socket - * @private + * @param {*} data The message to send + * @param {Object} [options] Options object + * @param {Boolean} [options.binary] Specifies whether `data` is binary or + * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` + * @param {Boolean} [options.fin=true] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when data is written out + * @public */ - completeUpgrade(extensions, key, protocols, req, socket, head, cb) { - if (!socket.readable || !socket.writable) return socket.destroy(); - if (socket[kWebSocket]) { - throw new Error( - "server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" - ); + send(data, options2, cb) { + if (this.readyState === _WebSocket.CONNECTING) { + throw new Error("WebSocket is not open: readyState 0 (CONNECTING)"); } - if (this._state > RUNNING) return abortHandshake(socket, 503); - const digest = createHash("sha1").update(key + GUID).digest("base64"); - const headers = [ - "HTTP/1.1 101 Switching Protocols", - "Upgrade: websocket", - "Connection: Upgrade", - `Sec-WebSocket-Accept: ${digest}` - ]; - const ws = new this.options.WebSocket(null); - if (protocols.size) { - const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; - if (protocol) { - headers.push(`Sec-WebSocket-Protocol: ${protocol}`); - ws._protocol = protocol; - } + if (typeof options2 === "function") { + cb = options2; + options2 = {}; } - if (extensions[PerMessageDeflate.extensionName]) { - const params = extensions[PerMessageDeflate.extensionName].params; - const value = extension.format({ - [PerMessageDeflate.extensionName]: [params] - }); - headers.push(`Sec-WebSocket-Extensions: ${value}`); - ws._extensions = extensions; + if (typeof data === "number") data = data.toString(); + if (this.readyState !== _WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; } - this.emit("headers", headers, req); - socket.write(headers.concat("\r\n").join("\r\n")); - socket.removeListener("error", socketOnError); - ws.setSocket(socket, head, { - maxPayload: this.options.maxPayload, - skipUTF8Validation: this.options.skipUTF8Validation - }); - if (this.clients) { - this.clients.add(ws); - ws.on("close", () => { - this.clients.delete(ws); - if (this._shouldEmitClose && !this.clients.size) { - process.nextTick(emitClose, this); - } - }); + const opts = { + binary: typeof data !== "string", + mask: !this._isServer, + compress: true, + fin: true, + ...options2 + }; + if (!this._extensions[PerMessageDeflate.extensionName]) { + opts.compress = false; } - cb(ws, req); + this._sender.send(data || EMPTY_BUFFER, opts, cb); } - }; - module14.exports = WebSocketServer2; - function addListeners(server, map) { - for (const event of Object.keys(map)) server.on(event, map[event]); - return function removeListeners() { - for (const event of Object.keys(map)) { - server.removeListener(event, map[event]); + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === _WebSocket.CLOSED) return; + if (this.readyState === _WebSocket.CONNECTING) { + const msg = "WebSocket was closed before the connection was established"; + return abortHandshake(this, this._req, msg); + } + if (this._socket) { + this._readyState = _WebSocket.CLOSING; + this._socket.destroy(); } - }; - } - function emitClose(server) { - server._state = CLOSED; - server.emit("close"); - } - function socketOnError() { - this.destroy(); - } - function abortHandshake(socket, code2, message, headers) { - if (socket.writable) { - message = message || http.STATUS_CODES[code2]; - headers = { - Connection: "close", - "Content-Type": "text/html", - "Content-Length": Buffer.byteLength(message), - ...headers - }; - socket.write( - `HTTP/1.1 ${code2} ${http.STATUS_CODES[code2]}\r -` + Object.keys(headers).map((h2) => `${h2}: ${headers[h2]}`).join("\r\n") + "\r\n\r\n" + message - ); - } - socket.removeListener("error", socketOnError); - socket.destroy(); - } - } -}); -var import_stream2; -var import_receiver; -var import_sender; -var import_websocket3; -var import_websocket_server; -var wrapper_default; -var init_wrapper = __esm({ - "node_modules/.deno/ws@8.5.0/node_modules/ws/wrapper.mjs"() { - import_stream2 = __toESM(require_stream(), 1); - import_receiver = __toESM(require_receiver(), 1); - import_sender = __toESM(require_sender(), 1); - import_websocket3 = __toESM(require_websocket(), 1); - import_websocket_server = __toESM(require_websocket_server(), 1); - wrapper_default = import_websocket3.default; - } -}); -function createErrorResponse(data) { - return JSON.stringify({ type: ERROR, data }); -} -function createPushErrorResponse(data) { - return JSON.stringify({ - type: ERROR, - data: { - ...data, - type: REQUEST_TYPE.PUSH_ACTION - } - }); -} -function createNotification(type, data) { - return JSON.stringify({ type, data }); -} -function createOkResponse(data) { - return JSON.stringify({ type: OK, data }); -} -function createServer(httpServer2, options2 = {}) { - const server = new import_websocket_server.default({ - ...defaultOptions3, - ...options2, - ...{ clientTracking: true }, - server: httpServer2 - }); - server.channels = /* @__PURE__ */ new Set(); - server.customServerEventHandlers = { ...options2.serverHandlers }; - server.customSocketEventHandlers = { ...options2.socketHandlers }; - server.customMessageHandlers = { ...options2.messageHandlers }; - server.pingIntervalID = void 0; - server.subscribersByChannelID = /* @__PURE__ */ Object.create(null); - server.pushSubscriptions = /* @__PURE__ */ Object.create(null); - const handlers = Object.keys(defaultServerHandlers); - handlers.forEach((name) => { - server.on(name, (...args) => { - try { - ; - defaultServerHandlers[name].apply(server, args); - server.customServerEventHandlers[name]?.apply(server, args); - } catch (error2) { - server.emit("error", error2); } + }; + Object.defineProperty(WebSocket3, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") }); - }); - if (server.options.pingInterval > 0) { - server.pingIntervalID = setInterval(() => { - if (server.clients.size && server.options.logPingRounds) { - log.debug("Pinging clients"); - } - server.clients.forEach((client) => { - if (isPushSubscriptionInfo(client)) return; - if (client.pinged && !client.activeSinceLastPing) { - log(`Disconnecting irresponsive client ${client.id}`); - return client.terminate(); - } - if (client.readyState === wrapper_default.OPEN) { - client.send(createMessage(PING, Date.now()), () => { - client.activeSinceLastPing = false; - client.pinged = true; + Object.defineProperty(WebSocket3.prototype, "CONNECTING", { + enumerable: true, + value: readyStates.indexOf("CONNECTING") + }); + Object.defineProperty(WebSocket3, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") + }); + Object.defineProperty(WebSocket3.prototype, "OPEN", { + enumerable: true, + value: readyStates.indexOf("OPEN") + }); + Object.defineProperty(WebSocket3, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") + }); + Object.defineProperty(WebSocket3.prototype, "CLOSING", { + enumerable: true, + value: readyStates.indexOf("CLOSING") + }); + Object.defineProperty(WebSocket3, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") + }); + Object.defineProperty(WebSocket3.prototype, "CLOSED", { + enumerable: true, + value: readyStates.indexOf("CLOSED") + }); + [ + "binaryType", + "bufferedAmount", + "extensions", + "isPaused", + "protocol", + "readyState", + "url" + ].forEach((property) => { + Object.defineProperty(WebSocket3.prototype, property, { enumerable: true }); + }); + ["open", "error", "close", "message"].forEach((method) => { + Object.defineProperty(WebSocket3.prototype, `on${method}`, { + enumerable: true, + get() { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) return listener[kListener]; + } + return null; + }, + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } + } + if (typeof handler !== "function") return; + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true }); } }); - }, server.options.pingInterval); - } - return Object.assign(server, publicMethods2); -} -var import_npm_chalk; -var isPushSubscriptionInfo; -var bold; -var PING; -var PONG; -var PUB; -var SUB; -var UNSUB; -var KV_FILTER; -var ERROR; -var OK; -var defaultOptions3; -var tag2; -var generateSocketID; -var log; -var defaultServerHandlers; -var defaultSocketEventHandlers; -var defaultMessageHandlers2; -var publicMethods2; -var init_pubsub2 = __esm({ - "src/serve/pubsub.ts"() { - "use strict"; - init_esm5(); - init_pubsub(); - init_push(); - init_logger(); - import_npm_chalk = __toESM(require_source()); - init_wrapper(); - isPushSubscriptionInfo = (x3) => { - return has(x3, "endpoint"); - }; - ({ bold } = import_npm_chalk.default); - ({ PING, PONG, PUB, SUB, UNSUB, KV_FILTER } = NOTIFICATION_TYPE); - ({ ERROR, OK } = RESPONSE_TYPE); - defaultOptions3 = { - logPingRounds: process8.env.NODE_ENV !== "production" && !process8.env.CI, - logPongMessages: false, - maxPayload: 6 * 1024 * 1024, - pingInterval: 3e4 - }; - tag2 = "[pubsub]"; - generateSocketID = /* @__PURE__ */ (() => { - let counter = 0; - return (debugID) => String(counter++) + (debugID ? "-" + debugID : ""); - })(); - log = logger_default.info.bind(logger_default, tag2); - log.bold = (...args) => logger_default.debug(bold(tag2, ...args)); - log.debug = logger_default.debug.bind(logger_default, tag2); - log.error = (error2, ...args) => logger_default.error(error2, bold.red(tag2, ...args)); - defaultServerHandlers = { - close() { - clearInterval(this.pingIntervalID); - log("Server closed"); - }, - /** - * Emitted when a connection handshake completes. - * - * @see https://github.com/websockets/ws/blob/master/doc/ws.md#event-connection - * @param {ws.WebSocket} socket - The client socket that connected. - * @param {http.IncomingMessage} request - The underlying Node http GET request. - */ - connection(socket, request) { - const server = this; - const url2 = request.url; - const urlSearch = url2?.includes("?") ? url2.slice(url2.lastIndexOf("?")) : ""; - const debugID = new URLSearchParams(urlSearch).get("debugID") || ""; - const send = socket.send.bind(socket); - socket.id = generateSocketID(debugID); - socket.activeSinceLastPing = true; - socket.pinged = false; - socket.server = server; - socket.subscriptions = /* @__PURE__ */ new Set(); - socket.kvFilter = /* @__PURE__ */ new Map(); - socket.ip = request.headers["x-real-ip"] || request.headers["x-forwarded-for"]?.split(",")[0].trim() || request.socket.remoteAddress; - socket.send = function(data) { - if (typeof data === "object" && data !== null && typeof data[Symbol.toPrimitive] === "function") { - return send(data[Symbol.toPrimitive]()); - } - return send(data); - }; - log.bold(`Socket ${socket.id} connected. Total: ${this.clients.size}`); - ["close", "error", "message", "ping", "pong"].forEach((eventName) => { - socket.on(eventName, (...args) => { - if (eventName !== "message") { - log.debug(`Event '${eventName}' on socket ${socket.id}`, ...args.map((arg) => String(arg))); - } - try { - ; - defaultSocketEventHandlers[eventName]?.call(socket, ...args); - socket.server.customSocketEventHandlers[eventName]?.call(socket, ...args); - } catch (error2) { - socket.server.emit("error", error2); - socket.terminate(); - } - }); - }); - }, - error(error2) { - log.error(error2, "Server error"); - }, - headers() { - }, - listening() { - log("Server listening"); + }); + WebSocket3.prototype.addEventListener = addEventListener2; + WebSocket3.prototype.removeEventListener = removeEventListener; + module14.exports = WebSocket3; + function initAsClient(websocket, address, protocols, options2) { + const opts = { + protocolVersion: protocolVersions[1], + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options2, + createConnection: void 0, + socketPath: void 0, + hostname: void 0, + protocol: void 0, + timeout: void 0, + method: void 0, + host: void 0, + path: void 0, + port: void 0 + }; + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})` + ); } - }; - defaultSocketEventHandlers = { - close() { - const socket = this; - const { server } = this; - for (const channelID of socket.subscriptions) { - server.subscribersByChannelID[channelID].delete(socket); - } - socket.subscriptions.clear(); - }, - message(data) { - const socket = this; - const { server } = this; - const text = data.toString(); - let msg = { type: "" }; + let parsedUrl; + if (address instanceof URL2) { + parsedUrl = address; + websocket._url = address.href; + } else { try { - msg = messageParser(text); - } catch (error2) { - log.error(error2, `Malformed message: ${error2.message}`); - server.rejectMessageAndTerminateSocket(msg, socket); - return; + parsedUrl = new URL2(address); + } catch (e2) { + throw new SyntaxError(`Invalid URL: ${address}`); } - if (msg.type !== "pong" || server.options.logPongMessages) { - log.debug(`Received '${msg.type}' on socket ${socket.id}`, text); + websocket._url = address; + } + const isSecure = parsedUrl.protocol === "wss:"; + const isUnixSocket = parsedUrl.protocol === "ws+unix:"; + let invalidURLMessage; + if (parsedUrl.protocol !== "ws:" && !isSecure && !isUnixSocket) { + invalidURLMessage = `The URL's protocol must be one of "ws:", "wss:", or "ws+unix:"`; + } else if (isUnixSocket && !parsedUrl.pathname) { + invalidURLMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidURLMessage = "The URL contains a fragment identifier"; + } + if (invalidURLMessage) { + const err = new SyntaxError(invalidURLMessage); + if (websocket._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket, err); + return; } - socket.activeSinceLastPing = true; - const defaultHandler = defaultMessageHandlers2[msg.type]; - const customHandler = server.customMessageHandlers[msg.type]; - if (defaultHandler || customHandler) { - try { - ; - defaultHandler?.call(socket, msg); - customHandler?.call(socket, msg); - } catch (error2) { - log.error(error2, "onMessage"); - server.rejectMessageAndTerminateSocket(msg, socket); + } + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes3(16).toString("base64"); + const get2 = isSecure ? https.get : http.get; + const protocolSet = /* @__PURE__ */ new Set(); + let perMessageDeflate; + opts.createConnection = isSecure ? tlsConnect : netConnect; + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname; + opts.headers = { + "Sec-WebSocket-Version": opts.protocolVersion, + "Sec-WebSocket-Key": key, + Connection: "Upgrade", + Upgrade: "websocket", + ...opts.headers + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); + opts.headers["Sec-WebSocket-Extensions"] = format52({ + [PerMessageDeflate.extensionName]: perMessageDeflate.offer() + }); + } + if (protocols.length) { + for (const protocol of protocols) { + if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) { + throw new SyntaxError( + "An invalid or duplicated subprotocol was specified" + ); } + protocolSet.add(protocol); + } + opts.headers["Sec-WebSocket-Protocol"] = protocols.join(","); + } + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers["Sec-WebSocket-Origin"] = opts.origin; } else { - log.error(`Unhandled message type: ${msg.type}`); - server.rejectMessageAndTerminateSocket(msg, socket); + opts.headers.Origin = opts.origin; } } - }; - defaultMessageHandlers2 = { - [PONG]() { - const socket = this; - socket.activeSinceLastPing = true; - }, - [PUB](msg) { - const { server } = this; - const subscribers = server.subscribersByChannelID[msg.channelID]; - server.broadcast(msg, { to: subscribers ?? [] }); - }, - [SUB]({ channelID, kvFilter }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); - return; + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + } + if (isUnixSocket) { + const parts = opts.path.split(":"); + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + if (opts.followRedirects) { + if (websocket._redirects === 0) { + websocket._originalHost = parsedUrl.host; + const headers = options2 && options2.headers; + options2 = { ...options2, headers: {} }; + if (headers) { + for (const [key2, value] of Object.entries(headers)) { + options2.headers[key2.toLowerCase()] = value; + } + } + } else if (parsedUrl.host !== websocket._originalHost) { + delete opts.headers.authorization; + delete opts.headers.cookie; + delete opts.headers.host; + opts.auth = void 0; + } + if (opts.auth && !options2.headers.authorization) { + options2.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64"); } - if (!socket.subscriptions.has(channelID)) { - socket.subscriptions.add(channelID); - if (Array.isArray(kvFilter)) { - socket.kvFilter.set(channelID, new Set(kvFilter)); + } + let req = websocket._req = get2(opts); + if (opts.timeout) { + req.on("timeout", () => { + abortHandshake(websocket, req, "Opening handshake has timed out"); + }); + } + req.on("error", (err) => { + if (req === null || req.aborted) return; + req = websocket._req = null; + emitErrorAndClose(websocket, err); + }); + req.on("response", (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) { + if (++websocket._redirects > opts.maxRedirects) { + abortHandshake(websocket, req, "Maximum redirects exceeded"); + return; } - if (!server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); + req.abort(); + let addr; + try { + addr = new URL2(location, address); + } catch (e2) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket, err); + return; } - server.subscribersByChannelID[channelID].add(socket); - } else { - log.debug("Already subscribed to", channelID); + initAsClient(websocket, addr, protocols, options2); + } else if (!websocket.emit("unexpected-response", req, res)) { + abortHandshake( + websocket, + req, + `Unexpected server response: ${res.statusCode}` + ); } - socket.send(createOkResponse({ type: SUB, channelID, kvFilter })); - }, - [KV_FILTER]({ channelID, kvFilter }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); + }); + req.on("upgrade", (res, socket, head) => { + websocket.emit("upgrade", res); + if (websocket.readyState !== WebSocket3.CONNECTING) return; + req = websocket._req = null; + const digest = createHash("sha1").update(key + GUID).digest("base64"); + if (res.headers["sec-websocket-accept"] !== digest) { + abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header"); return; } - if (socket.subscriptions.has(channelID)) { - if (Array.isArray(kvFilter)) { - socket.kvFilter.set(channelID, new Set(kvFilter)); - } else { - socket.kvFilter.delete(channelID); + const serverProt = res.headers["sec-websocket-protocol"]; + let protError; + if (serverProt !== void 0) { + if (!protocolSet.size) { + protError = "Server sent a subprotocol but none was requested"; + } else if (!protocolSet.has(serverProt)) { + protError = "Server sent an invalid subprotocol"; } - } else { - log.debug("[KV_FILTER] Not subscribed to", channelID); + } else if (protocolSet.size) { + protError = "Server sent no subprotocol"; } - socket.send(createOkResponse({ type: KV_FILTER, channelID, kvFilter })); - }, - [UNSUB]({ channelID }) { - const socket = this; - const { server } = this; - if (!server.channels.has(channelID)) { - socket.send(createErrorResponse( - { type: UNSUB, channelID, reason: `Unknown channel id: ${channelID}` } - )); + if (protError) { + abortHandshake(websocket, socket, protError); + return; } - if (socket.subscriptions.has(channelID)) { - socket.subscriptions.delete(channelID); - socket.kvFilter.delete(channelID); - if (server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID].delete(socket); + if (serverProt) websocket._protocol = serverProt; + const secWebSocketExtensions = res.headers["sec-websocket-extensions"]; + if (secWebSocketExtensions !== void 0) { + if (!perMessageDeflate) { + const message = "Server sent a Sec-WebSocket-Extensions header but no extension was requested"; + abortHandshake(websocket, socket, message); + return; } - } - socket.send(createOkResponse({ type: UNSUB, channelID })); - } - }; - publicMethods2 = { - /** - * Broadcasts a message, ignoring clients which are not open. - * - * @param message - * @param to - The intended recipients of the message. Defaults to every open client socket. - * @param except - A recipient to exclude. Optional. - */ - broadcast(message, { to, except, wsOnly } = {}) { - const server = this; - const msg = typeof message === "string" ? message : JSON.stringify(message); - let shortMsg; - const shortenPayload = () => { - if (!shortMsg && (typeof message === "object" && message.type === NOTIFICATION_TYPE.ENTRY && message.data)) { - delete message.data; - shortMsg = JSON.stringify(message); - } - return shortMsg; - }; - for (const client of to || server.clients) { - if (!wsOnly && isPushSubscriptionInfo(client)) { - if (msg.length > 4096 - 86 - 17) { - if (!shortenPayload()) { - console.info("Skipping too large of a payload for", client.id); - continue; - } - } - postEvent(client, shortMsg || msg).catch((e2) => { - if (e2?.message === "Payload too large") { - if (shortMsg || !shortenPayload()) { - console.info("Skipping too large of a payload for", client.id); - return; - } - postEvent(client, shortMsg).catch((e3) => { - console.error(e3, "Error posting push notification"); - }); - return; - } - console.error(e2, "Error posting push notification"); - }); - continue; + let extensions; + try { + extensions = parse62(secWebSocketExtensions); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake(websocket, socket, message); + return; } - if (client.readyState === wrapper_default.OPEN && client !== except) { - client.send(msg); + const extensionNames = Object.keys(extensions); + if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) { + const message = "Server indicated an extension that was not requested"; + abortHandshake(websocket, socket, message); + return; } - } - }, - // Enumerates the subscribers of a given channel. - *enumerateSubscribers(channelID, kvKey) { - const server = this; - if (channelID in server.subscribersByChannelID) { - const subscribers = server.subscribersByChannelID[channelID]; - if (!kvKey) { - yield* subscribers; - } else { - for (const subscriber of subscribers) { - const kvFilter = subscriber.kvFilter?.get(channelID); - if (!kvFilter || kvFilter.has(kvKey)) yield subscriber; - } + try { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + } catch (err) { + const message = "Invalid Sec-WebSocket-Extensions header"; + abortHandshake(websocket, socket, message); + return; } + websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate; } - }, - rejectMessageAndTerminateSocket(request, socket) { - socket.send(createErrorResponse({ ...request }), () => socket.terminate()); - } - }; - } -}); -var require_parser2 = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js"(exports2) { - "use strict"; - exports2.load = function(received, defaults, onto = {}) { - var k, ref, v2; - for (k in defaults) { - v2 = defaults[k]; - onto[k] = (ref = received[k]) != null ? ref : v2; + websocket.setSocket(socket, head, { + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); + }); + } + function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket3.CLOSING; + websocket.emit("error", err); + websocket.emitClose(); + } + function netConnect(options2) { + options2.path = options2.socketPath; + return net.connect(options2); + } + function tlsConnect(options2) { + options2.path = void 0; + if (!options2.servername && options2.servername !== "") { + options2.servername = net.isIP(options2.host) ? "" : options2.host; } - return onto; - }; - exports2.overwrite = function(received, defaults, onto = {}) { - var k, v2; - for (k in received) { - v2 = received[k]; - if (defaults[k] !== void 0) { - onto[k] = v2; + return tls.connect(options2); + } + function abortHandshake(websocket, stream, message) { + websocket._readyState = WebSocket3.CLOSING; + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake); + if (stream.setHeader) { + stream.abort(); + if (stream.socket && !stream.socket.destroyed) { + stream.socket.destroy(); } + stream.once("abort", websocket.emitClose.bind(websocket)); + websocket.emit("error", err); + } else { + stream.destroy(err); + stream.once("error", websocket.emit.bind(websocket, "error")); + stream.once("close", websocket.emitClose.bind(websocket)); } - return onto; - }; - } -}); -var require_DLList = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/DLList.js"(exports2, module14) { - "use strict"; - var DLList; - DLList = class DLList { - constructor(incr, decr) { - this.incr = incr; - this.decr = decr; - this._first = null; - this._last = null; - this.length = 0; + } + function sendAfterClose(websocket, data, cb) { + if (data) { + const length2 = toBuffer(data).length; + if (websocket._socket) websocket._sender._bufferedBytes += length2; + else websocket._bufferedAmount += length2; } - push(value) { - var node; - this.length++; - if (typeof this.incr === "function") { - this.incr(); - } - node = { - value, - prev: this._last, - next: null - }; - if (this._last != null) { - this._last.next = node; - this._last = node; - } else { - this._first = this._last = node; - } - return void 0; + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})` + ); + cb(err); } - shift() { - var value; - if (this._first == null) { - return; - } else { - this.length--; - if (typeof this.decr === "function") { - this.decr(); - } - } - value = this._first.value; - if ((this._first = this._first.next) != null) { - this._first.prev = null; - } else { - this._last = null; - } - return value; + } + function receiverOnConclude(code2, reason) { + const websocket = this[kWebSocket]; + websocket._closeFrameReceived = true; + websocket._closeMessage = reason; + websocket._closeCode = code2; + if (websocket._socket[kWebSocket] === void 0) return; + websocket._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket._socket); + if (code2 === 1005) websocket.close(); + else websocket.close(code2, reason); + } + function receiverOnDrain() { + const websocket = this[kWebSocket]; + if (!websocket.isPaused) websocket._socket.resume(); + } + function receiverOnError(err) { + const websocket = this[kWebSocket]; + if (websocket._socket[kWebSocket] !== void 0) { + websocket._socket.removeListener("data", socketOnData); + process.nextTick(resume, websocket._socket); + websocket.close(err[kStatusCode]); } - first() { - if (this._first != null) { - return this._first.value; - } + websocket.emit("error", err); + } + function receiverOnFinish() { + this[kWebSocket].emitClose(); + } + function receiverOnMessage(data, isBinary) { + this[kWebSocket].emit("message", data, isBinary); + } + function receiverOnPing(data) { + const websocket = this[kWebSocket]; + websocket.pong(data, !websocket._isServer, NOOP); + websocket.emit("ping", data); + } + function receiverOnPong(data) { + this[kWebSocket].emit("pong", data); + } + function resume(stream) { + stream.resume(); + } + function socketOnClose() { + const websocket = this[kWebSocket]; + this.removeListener("close", socketOnClose); + this.removeListener("data", socketOnData); + this.removeListener("end", socketOnEnd); + websocket._readyState = WebSocket3.CLOSING; + let chunk; + if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && (chunk = websocket._socket.read()) !== null) { + websocket._receiver.write(chunk); } - getArray() { - var node, ref, results; - node = this._first; - results = []; - while (node != null) { - results.push((ref = node, node = node.next, ref.value)); - } - return results; + websocket._receiver.end(); + this[kWebSocket] = void 0; + clearTimeout(websocket._closeTimer); + if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) { + websocket.emitClose(); + } else { + websocket._receiver.on("error", receiverOnFinish); + websocket._receiver.on("finish", receiverOnFinish); } - forEachShift(cb) { - var node; - node = this.shift(); - while (node != null) { - cb(node), node = this.shift(); - } - return void 0; + } + function socketOnData(chunk) { + if (!this[kWebSocket]._receiver.write(chunk)) { + this.pause(); } - debug() { - var node, ref, ref1, ref2, results; - node = this._first; - results = []; - while (node != null) { - results.push((ref = node, node = node.next, { - value: ref.value, - prev: (ref1 = ref.prev) != null ? ref1.value : void 0, - next: (ref2 = ref.next) != null ? ref2.value : void 0 - })); - } - return results; + } + function socketOnEnd() { + const websocket = this[kWebSocket]; + websocket._readyState = WebSocket3.CLOSING; + websocket._receiver.end(); + this.end(); + } + function socketOnError() { + const websocket = this[kWebSocket]; + this.removeListener("error", socketOnError); + this.on("error", NOOP); + if (websocket) { + websocket._readyState = WebSocket3.CLOSING; + this.destroy(); } - }; - module14.exports = DLList; + } } }); -var require_Events = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Events.js"(exports2, module14) { +var require_subprotocol = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/subprotocol.js"(exports2, module14) { "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + var { tokenChars } = require_validation(); + function parse62(header) { + const protocols = /* @__PURE__ */ new Set(); + let start = -1; + let end = -1; + let i2 = 0; + for (i2; i2 < header.length; i2++) { + const code2 = header.charCodeAt(i2); + if (end === -1 && tokenChars[code2] === 1) { + if (start === -1) start = i2; + } else if (i2 !== 0 && (code2 === 32 || code2 === 9)) { + if (end === -1 && start !== -1) end = i2; + } else if (code2 === 44) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i2}`); } - _next(void 0); - }); - }; - } - var Events2; - Events2 = class Events { - constructor(instance) { - this.instance = instance; - this._events = {}; - if (this.instance.on != null || this.instance.once != null || this.instance.removeAllListeners != null) { - throw new Error("An Emitter already exists for this object"); - } - this.instance.on = (name, cb) => { - return this._addListener(name, "many", cb); - }; - this.instance.once = (name, cb) => { - return this._addListener(name, "once", cb); - }; - this.instance.removeAllListeners = (name = null) => { - if (name != null) { - return delete this._events[name]; - } else { - return this._events = {}; + if (end === -1) end = i2; + const protocol2 = header.slice(start, end); + if (protocols.has(protocol2)) { + throw new SyntaxError(`The "${protocol2}" subprotocol is duplicated`); } - }; - } - _addListener(name, status, cb) { - var base2; - if ((base2 = this._events)[name] == null) { - base2[name] = []; - } - this._events[name].push({ - cb, - status - }); - return this.instance; - } - listenerCount(name) { - if (this._events[name] != null) { - return this._events[name].length; + protocols.add(protocol2); + start = end = -1; } else { - return 0; + throw new SyntaxError(`Unexpected character at index ${i2}`); } } - trigger(name, ...args) { - var _this = this; - return _asyncToGenerator2(function* () { - var e2, promises; - try { - if (name !== "debug") { - _this.trigger("debug", `Event triggered: ${name}`, args); - } - if (_this._events[name] == null) { - return; - } - _this._events[name] = _this._events[name].filter(function(listener) { - return listener.status !== "none"; - }); - promises = _this._events[name].map( - /* @__PURE__ */ function() { - var _ref = _asyncToGenerator2(function* (listener) { - var e3, returned; - if (listener.status === "none") { - return; - } - if (listener.status === "once") { - listener.status = "none"; - } - try { - returned = typeof listener.cb === "function" ? listener.cb(...args) : void 0; - if (typeof (returned != null ? returned.then : void 0) === "function") { - return yield returned; - } else { - return returned; - } - } catch (error2) { - e3 = error2; - if (true) { - _this.trigger("error", e3); - } - return null; - } - }); - return function(_x) { - return _ref.apply(this, arguments); - }; - }() - ); - return (yield Promise.all(promises)).find(function(x3) { - return x3 != null; - }); - } catch (error2) { - e2 = error2; - if (true) { - _this.trigger("error", e2); - } - return null; - } - })(); + if (start === -1 || end !== -1) { + throw new SyntaxError("Unexpected end of input"); } - }; - module14.exports = Events2; + const protocol = header.slice(start, i2); + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + protocols.add(protocol); + return protocols; + } + module14.exports = { parse: parse62 }; } }); -var require_Queues = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Queues.js"(exports2, module14) { +var require_websocket_server = __commonJS({ + "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket-server.js"(exports2, module14) { "use strict"; - var DLList; - var Events2; - var Queues; - DLList = require_DLList(); - Events2 = require_Events(); - Queues = class Queues { - constructor(num_priorities) { - var i2; - this.Events = new Events2(this); - this._length = 0; - this._lists = function() { - var j, ref, results; - results = []; - for (i2 = j = 1, ref = num_priorities; 1 <= ref ? j <= ref : j >= ref; i2 = 1 <= ref ? ++j : --j) { - results.push(new DLList(() => { - return this.incr(); - }, () => { - return this.decr(); - })); - } - return results; - }.call(this); - } - incr() { - if (this._length++ === 0) { - return this.Events.trigger("leftzero"); + var EventEmitter = __require2("events"); + var http = __require2("http"); + var https = __require2("https"); + var net = __require2("net"); + var tls = __require2("tls"); + var { createHash } = __require2("crypto"); + var extension = require_extension(); + var PerMessageDeflate = require_permessage_deflate(); + var subprotocol = require_subprotocol(); + var WebSocket3 = require_websocket(); + var { GUID, kWebSocket } = require_constants2(); + var keyRegex = /^[+/0-9A-Za-z]{22}==$/; + var RUNNING = 0; + var CLOSING = 1; + var CLOSED = 2; + var WebSocketServer2 = class extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Number} [options.backlog=511] The maximum length of the queue of + * pending connections + * @param {Boolean} [options.clientTracking=true] Specifies whether or not to + * track clients + * @param {Function} [options.handleProtocols] A hook to handle protocols + * @param {String} [options.host] The hostname where to bind the server + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Boolean} [options.noServer=false] Enable no server mode + * @param {String} [options.path] Accept only connections matching this path + * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable + * permessage-deflate + * @param {Number} [options.port] The port where to bind the server + * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S + * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @param {Function} [options.verifyClient] A hook to reject connections + * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` + * class to use. It must be the `WebSocket` class or class that extends it + * @param {Function} [callback] A listener for the `listening` event + */ + constructor(options2, callback) { + super(); + options2 = { + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + verifyClient: null, + noServer: false, + backlog: null, + // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + WebSocket: WebSocket3, + ...options2 + }; + if (options2.port == null && !options2.server && !options2.noServer || options2.port != null && (options2.server || options2.noServer) || options2.server && options2.noServer) { + throw new TypeError( + 'One and only one of the "port", "server", or "noServer" options must be specified' + ); } - } - decr() { - if (--this._length === 0) { - return this.Events.trigger("zero"); + if (options2.port != null) { + this._server = http.createServer((req, res) => { + const body = http.STATUS_CODES[426]; + res.writeHead(426, { + "Content-Length": body.length, + "Content-Type": "text/plain" + }); + res.end(body); + }); + this._server.listen( + options2.port, + options2.host, + options2.backlog, + callback + ); + } else if (options2.server) { + this._server = options2.server; + } + if (this._server) { + const emitConnection = this.emit.bind(this, "connection"); + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, "listening"), + error: this.emit.bind(this, "error"), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, emitConnection); + } + }); } + if (options2.perMessageDeflate === true) options2.perMessageDeflate = {}; + if (options2.clientTracking) { + this.clients = /* @__PURE__ */ new Set(); + this._shouldEmitClose = false; + } + this.options = options2; + this._state = RUNNING; } - push(job) { - return this._lists[job.options.priority].push(job); + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); + } + if (!this._server) return null; + return this._server.address(); } - queued(priority) { - if (priority != null) { - return this._lists[priority].length; + /** + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. + * + * @param {Function} [cb] A one-time listener for the `'close'` event + * @public + */ + close(cb) { + if (this._state === CLOSED) { + if (cb) { + this.once("close", () => { + cb(new Error("The server is not running")); + }); + } + process.nextTick(emitClose, this); + return; + } + if (cb) this.once("close", cb); + if (this._state === CLOSING) return; + this._state = CLOSING; + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; + } + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); + } } else { - return this._length; + const server = this._server; + this._removeListeners(); + this._removeListeners = this._server = null; + server.close(() => { + emitClose(this); + }); } } - shiftAll(fn) { - return this._lists.forEach(function(list) { - return list.forEachShift(fn); - }); - } - getFirst(arr = this._lists) { - var j, len, list; - for (j = 0, len = arr.length; j < len; j++) { - list = arr[j]; - if (list.length > 0) { - return list; - } + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf("?"); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + if (pathname !== this.options.path) return false; } - return []; + return true; } - shiftLastFrom(priority) { - return this.getFirst(this._lists.slice(priority).reverse()).shift(); - } - }; - module14.exports = Queues; - } -}); -var require_BottleneckError = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/BottleneckError.js"(exports2, module14) { - "use strict"; - var BottleneckError; - BottleneckError = class BottleneckError extends Error { - }; - module14.exports = BottleneckError; - } -}); -var require_Job = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Job.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on("error", socketOnError); + const key = req.headers["sec-websocket-key"] !== void 0 ? req.headers["sec-websocket-key"] : false; + const version3 = +req.headers["sec-websocket-version"]; + if (req.method !== "GET" || req.headers.upgrade.toLowerCase() !== "websocket" || !key || !keyRegex.test(key) || version3 !== 8 && version3 !== 13 || !this.shouldHandle(req)) { + return abortHandshake(socket, 400); + } + const secWebSocketProtocol = req.headers["sec-websocket-protocol"]; + let protocols = /* @__PURE__ */ new Set(); + if (secWebSocketProtocol !== void 0) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + return abortHandshake(socket, 400); } - _next(void 0); - }); - }; - } - var BottleneckError; - var DEFAULT_PRIORITY; - var Job; - var NUM_PRIORITIES; - var parser3; - NUM_PRIORITIES = 10; - DEFAULT_PRIORITY = 5; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - Job = class Job { - constructor(task, args, options2, jobDefaults, rejectOnDrop, Events2, _states, Promise2) { - this.task = task; - this.args = args; - this.rejectOnDrop = rejectOnDrop; - this.Events = Events2; - this._states = _states; - this.Promise = Promise2; - this.options = parser3.load(options2, jobDefaults); - this.options.priority = this._sanitizePriority(this.options.priority); - if (this.options.id === jobDefaults.id) { - this.options.id = `${this.options.id}-${this._randomIndex()}`; } - this.promise = new this.Promise((_resolve, _reject) => { - this._resolve = _resolve; - this._reject = _reject; - }); - this.retryCount = 0; - } - _sanitizePriority(priority) { - var sProperty; - sProperty = ~~priority !== priority ? DEFAULT_PRIORITY : priority; - if (sProperty < 0) { - return 0; - } else if (sProperty > NUM_PRIORITIES - 1) { - return NUM_PRIORITIES - 1; - } else { - return sProperty; + const secWebSocketExtensions = req.headers["sec-websocket-extensions"]; + const extensions = {}; + if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) { + const perMessageDeflate = new PerMessageDeflate( + this.options.perMessageDeflate, + true, + this.options.maxPayload + ); + try { + const offers = extension.parse(secWebSocketExtensions); + if (offers[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + } catch (err) { + return abortHandshake(socket, 400); + } } - } - _randomIndex() { - return Math.random().toString(36).slice(2); - } - doDrop({ - error: error2, - message = "This job has been dropped by Bottleneck" - } = {}) { - if (this._states.remove(this.options.id)) { - if (this.rejectOnDrop) { - this._reject(error2 != null ? error2 : new BottleneckError(message)); + if (this.options.verifyClient) { + const info = { + origin: req.headers[`${version3 === 8 ? "sec-websocket-origin" : "origin"}`], + secure: !!(req.socket.authorized || req.socket.encrypted), + req + }; + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code2, message, headers) => { + if (!verified) { + return abortHandshake(socket, code2 || 401, message, headers); + } + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); + }); + return; } - this.Events.trigger("dropped", { - args: this.args, - options: this.options, - task: this.task, - promise: this.promise - }); - return true; - } else { - return false; + if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); } + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); } - _assertStatus(expected) { - var status; - status = this._states.jobStatus(this.options.id); - if (!(status === expected || expected === "DONE" && status === null)) { - throw new BottleneckError(`Invalid job status ${status}, expected ${expected}. Please open an issue at https://github.com/SGrondin/bottleneck/issues`); + /** + * Upgrade the connection to WebSocket. + * + * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols + * @param {http.IncomingMessage} req The request object + * @param {(net.Socket|tls.Socket)} socket The network socket between the + * server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket + * @private + */ + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { + if (!socket.readable || !socket.writable) return socket.destroy(); + if (socket[kWebSocket]) { + throw new Error( + "server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration" + ); } - } - doReceive() { - this._states.start(this.options.id); - return this.Events.trigger("received", { - args: this.args, - options: this.options - }); - } - doQueue(reachedHWM, blocked) { - this._assertStatus("RECEIVED"); - this._states.next(this.options.id); - return this.Events.trigger("queued", { - args: this.args, - options: this.options, - reachedHWM, - blocked - }); - } - doRun() { - if (this.retryCount === 0) { - this._assertStatus("QUEUED"); - this._states.next(this.options.id); - } else { - this._assertStatus("EXECUTING"); + if (this._state > RUNNING) return abortHandshake(socket, 503); + const digest = createHash("sha1").update(key + GUID).digest("base64"); + const headers = [ + "HTTP/1.1 101 Switching Protocols", + "Upgrade: websocket", + "Connection: Upgrade", + `Sec-WebSocket-Accept: ${digest}` + ]; + const ws = new this.options.WebSocket(null); + if (protocols.size) { + const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value; + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws._protocol = protocol; + } } - return this.Events.trigger("scheduled", { - args: this.args, - options: this.options + if (extensions[PerMessageDeflate.extensionName]) { + const params = extensions[PerMessageDeflate.extensionName].params; + const value = extension.format({ + [PerMessageDeflate.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; + } + this.emit("headers", headers, req); + socket.write(headers.concat("\r\n").join("\r\n")); + socket.removeListener("error", socketOnError); + ws.setSocket(socket, head, { + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation }); - } - doExecute(chained, clearGlobalState, run2, free) { - var _this = this; - return _asyncToGenerator2(function* () { - var error2, eventInfo, passed; - if (_this.retryCount === 0) { - _this._assertStatus("RUNNING"); - _this._states.next(_this.options.id); - } else { - _this._assertStatus("EXECUTING"); - } - eventInfo = { - args: _this.args, - options: _this.options, - retryCount: _this.retryCount - }; - _this.Events.trigger("executing", eventInfo); - try { - passed = yield chained != null ? chained.schedule(_this.options, _this.task, ..._this.args) : _this.task(..._this.args); - if (clearGlobalState()) { - _this.doDone(eventInfo); - yield free(_this.options, eventInfo); - _this._assertStatus("DONE"); - return _this._resolve(passed); + if (this.clients) { + this.clients.add(ws); + ws.on("close", () => { + this.clients.delete(ws); + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); } - } catch (error1) { - error2 = error1; - return _this._onFailure(error2, eventInfo, clearGlobalState, run2, free); - } - })(); + }); + } + cb(ws, req); } - doExpire(clearGlobalState, run2, free) { - var error2, eventInfo; - if (this._states.jobStatus(this.options.id === "RUNNING")) { - this._states.next(this.options.id); + }; + module14.exports = WebSocketServer2; + function addListeners(server, map) { + for (const event of Object.keys(map)) server.on(event, map[event]); + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); } - this._assertStatus("EXECUTING"); - eventInfo = { - args: this.args, - options: this.options, - retryCount: this.retryCount + }; + } + function emitClose(server) { + server._state = CLOSED; + server.emit("close"); + } + function socketOnError() { + this.destroy(); + } + function abortHandshake(socket, code2, message, headers) { + if (socket.writable) { + message = message || http.STATUS_CODES[code2]; + headers = { + Connection: "close", + "Content-Type": "text/html", + "Content-Length": Buffer.byteLength(message), + ...headers }; - error2 = new BottleneckError(`This job timed out after ${this.options.expiration} ms.`); - return this._onFailure(error2, eventInfo, clearGlobalState, run2, free); - } - _onFailure(error2, eventInfo, clearGlobalState, run2, free) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var retry, retryAfter; - if (clearGlobalState()) { - retry = yield _this2.Events.trigger("failed", error2, eventInfo); - if (retry != null) { - retryAfter = ~~retry; - _this2.Events.trigger("retry", `Retrying ${_this2.options.id} after ${retryAfter} ms`, eventInfo); - _this2.retryCount++; - return run2(retryAfter); - } else { - _this2.doDone(eventInfo); - yield free(_this2.options, eventInfo); - _this2._assertStatus("DONE"); - return _this2._reject(error2); - } - } - })(); - } - doDone(eventInfo) { - this._assertStatus("EXECUTING"); - this._states.next(this.options.id); - return this.Events.trigger("done", eventInfo); + socket.write( + `HTTP/1.1 ${code2} ${http.STATUS_CODES[code2]}\r +` + Object.keys(headers).map((h2) => `${h2}: ${headers[h2]}`).join("\r\n") + "\r\n\r\n" + message + ); } - }; - module14.exports = Job; + socket.removeListener("error", socketOnError); + socket.destroy(); + } } }); -var require_LocalDatastore = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/LocalDatastore.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); +init_esm(); +var import_npm_nconf7 = __toESM(require_nconf()); +function getLineColFromPtr(string3, ptr) { + let lines = string3.slice(0, ptr).split(/\r\n|\n|\r/g); + return [lines.length, lines.pop().length + 1]; +} +function makeCodeBlock(string3, line, column) { + let lines = string3.split(/\r\n|\n|\r/g); + let codeblock = ""; + let numberLen = (Math.log10(line + 1) | 0) + 1; + for (let i2 = line - 1; i2 <= line + 1; i2++) { + let l = lines[i2 - 1]; + if (!l) + continue; + codeblock += i2.toString().padEnd(numberLen, " "); + codeblock += ": "; + codeblock += l; + codeblock += "\n"; + if (i2 === line) { + codeblock += " ".repeat(numberLen + column + 2); + codeblock += "^\n"; + } + } + return codeblock; +} +var TomlError = class extends Error { + line; + column; + codeblock; + constructor(message, options2) { + const [line, column] = getLineColFromPtr(options2.toml, options2.ptr); + const codeblock = makeCodeBlock(options2.toml, line, column); + super(`Invalid TOML document: ${message} + +${codeblock}`, options2); + this.line = line; + this.column = column; + this.codeblock = codeblock; + } +}; +function isEscaped(str, ptr) { + let i2 = 0; + while (str[ptr - ++i2] === "\\") + ; + return --i2 && i2 % 2; +} +function indexOfNewline(str, start = 0, end = str.length) { + let idx = str.indexOf("\n", start); + if (str[idx - 1] === "\r") + idx--; + return idx <= end ? idx : -1; +} +function skipComment(str, ptr) { + for (let i2 = ptr; i2 < str.length; i2++) { + let c = str[i2]; + if (c === "\n") + return i2; + if (c === "\r" && str[i2 + 1] === "\n") + return i2 + 1; + if (c < " " && c !== " " || c === "\x7F") { + throw new TomlError("control characters are not allowed in comments", { + toml: str, + ptr + }); + } + } + return str.length; +} +function skipVoid(str, ptr, banNewLines, banComments) { + let c; + while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n")) + ptr++; + return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines); +} +function skipUntil(str, ptr, sep, end, banNewLines = false) { + if (!end) { + ptr = indexOfNewline(str, ptr); + return ptr < 0 ? str.length : ptr; + } + for (let i2 = ptr; i2 < str.length; i2++) { + let c = str[i2]; + if (c === "#") { + i2 = indexOfNewline(str, i2); + } else if (c === sep) { + return i2 + 1; + } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i2 + 1] === "\n")) { + return i2; + } + } + throw new TomlError("cannot find end of structure", { + toml: str, + ptr + }); +} +function getStringEnd(str, seek) { + let first = str[seek]; + let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first; + seek += target.length - 1; + do + seek = str.indexOf(target, ++seek); + while (seek > -1 && first !== "'" && isEscaped(str, seek)); + if (seek > -1) { + seek += target.length; + if (target.length > 1) { + if (str[seek] === first) + seek++; + if (str[seek] === first) + seek++; + } + } + return seek; +} +var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}:\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?$/i; +var TomlDate = class _TomlDate extends Date { + #hasDate = false; + #hasTime = false; + #offset = null; + constructor(date3) { + let hasDate = true; + let hasTime = true; + let offset = "Z"; + if (typeof date3 === "string") { + let match2 = date3.match(DATE_TIME_RE); + if (match2) { + if (!match2[1]) { + hasDate = false; + date3 = `0000-01-01T${date3}`; + } + hasTime = !!match2[2]; + hasTime && date3[10] === " " && (date3 = date3.replace(" ", "T")); + if (match2[2] && +match2[2] > 23) { + date3 = ""; + } else { + offset = match2[3] || null; + date3 = date3.toUpperCase(); + if (!offset && hasTime) + date3 += "Z"; + } } else { - Promise.resolve(value).then(_next, _throw); + date3 = ""; } } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; + super(date3); + if (!isNaN(this.getTime())) { + this.#hasDate = hasDate; + this.#hasTime = hasTime; + this.#offset = offset; } - var BottleneckError; - var LocalDatastore; - var parser3; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - LocalDatastore = class LocalDatastore { - constructor(instance, storeOptions, storeInstanceOptions) { - this.instance = instance; - this.storeOptions = storeOptions; - this.clientId = this.instance._randomIndex(); - parser3.load(storeInstanceOptions, storeInstanceOptions, this); - this._nextRequest = this._lastReservoirRefresh = this._lastReservoirIncrease = Date.now(); - this._running = 0; - this._done = 0; - this._unblockTime = 0; - this.ready = this.Promise.resolve(); - this.clients = {}; - this._startHeartbeat(); + } + isDateTime() { + return this.#hasDate && this.#hasTime; + } + isLocal() { + return !this.#hasDate || !this.#hasTime || !this.#offset; + } + isDate() { + return this.#hasDate && !this.#hasTime; + } + isTime() { + return this.#hasTime && !this.#hasDate; + } + isValid() { + return this.#hasDate || this.#hasTime; + } + toISOString() { + let iso = super.toISOString(); + if (this.isDate()) + return iso.slice(0, 10); + if (this.isTime()) + return iso.slice(11, 23); + if (this.#offset === null) + return iso.slice(0, -1); + if (this.#offset === "Z") + return iso; + let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6); + offset = this.#offset[0] === "-" ? offset : -offset; + let offsetDate = new Date(this.getTime() - offset * 6e4); + return offsetDate.toISOString().slice(0, -1) + this.#offset; + } + static wrapAsOffsetDateTime(jsDate, offset = "Z") { + let date3 = new _TomlDate(jsDate); + date3.#offset = offset; + return date3; + } + static wrapAsLocalDateTime(jsDate) { + let date3 = new _TomlDate(jsDate); + date3.#offset = null; + return date3; + } + static wrapAsLocalDate(jsDate) { + let date3 = new _TomlDate(jsDate); + date3.#hasTime = false; + date3.#offset = null; + return date3; + } + static wrapAsLocalTime(jsDate) { + let date3 = new _TomlDate(jsDate); + date3.#hasDate = false; + date3.#offset = null; + return date3; + } +}; +var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/; +var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/; +var LEADING_ZERO = /^[+-]?0[0-9_]/; +var ESCAPE_REGEX = /^[0-9a-f]{4,8}$/i; +var ESC_MAP = { + b: "\b", + t: " ", + n: "\n", + f: "\f", + r: "\r", + '"': '"', + "\\": "\\" +}; +function parseString(str, ptr = 0, endPtr = str.length) { + let isLiteral = str[ptr] === "'"; + let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1]; + if (isMultiline) { + endPtr -= 2; + if (str[ptr += 2] === "\r") + ptr++; + if (str[ptr] === "\n") + ptr++; + } + let tmp = 0; + let isEscape; + let parsed = ""; + let sliceStart = ptr; + while (ptr < endPtr - 1) { + let c = str[ptr++]; + if (c === "\n" || c === "\r" && str[ptr] === "\n") { + if (!isMultiline) { + throw new TomlError("newlines are not allowed in strings", { + toml: str, + ptr: ptr - 1 + }); } - _startHeartbeat() { - var base2; - if (this.heartbeat == null && (this.storeOptions.reservoirRefreshInterval != null && this.storeOptions.reservoirRefreshAmount != null || this.storeOptions.reservoirIncreaseInterval != null && this.storeOptions.reservoirIncreaseAmount != null)) { - return typeof (base2 = this.heartbeat = setInterval(() => { - var amount, incr, maximum, now, reservoir; - now = Date.now(); - if (this.storeOptions.reservoirRefreshInterval != null && now >= this._lastReservoirRefresh + this.storeOptions.reservoirRefreshInterval) { - this._lastReservoirRefresh = now; - this.storeOptions.reservoir = this.storeOptions.reservoirRefreshAmount; - this.instance._drainAll(this.computeCapacity()); - } - if (this.storeOptions.reservoirIncreaseInterval != null && now >= this._lastReservoirIncrease + this.storeOptions.reservoirIncreaseInterval) { - var _this$storeOptions = this.storeOptions; - amount = _this$storeOptions.reservoirIncreaseAmount; - maximum = _this$storeOptions.reservoirIncreaseMaximum; - reservoir = _this$storeOptions.reservoir; - this._lastReservoirIncrease = now; - incr = maximum != null ? Math.min(amount, maximum - reservoir) : amount; - if (incr > 0) { - this.storeOptions.reservoir += incr; - return this.instance._drainAll(this.computeCapacity()); - } - } - }, this.heartbeatInterval)).unref === "function" ? base2.unref() : void 0; - } else { - return clearInterval(this.heartbeat); + } else if (c < " " && c !== " " || c === "\x7F") { + throw new TomlError("control characters are not allowed in strings", { + toml: str, + ptr: ptr - 1 + }); + } + if (isEscape) { + isEscape = false; + if (c === "u" || c === "U") { + let code2 = str.slice(ptr, ptr += c === "u" ? 4 : 8); + if (!ESCAPE_REGEX.test(code2)) { + throw new TomlError("invalid unicode escape", { + toml: str, + ptr: tmp + }); } - } - __publish__(message) { - var _this = this; - return _asyncToGenerator2(function* () { - yield _this.yieldLoop(); - return _this.instance.Events.trigger("message", message.toString()); - })(); - } - __disconnect__(flush) { - var _this2 = this; - return _asyncToGenerator2(function* () { - yield _this2.yieldLoop(); - clearInterval(_this2.heartbeat); - return _this2.Promise.resolve(); - })(); - } - yieldLoop(t = 0) { - return new this.Promise(function(resolve82, reject) { - return setTimeout(resolve82, t); + try { + parsed += String.fromCodePoint(parseInt(code2, 16)); + } catch { + throw new TomlError("invalid unicode escape", { + toml: str, + ptr: tmp + }); + } + } else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) { + ptr = skipVoid(str, ptr - 1, true); + if (str[ptr] !== "\n" && str[ptr] !== "\r") { + throw new TomlError("invalid escape: only line-ending whitespace may be escaped", { + toml: str, + ptr: tmp + }); + } + ptr = skipVoid(str, ptr); + } else if (c in ESC_MAP) { + parsed += ESC_MAP[c]; + } else { + throw new TomlError("unrecognized escape sequence", { + toml: str, + ptr: tmp }); } - computePenalty() { - var ref; - return (ref = this.storeOptions.penalty) != null ? ref : 15 * this.storeOptions.minTime || 5e3; - } - __updateSettings__(options2) { - var _this3 = this; - return _asyncToGenerator2(function* () { - yield _this3.yieldLoop(); - parser3.overwrite(options2, options2, _this3.storeOptions); - _this3._startHeartbeat(); - _this3.instance._drainAll(_this3.computeCapacity()); - return true; - })(); - } - __running__() { - var _this4 = this; - return _asyncToGenerator2(function* () { - yield _this4.yieldLoop(); - return _this4._running; - })(); - } - __queued__() { - var _this5 = this; - return _asyncToGenerator2(function* () { - yield _this5.yieldLoop(); - return _this5.instance.queued(); - })(); + sliceStart = ptr; + } else if (!isLiteral && c === "\\") { + tmp = ptr - 1; + isEscape = true; + parsed += str.slice(sliceStart, tmp); + } + } + return parsed + str.slice(sliceStart, endPtr - 1); +} +function parseValue(value, toml, ptr, integersAsBigInt) { + if (value === "true") + return true; + if (value === "false") + return false; + if (value === "-inf") + return -Infinity; + if (value === "inf" || value === "+inf") + return Infinity; + if (value === "nan" || value === "+nan" || value === "-nan") + return NaN; + if (value === "-0") + return integersAsBigInt ? 0n : 0; + let isInt = INT_REGEX.test(value); + if (isInt || FLOAT_REGEX.test(value)) { + if (LEADING_ZERO.test(value)) { + throw new TomlError("leading zeroes are not allowed", { + toml, + ptr + }); + } + value = value.replace(/_/g, ""); + let numeric = +value; + if (isNaN(numeric)) { + throw new TomlError("invalid number", { + toml, + ptr + }); + } + if (isInt) { + if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) { + throw new TomlError("integer value cannot be represented losslessly", { + toml, + ptr + }); } - __done__() { - var _this6 = this; - return _asyncToGenerator2(function* () { - yield _this6.yieldLoop(); - return _this6._done; - })(); + if (isInt || integersAsBigInt === true) + numeric = BigInt(value); + } + return numeric; + } + const date3 = new TomlDate(value); + if (!date3.isValid()) { + throw new TomlError("invalid value", { + toml, + ptr + }); + } + return date3; +} +function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) { + let value = str.slice(startPtr, endPtr); + let commentIdx = value.indexOf("#"); + if (commentIdx > -1) { + skipComment(str, commentIdx); + value = value.slice(0, commentIdx); + } + let trimmed = value.trimEnd(); + if (!allowNewLines) { + let newlineIdx = value.indexOf("\n", trimmed.length); + if (newlineIdx > -1) { + throw new TomlError("newlines are not allowed in inline tables", { + toml: str, + ptr: startPtr + newlineIdx + }); + } + } + return [trimmed, commentIdx]; +} +function extractValue(str, ptr, end, depth, integersAsBigInt) { + if (depth === 0) { + throw new TomlError("document contains excessively nested structures. aborting.", { + toml: str, + ptr + }); + } + let c = str[ptr]; + if (c === "[" || c === "{") { + let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt); + let newPtr = end ? skipUntil(str, endPtr2, ",", end) : endPtr2; + if (endPtr2 - newPtr && end === "}") { + let nextNewLine = indexOfNewline(str, endPtr2, newPtr); + if (nextNewLine > -1) { + throw new TomlError("newlines are not allowed in inline tables", { + toml: str, + ptr: nextNewLine + }); } - __groupCheck__(time3) { - var _this7 = this; - return _asyncToGenerator2(function* () { - yield _this7.yieldLoop(); - return _this7._nextRequest + _this7.timeout < time3; - })(); + } + return [value, newPtr]; + } + let endPtr; + if (c === '"' || c === "'") { + endPtr = getStringEnd(str, ptr); + let parsed = parseString(str, ptr, endPtr); + if (end) { + endPtr = skipVoid(str, endPtr, end !== "]"); + if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") { + throw new TomlError("unexpected character encountered", { + toml: str, + ptr: endPtr + }); } - computeCapacity() { - var maxConcurrent, reservoir; - var _this$storeOptions2 = this.storeOptions; - maxConcurrent = _this$storeOptions2.maxConcurrent; - reservoir = _this$storeOptions2.reservoir; - if (maxConcurrent != null && reservoir != null) { - return Math.min(maxConcurrent - this._running, reservoir); - } else if (maxConcurrent != null) { - return maxConcurrent - this._running; - } else if (reservoir != null) { - return reservoir; - } else { - return null; + endPtr += +(str[endPtr] === ","); + } + return [parsed, endPtr]; + } + endPtr = skipUntil(str, ptr, ",", end); + let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","), end === "]"); + if (!slice[0]) { + throw new TomlError("incomplete key-value declaration: no value specified", { + toml: str, + ptr + }); + } + if (end && slice[1] > -1) { + endPtr = skipVoid(str, ptr + slice[1]); + endPtr += +(str[endPtr] === ","); + } + return [ + parseValue(slice[0], str, ptr, integersAsBigInt), + endPtr + ]; +} +var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/; +function parseKey(str, ptr, end = "=") { + let dot = ptr - 1; + let parsed = []; + let endPtr = str.indexOf(end, ptr); + if (endPtr < 0) { + throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + } + do { + let c = str[ptr = ++dot]; + if (c !== " " && c !== " ") { + if (c === '"' || c === "'") { + if (c === str[ptr + 1] && c === str[ptr + 2]) { + throw new TomlError("multiline strings are not allowed in keys", { + toml: str, + ptr + }); } + let eos = getStringEnd(str, ptr); + if (eos < 0) { + throw new TomlError("unfinished string encountered", { + toml: str, + ptr + }); + } + dot = str.indexOf(".", eos); + let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot); + let newLine = indexOfNewline(strEnd); + if (newLine > -1) { + throw new TomlError("newlines are not allowed in keys", { + toml: str, + ptr: ptr + dot + newLine + }); + } + if (strEnd.trimStart()) { + throw new TomlError("found extra tokens after the string part", { + toml: str, + ptr: eos + }); + } + if (endPtr < eos) { + endPtr = str.indexOf(end, eos); + if (endPtr < 0) { + throw new TomlError("incomplete key-value: cannot find end of key", { + toml: str, + ptr + }); + } + } + parsed.push(parseString(str, ptr, eos)); + } else { + dot = str.indexOf(".", ptr); + let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot); + if (!KEY_PART_RE.test(part)) { + throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", { + toml: str, + ptr + }); + } + parsed.push(part.trimEnd()); } - conditionsCheck(weight) { - var capacity; - capacity = this.computeCapacity(); - return capacity == null || weight <= capacity; - } - __incrementReservoir__(incr) { - var _this8 = this; - return _asyncToGenerator2(function* () { - var reservoir; - yield _this8.yieldLoop(); - reservoir = _this8.storeOptions.reservoir += incr; - _this8.instance._drainAll(_this8.computeCapacity()); - return reservoir; - })(); - } - __currentReservoir__() { - var _this9 = this; - return _asyncToGenerator2(function* () { - yield _this9.yieldLoop(); - return _this9.storeOptions.reservoir; - })(); + } + } while (dot + 1 && dot < endPtr); + return [parsed, skipVoid(str, endPtr + 1, true, true)]; +} +function parseInlineTable(str, ptr, depth, integersAsBigInt) { + let res = {}; + let seen = /* @__PURE__ */ new Set(); + let c; + let comma = 0; + ptr++; + while ((c = str[ptr++]) !== "}" && c) { + let err = { toml: str, ptr: ptr - 1 }; + if (c === "\n") { + throw new TomlError("newlines are not allowed in inline tables", err); + } else if (c === "#") { + throw new TomlError("inline tables cannot contain comments", err); + } else if (c === ",") { + throw new TomlError("expected key-value, found comma", err); + } else if (c !== " " && c !== " ") { + let k; + let t = res; + let hasOwn = false; + let [key, keyEndPtr] = parseKey(str, ptr - 1); + for (let i2 = 0; i2 < key.length; i2++) { + if (i2) + t = hasOwn ? t[k] : t[k] = {}; + k = key[i2]; + if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) { + throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); + } + if (!hasOwn && k === "__proto__") { + Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true }); + } } - isBlocked(now) { - return this._unblockTime >= now; + if (hasOwn) { + throw new TomlError("trying to redefine an already defined value", { + toml: str, + ptr + }); } - check(weight, now) { - return this.conditionsCheck(weight) && this._nextRequest - now <= 0; + let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt); + seen.add(value); + t[k] = value; + ptr = valueEndPtr; + comma = str[ptr - 1] === "," ? ptr - 1 : 0; + } + } + if (comma) { + throw new TomlError("trailing commas are not allowed in inline tables", { + toml: str, + ptr: comma + }); + } + if (!c) { + throw new TomlError("unfinished table encountered", { + toml: str, + ptr + }); + } + return [res, ptr]; +} +function parseArray(str, ptr, depth, integersAsBigInt) { + let res = []; + let c; + ptr++; + while ((c = str[ptr++]) !== "]" && c) { + if (c === ",") { + throw new TomlError("expected value, found comma", { + toml: str, + ptr: ptr - 1 + }); + } else if (c === "#") + ptr = skipComment(str, ptr); + else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { + let e2 = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt); + res.push(e2[0]); + ptr = e2[1]; + } + } + if (!c) { + throw new TomlError("unfinished array encountered", { + toml: str, + ptr + }); + } + return [res, ptr]; +} +function peekTable(key, table, meta, type) { + let t = table; + let m3 = meta; + let k; + let hasOwn = false; + let state; + for (let i2 = 0; i2 < key.length; i2++) { + if (i2) { + t = hasOwn ? t[k] : t[k] = {}; + m3 = (state = m3[k]).c; + if (type === 0 && (state.t === 1 || state.t === 2)) { + return null; } - __check__(weight) { - var _this10 = this; - return _asyncToGenerator2(function* () { - var now; - yield _this10.yieldLoop(); - now = Date.now(); - return _this10.check(weight, now); - })(); + if (state.t === 2) { + let l = t.length - 1; + t = t[l]; + m3 = m3[l].c; } - __register__(index, weight, expiration) { - var _this11 = this; - return _asyncToGenerator2(function* () { - var now, wait; - yield _this11.yieldLoop(); - now = Date.now(); - if (_this11.conditionsCheck(weight)) { - _this11._running += weight; - if (_this11.storeOptions.reservoir != null) { - _this11.storeOptions.reservoir -= weight; - } - wait = Math.max(_this11._nextRequest - now, 0); - _this11._nextRequest = now + wait + _this11.storeOptions.minTime; - return { - success: true, - wait, - reservoir: _this11.storeOptions.reservoir - }; - } else { - return { - success: false - }; - } - })(); + } + k = key[i2]; + if ((hasOwn = Object.hasOwn(t, k)) && m3[k]?.t === 0 && m3[k]?.d) { + return null; + } + if (!hasOwn) { + if (k === "__proto__") { + Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true }); + Object.defineProperty(m3, k, { enumerable: true, configurable: true, writable: true }); } - strategyIsBlock() { - return this.storeOptions.strategy === 3; + m3[k] = { + t: i2 < key.length - 1 && type === 2 ? 3 : type, + d: false, + i: 0, + c: {} + }; + } + } + state = m3[k]; + if (state.t !== type && !(type === 1 && state.t === 3)) { + return null; + } + if (type === 2) { + if (!state.d) { + state.d = true; + t[k] = []; + } + t[k].push(t = {}); + state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} }; + } + if (state.d) { + return null; + } + state.d = true; + if (type === 1) { + t = hasOwn ? t[k] : t[k] = {}; + } else if (type === 0 && hasOwn) { + return null; + } + return [k, t, state.c]; +} +function parse8(toml, { maxDepth = 1e3, integersAsBigInt } = {}) { + let res = {}; + let meta = {}; + let tbl = res; + let m3 = meta; + for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) { + if (toml[ptr] === "[") { + let isTableArray = toml[++ptr] === "["; + let k = parseKey(toml, ptr += +isTableArray, "]"); + if (isTableArray) { + if (toml[k[1] - 1] !== "]") { + throw new TomlError("expected end of table declaration", { + toml, + ptr: k[1] - 1 + }); + } + k[1]++; } - __submit__(queueLength, weight) { - var _this12 = this; - return _asyncToGenerator2(function* () { - var blocked, now, reachedHWM; - yield _this12.yieldLoop(); - if (_this12.storeOptions.maxConcurrent != null && weight > _this12.storeOptions.maxConcurrent) { - throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${_this12.storeOptions.maxConcurrent}`); - } - now = Date.now(); - reachedHWM = _this12.storeOptions.highWater != null && queueLength === _this12.storeOptions.highWater && !_this12.check(weight, now); - blocked = _this12.strategyIsBlock() && (reachedHWM || _this12.isBlocked(now)); - if (blocked) { - _this12._unblockTime = now + _this12.computePenalty(); - _this12._nextRequest = _this12._unblockTime + _this12.storeOptions.minTime; - _this12.instance._dropAllQueued(); - } - return { - reachedHWM, - blocked, - strategy: _this12.storeOptions.strategy - }; - })(); + let p = peekTable( + k[0], + res, + meta, + isTableArray ? 2 : 1 + /* Type.EXPLICIT */ + ); + if (!p) { + throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); } - __free__(index, weight) { - var _this13 = this; - return _asyncToGenerator2(function* () { - yield _this13.yieldLoop(); - _this13._running -= weight; - _this13._done += weight; - _this13.instance._drainAll(_this13.computeCapacity()); - return { - running: _this13._running - }; - })(); + m3 = p[2]; + tbl = p[1]; + ptr = k[1]; + } else { + let k = parseKey(toml, ptr); + let p = peekTable( + k[0], + tbl, + m3, + 0 + /* Type.DOTTED */ + ); + if (!p) { + throw new TomlError("trying to redefine an already defined table or value", { + toml, + ptr + }); + } + let v2 = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt); + p[1][p[0]] = v2[0]; + ptr = v2[1]; + } + ptr = skipVoid(toml, ptr, true); + if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") { + throw new TomlError("each key-value declaration must be followed by an end-of-line", { + toml, + ptr + }); + } + ptr = skipVoid(toml, ptr); + } + return res; +} +var BARE_KEY = /^[a-z0-9-_]+$/i; +function extendedTypeOf(obj) { + let type = typeof obj; + if (type === "object") { + if (Array.isArray(obj)) + return "array"; + if (obj instanceof Date) + return "date"; + } + return type; +} +function isArrayOfTables(obj) { + for (let i2 = 0; i2 < obj.length; i2++) { + if (extendedTypeOf(obj[i2]) !== "object") + return false; + } + return obj.length != 0; +} +function formatString(s) { + return JSON.stringify(s).replace(/\x7f/g, "\\u007f"); +} +function stringifyValue(val, type, depth, numberAsFloat) { + if (depth === 0) { + throw new Error("Could not stringify the object: maximum object depth exceeded"); + } + if (type === "number") { + if (isNaN(val)) + return "nan"; + if (val === Infinity) + return "inf"; + if (val === -Infinity) + return "-inf"; + if (numberAsFloat && Number.isInteger(val)) + return val.toFixed(1); + return val.toString(); + } + if (type === "bigint" || type === "boolean") { + return val.toString(); + } + if (type === "string") { + return formatString(val); + } + if (type === "date") { + if (isNaN(val.getTime())) { + throw new TypeError("cannot serialize invalid date"); + } + return val.toISOString(); + } + if (type === "object") { + return stringifyInlineTable(val, depth, numberAsFloat); + } + if (type === "array") { + return stringifyArray(val, depth, numberAsFloat); + } +} +function stringifyInlineTable(obj, depth, numberAsFloat) { + let keys = Object.keys(obj); + if (keys.length === 0) + return "{}"; + let res = "{ "; + for (let i2 = 0; i2 < keys.length; i2++) { + let k = keys[i2]; + if (i2) + res += ", "; + res += BARE_KEY.test(k) ? k : formatString(k); + res += " = "; + res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat); + } + return res + " }"; +} +function stringifyArray(array2, depth, numberAsFloat) { + if (array2.length === 0) + return "[]"; + let res = "[ "; + for (let i2 = 0; i2 < array2.length; i2++) { + if (i2) + res += ", "; + if (array2[i2] === null || array2[i2] === void 0) { + throw new TypeError("arrays cannot contain null or undefined values"); + } + res += stringifyValue(array2[i2], extendedTypeOf(array2[i2]), depth - 1, numberAsFloat); + } + return res + " ]"; +} +function stringifyArrayTable(array2, key, depth, numberAsFloat) { + if (depth === 0) { + throw new Error("Could not stringify the object: maximum object depth exceeded"); + } + let res = ""; + for (let i2 = 0; i2 < array2.length; i2++) { + res += `[[${key}]] +`; + res += stringifyTable(array2[i2], key, depth, numberAsFloat); + res += "\n\n"; + } + return res; +} +function stringifyTable(obj, prefix, depth, numberAsFloat) { + if (depth === 0) { + throw new Error("Could not stringify the object: maximum object depth exceeded"); + } + let preamble = ""; + let tables = ""; + let keys = Object.keys(obj); + for (let i2 = 0; i2 < keys.length; i2++) { + let k = keys[i2]; + if (obj[k] !== null && obj[k] !== void 0) { + let type = extendedTypeOf(obj[k]); + if (type === "symbol" || type === "function") { + throw new TypeError(`cannot serialize values of type '${type}'`); + } + let key = BARE_KEY.test(k) ? k : formatString(k); + if (type === "array" && isArrayOfTables(obj[k])) { + tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat); + } else if (type === "object") { + let tblKey = prefix ? `${prefix}.${key}` : key; + tables += `[${tblKey}] +`; + tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat); + tables += "\n\n"; + } else { + preamble += key; + preamble += " = "; + preamble += stringifyValue(obj[k], type, depth, numberAsFloat); + preamble += "\n"; } + } + } + return `${preamble} +${tables}`.trim(); +} +function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) { + if (extendedTypeOf(obj) !== "object") { + throw new TypeError("stringify can only be called with an object"); + } + return stringifyTable(obj, "", maxDepth, numbersAsFloat); +} +var commands_exports = {}; +__export(commands_exports, { + deploy: () => module3, + eventsAfter: () => module4, + get: () => module5, + hash: () => module6, + keygen: () => module7, + manifest: () => module8, + migrate: () => module9, + pin: () => module10, + serve: () => module11, + upload: () => module2, + verifySignature: () => module12, + version: () => module13 +}); +init_zod(); +init_functions(); +init_esm(); +init_esm2(); +init_esm(); +init_esm3(); +var listenKey = (evt) => `events/${evt}/listeners`; +var esm_default4 = esm_default("sbp/selectors/register", { + "okTurtles.events/_init": function() { + this.errorHandler = (event, e2) => { + console.error(`[okTurtles.events] Error at handler for ${event}`, e2); }; - module14.exports = LocalDatastore; + }, + "okTurtles.events/on": function(event, handler) { + esm_default("okTurtles.data/add", listenKey(event), handler); + return () => esm_default("okTurtles.events/off", event, handler); + }, + "okTurtles.events/once": function(event, handler) { + const cbWithOff = (...args) => { + handler(...args); + esm_default("okTurtles.events/off", event, cbWithOff); + }; + return esm_default("okTurtles.events/on", event, cbWithOff); + }, + "okTurtles.events/emit": function(event, ...data) { + var _a2; + for (const listener of esm_default("okTurtles.data/get", listenKey(event)) || []) { + try { + listener(...data); + } catch (e2) { + (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); + } + } + }, + // almost identical to Vue.prototype.$off, except we require `event` argument + "okTurtles.events/off": function(event, handler) { + if (handler) { + esm_default("okTurtles.data/remove", listenKey(event), handler); + } else { + esm_default("okTurtles.data/delete", listenKey(event)); + } + }, + "okTurtles.events/setErrorHandler": function(errorHandler2) { + this.errorHandler = errorHandler2; } }); -var require_lua = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/lua.json"(exports2, module14) { - module14.exports = { - "blacklist_client.lua": "local blacklist = ARGV[num_static_argv + 1]\n\nif redis.call('zscore', client_last_seen_key, blacklist) then\n redis.call('zadd', client_last_seen_key, 0, blacklist)\nend\n\n\nreturn {}\n", - "check.lua": "local weight = tonumber(ARGV[num_static_argv + 1])\n\nlocal capacity = process_tick(now, false)['capacity']\nlocal nextRequest = tonumber(redis.call('hget', settings_key, 'nextRequest'))\n\nreturn conditions_check(capacity, weight) and nextRequest - now <= 0\n", - "conditions_check.lua": "local conditions_check = function (capacity, weight)\n return capacity == nil or weight <= capacity\nend\n", - "current_reservoir.lua": "return process_tick(now, false)['reservoir']\n", - "done.lua": "process_tick(now, false)\n\nreturn tonumber(redis.call('hget', settings_key, 'done'))\n", - "free.lua": "local index = ARGV[num_static_argv + 1]\n\nredis.call('zadd', job_expirations_key, 0, index)\n\nreturn process_tick(now, false)['running']\n", - "get_time.lua": "redis.replicate_commands()\n\nlocal get_time = function ()\n local time = redis.call('time')\n\n return tonumber(time[1]..string.sub(time[2], 1, 3))\nend\n", - "group_check.lua": "return not (redis.call('exists', settings_key) == 1)\n", - "heartbeat.lua": "process_tick(now, true)\n", - "increment_reservoir.lua": "local incr = tonumber(ARGV[num_static_argv + 1])\n\nredis.call('hincrby', settings_key, 'reservoir', incr)\n\nlocal reservoir = process_tick(now, true)['reservoir']\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn reservoir\n", - "init.lua": `local clear = tonumber(ARGV[num_static_argv + 1]) -local limiter_version = ARGV[num_static_argv + 2] -local num_local_argv = num_static_argv + 2 - -if clear == 1 then - redis.call('del', unpack(KEYS)) -end - -if redis.call('exists', settings_key) == 0 then - -- Create - local args = {'hmset', settings_key} - - for i = num_local_argv + 1, #ARGV do - table.insert(args, ARGV[i]) - end - - redis.call(unpack(args)) - redis.call('hmset', settings_key, - 'nextRequest', now, - 'lastReservoirRefresh', now, - 'lastReservoirIncrease', now, - 'running', 0, - 'done', 0, - 'unblockTime', 0, - 'capacityPriorityCounter', 0 - ) - -else - -- Apply migrations - local settings = redis.call('hmget', settings_key, - 'id', - 'version' - ) - local id = settings[1] - local current_version = settings[2] - - if current_version ~= limiter_version then - local version_digits = {} - for k, v in string.gmatch(current_version, "([^.]+)") do - table.insert(version_digits, tonumber(k)) - end - - -- 2.10.0 - if version_digits[2] < 10 then - redis.call('hsetnx', settings_key, 'reservoirRefreshInterval', '') - redis.call('hsetnx', settings_key, 'reservoirRefreshAmount', '') - redis.call('hsetnx', settings_key, 'lastReservoirRefresh', '') - redis.call('hsetnx', settings_key, 'done', 0) - redis.call('hset', settings_key, 'version', '2.10.0') - end - - -- 2.11.1 - if version_digits[2] < 11 or (version_digits[2] == 11 and version_digits[3] < 1) then - if redis.call('hstrlen', settings_key, 'lastReservoirRefresh') == 0 then - redis.call('hmset', settings_key, - 'lastReservoirRefresh', now, - 'version', '2.11.1' - ) - end - end - - -- 2.14.0 - if version_digits[2] < 14 then - local old_running_key = 'b_'..id..'_running' - local old_executing_key = 'b_'..id..'_executing' - - if redis.call('exists', old_running_key) == 1 then - redis.call('rename', old_running_key, job_weights_key) - end - if redis.call('exists', old_executing_key) == 1 then - redis.call('rename', old_executing_key, job_expirations_key) - end - redis.call('hset', settings_key, 'version', '2.14.0') - end - - -- 2.15.2 - if version_digits[2] < 15 or (version_digits[2] == 15 and version_digits[3] < 2) then - redis.call('hsetnx', settings_key, 'capacityPriorityCounter', 0) - redis.call('hset', settings_key, 'version', '2.15.2') - end - - -- 2.17.0 - if version_digits[2] < 17 then - redis.call('hsetnx', settings_key, 'clientTimeout', 10000) - redis.call('hset', settings_key, 'version', '2.17.0') - end - - -- 2.18.0 - if version_digits[2] < 18 then - redis.call('hsetnx', settings_key, 'reservoirIncreaseInterval', '') - redis.call('hsetnx', settings_key, 'reservoirIncreaseAmount', '') - redis.call('hsetnx', settings_key, 'reservoirIncreaseMaximum', '') - redis.call('hsetnx', settings_key, 'lastReservoirIncrease', now) - redis.call('hset', settings_key, 'version', '2.18.0') - end - - end - - process_tick(now, false) -end - -local groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout')) -refresh_expiration(0, 0, groupTimeout) - -return {} -`, - "process_tick.lua": "local process_tick = function (now, always_publish)\n\n local compute_capacity = function (maxConcurrent, running, reservoir)\n if maxConcurrent ~= nil and reservoir ~= nil then\n return math.min((maxConcurrent - running), reservoir)\n elseif maxConcurrent ~= nil then\n return maxConcurrent - running\n elseif reservoir ~= nil then\n return reservoir\n else\n return nil\n end\n end\n\n local settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'running',\n 'reservoir',\n 'reservoirRefreshInterval',\n 'reservoirRefreshAmount',\n 'lastReservoirRefresh',\n 'reservoirIncreaseInterval',\n 'reservoirIncreaseAmount',\n 'reservoirIncreaseMaximum',\n 'lastReservoirIncrease',\n 'capacityPriorityCounter',\n 'clientTimeout'\n )\n local id = settings[1]\n local maxConcurrent = tonumber(settings[2])\n local running = tonumber(settings[3])\n local reservoir = tonumber(settings[4])\n local reservoirRefreshInterval = tonumber(settings[5])\n local reservoirRefreshAmount = tonumber(settings[6])\n local lastReservoirRefresh = tonumber(settings[7])\n local reservoirIncreaseInterval = tonumber(settings[8])\n local reservoirIncreaseAmount = tonumber(settings[9])\n local reservoirIncreaseMaximum = tonumber(settings[10])\n local lastReservoirIncrease = tonumber(settings[11])\n local capacityPriorityCounter = tonumber(settings[12])\n local clientTimeout = tonumber(settings[13])\n\n local initial_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n --\n -- Process 'running' changes\n --\n local expired = redis.call('zrangebyscore', job_expirations_key, '-inf', '('..now)\n\n if #expired > 0 then\n redis.call('zremrangebyscore', job_expirations_key, '-inf', '('..now)\n\n local flush_batch = function (batch, acc)\n local weights = redis.call('hmget', job_weights_key, unpack(batch))\n redis.call('hdel', job_weights_key, unpack(batch))\n local clients = redis.call('hmget', job_clients_key, unpack(batch))\n redis.call('hdel', job_clients_key, unpack(batch))\n\n -- Calculate sum of removed weights\n for i = 1, #weights do\n acc['total'] = acc['total'] + (tonumber(weights[i]) or 0)\n end\n\n -- Calculate sum of removed weights by client\n local client_weights = {}\n for i = 1, #clients do\n local removed = tonumber(weights[i]) or 0\n if removed > 0 then\n acc['client_weights'][clients[i]] = (acc['client_weights'][clients[i]] or 0) + removed\n end\n end\n end\n\n local acc = {\n ['total'] = 0,\n ['client_weights'] = {}\n }\n local batch_size = 1000\n\n -- Compute changes to Zsets and apply changes to Hashes\n for i = 1, #expired, batch_size do\n local batch = {}\n for j = i, math.min(i + batch_size - 1, #expired) do\n table.insert(batch, expired[j])\n end\n\n flush_batch(batch, acc)\n end\n\n -- Apply changes to Zsets\n if acc['total'] > 0 then\n redis.call('hincrby', settings_key, 'done', acc['total'])\n running = tonumber(redis.call('hincrby', settings_key, 'running', -acc['total']))\n end\n\n for client, weight in pairs(acc['client_weights']) do\n redis.call('zincrby', client_running_key, -weight, client)\n end\n end\n\n --\n -- Process 'reservoir' changes\n --\n local reservoirRefreshActive = reservoirRefreshInterval ~= nil and reservoirRefreshAmount ~= nil\n if reservoirRefreshActive and now >= lastReservoirRefresh + reservoirRefreshInterval then\n reservoir = reservoirRefreshAmount\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirRefresh', now\n )\n end\n\n local reservoirIncreaseActive = reservoirIncreaseInterval ~= nil and reservoirIncreaseAmount ~= nil\n if reservoirIncreaseActive and now >= lastReservoirIncrease + reservoirIncreaseInterval then\n local num_intervals = math.floor((now - lastReservoirIncrease) / reservoirIncreaseInterval)\n local incr = reservoirIncreaseAmount * num_intervals\n if reservoirIncreaseMaximum ~= nil then\n incr = math.min(incr, reservoirIncreaseMaximum - (reservoir or 0))\n end\n if incr > 0 then\n reservoir = (reservoir or 0) + incr\n end\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'lastReservoirIncrease', lastReservoirIncrease + (num_intervals * reservoirIncreaseInterval)\n )\n end\n\n --\n -- Clear unresponsive clients\n --\n local unresponsive = redis.call('zrangebyscore', client_last_seen_key, '-inf', (now - clientTimeout))\n local unresponsive_lookup = {}\n local terminated_clients = {}\n for i = 1, #unresponsive do\n unresponsive_lookup[unresponsive[i]] = true\n if tonumber(redis.call('zscore', client_running_key, unresponsive[i])) == 0 then\n table.insert(terminated_clients, unresponsive[i])\n end\n end\n if #terminated_clients > 0 then\n redis.call('zrem', client_running_key, unpack(terminated_clients))\n redis.call('hdel', client_num_queued_key, unpack(terminated_clients))\n redis.call('zrem', client_last_registered_key, unpack(terminated_clients))\n redis.call('zrem', client_last_seen_key, unpack(terminated_clients))\n end\n\n --\n -- Broadcast capacity changes\n --\n local final_capacity = compute_capacity(maxConcurrent, running, reservoir)\n\n if always_publish or (initial_capacity ~= nil and final_capacity == nil) then\n -- always_publish or was not unlimited, now unlimited\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n\n elseif initial_capacity ~= nil and final_capacity ~= nil and final_capacity > initial_capacity then\n -- capacity was increased\n -- send the capacity message to the limiter having the lowest number of running jobs\n -- the tiebreaker is the limiter having not registered a job in the longest time\n\n local lowest_concurrency_value = nil\n local lowest_concurrency_clients = {}\n local lowest_concurrency_last_registered = {}\n local client_concurrencies = redis.call('zrange', client_running_key, 0, -1, 'withscores')\n\n for i = 1, #client_concurrencies, 2 do\n local client = client_concurrencies[i]\n local concurrency = tonumber(client_concurrencies[i+1])\n\n if (\n lowest_concurrency_value == nil or lowest_concurrency_value == concurrency\n ) and (\n not unresponsive_lookup[client]\n ) and (\n tonumber(redis.call('hget', client_num_queued_key, client)) > 0\n ) then\n lowest_concurrency_value = concurrency\n table.insert(lowest_concurrency_clients, client)\n local last_registered = tonumber(redis.call('zscore', client_last_registered_key, client))\n table.insert(lowest_concurrency_last_registered, last_registered)\n end\n end\n\n if #lowest_concurrency_clients > 0 then\n local position = 1\n local earliest = lowest_concurrency_last_registered[1]\n\n for i,v in ipairs(lowest_concurrency_last_registered) do\n if v < earliest then\n position = i\n earliest = v\n end\n end\n\n local next_client = lowest_concurrency_clients[position]\n redis.call('publish', 'b_'..id,\n 'capacity-priority:'..(final_capacity or '')..\n ':'..next_client..\n ':'..capacityPriorityCounter\n )\n redis.call('hincrby', settings_key, 'capacityPriorityCounter', '1')\n else\n redis.call('publish', 'b_'..id, 'capacity:'..(final_capacity or ''))\n end\n end\n\n return {\n ['capacity'] = final_capacity,\n ['running'] = running,\n ['reservoir'] = reservoir\n }\nend\n", - "queued.lua": "local clientTimeout = tonumber(redis.call('hget', settings_key, 'clientTimeout'))\nlocal valid_clients = redis.call('zrangebyscore', client_last_seen_key, (now - clientTimeout), 'inf')\nlocal client_queued = redis.call('hmget', client_num_queued_key, unpack(valid_clients))\n\nlocal sum = 0\nfor i = 1, #client_queued do\n sum = sum + tonumber(client_queued[i])\nend\n\nreturn sum\n", - "refresh_expiration.lua": "local refresh_expiration = function (now, nextRequest, groupTimeout)\n\n if groupTimeout ~= nil then\n local ttl = (nextRequest + groupTimeout) - now\n\n for i = 1, #KEYS do\n redis.call('pexpire', KEYS[i], ttl)\n end\n end\n\nend\n", - "refs.lua": "local settings_key = KEYS[1]\nlocal job_weights_key = KEYS[2]\nlocal job_expirations_key = KEYS[3]\nlocal job_clients_key = KEYS[4]\nlocal client_running_key = KEYS[5]\nlocal client_num_queued_key = KEYS[6]\nlocal client_last_registered_key = KEYS[7]\nlocal client_last_seen_key = KEYS[8]\n\nlocal now = tonumber(ARGV[1])\nlocal client = ARGV[2]\n\nlocal num_static_argv = 2\n", - "register.lua": "local index = ARGV[num_static_argv + 1]\nlocal weight = tonumber(ARGV[num_static_argv + 2])\nlocal expiration = tonumber(ARGV[num_static_argv + 3])\n\nlocal state = process_tick(now, false)\nlocal capacity = state['capacity']\nlocal reservoir = state['reservoir']\n\nlocal settings = redis.call('hmget', settings_key,\n 'nextRequest',\n 'minTime',\n 'groupTimeout'\n)\nlocal nextRequest = tonumber(settings[1])\nlocal minTime = tonumber(settings[2])\nlocal groupTimeout = tonumber(settings[3])\n\nif conditions_check(capacity, weight) then\n\n redis.call('hincrby', settings_key, 'running', weight)\n redis.call('hset', job_weights_key, index, weight)\n if expiration ~= nil then\n redis.call('zadd', job_expirations_key, now + expiration, index)\n end\n redis.call('hset', job_clients_key, index, client)\n redis.call('zincrby', client_running_key, weight, client)\n redis.call('hincrby', client_num_queued_key, client, -1)\n redis.call('zadd', client_last_registered_key, now, client)\n\n local wait = math.max(nextRequest - now, 0)\n local newNextRequest = now + wait + minTime\n\n if reservoir == nil then\n redis.call('hset', settings_key,\n 'nextRequest', newNextRequest\n )\n else\n reservoir = reservoir - weight\n redis.call('hmset', settings_key,\n 'reservoir', reservoir,\n 'nextRequest', newNextRequest\n )\n end\n\n refresh_expiration(now, newNextRequest, groupTimeout)\n\n return {true, wait, reservoir}\n\nelse\n return {false}\nend\n", - "register_client.lua": "local queued = tonumber(ARGV[num_static_argv + 1])\n\n-- Could have been re-registered concurrently\nif not redis.call('zscore', client_last_seen_key, client) then\n redis.call('zadd', client_running_key, 0, client)\n redis.call('hset', client_num_queued_key, client, queued)\n redis.call('zadd', client_last_registered_key, 0, client)\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n\nreturn {}\n", - "running.lua": "return process_tick(now, false)['running']\n", - "submit.lua": "local queueLength = tonumber(ARGV[num_static_argv + 1])\nlocal weight = tonumber(ARGV[num_static_argv + 2])\n\nlocal capacity = process_tick(now, false)['capacity']\n\nlocal settings = redis.call('hmget', settings_key,\n 'id',\n 'maxConcurrent',\n 'highWater',\n 'nextRequest',\n 'strategy',\n 'unblockTime',\n 'penalty',\n 'minTime',\n 'groupTimeout'\n)\nlocal id = settings[1]\nlocal maxConcurrent = tonumber(settings[2])\nlocal highWater = tonumber(settings[3])\nlocal nextRequest = tonumber(settings[4])\nlocal strategy = tonumber(settings[5])\nlocal unblockTime = tonumber(settings[6])\nlocal penalty = tonumber(settings[7])\nlocal minTime = tonumber(settings[8])\nlocal groupTimeout = tonumber(settings[9])\n\nif maxConcurrent ~= nil and weight > maxConcurrent then\n return redis.error_reply('OVERWEIGHT:'..weight..':'..maxConcurrent)\nend\n\nlocal reachedHWM = (highWater ~= nil and queueLength == highWater\n and not (\n conditions_check(capacity, weight)\n and nextRequest - now <= 0\n )\n)\n\nlocal blocked = strategy == 3 and (reachedHWM or unblockTime >= now)\n\nif blocked then\n local computedPenalty = penalty\n if computedPenalty == nil then\n if minTime == 0 then\n computedPenalty = 5000\n else\n computedPenalty = 15 * minTime\n end\n end\n\n local newNextRequest = now + computedPenalty + minTime\n\n redis.call('hmset', settings_key,\n 'unblockTime', now + computedPenalty,\n 'nextRequest', newNextRequest\n )\n\n local clients_queued_reset = redis.call('hkeys', client_num_queued_key)\n local queued_reset = {}\n for i = 1, #clients_queued_reset do\n table.insert(queued_reset, clients_queued_reset[i])\n table.insert(queued_reset, 0)\n end\n redis.call('hmset', client_num_queued_key, unpack(queued_reset))\n\n redis.call('publish', 'b_'..id, 'blocked:')\n\n refresh_expiration(now, newNextRequest, groupTimeout)\nend\n\nif not blocked and not reachedHWM then\n redis.call('hincrby', client_num_queued_key, client, 1)\nend\n\nreturn {reachedHWM, blocked, strategy}\n", - "update_settings.lua": "local args = {'hmset', settings_key}\n\nfor i = num_static_argv + 1, #ARGV do\n table.insert(args, ARGV[i])\nend\n\nredis.call(unpack(args))\n\nprocess_tick(now, true)\n\nlocal groupTimeout = tonumber(redis.call('hget', settings_key, 'groupTimeout'))\nrefresh_expiration(0, 0, groupTimeout)\n\nreturn {}\n", - "validate_client.lua": "if not redis.call('zscore', client_last_seen_key, client) then\n return redis.error_reply('UNKNOWN_CLIENT')\nend\n\nredis.call('zadd', client_last_seen_key, now, client)\n", - "validate_keys.lua": "if not (redis.call('exists', settings_key) == 1) then\n return redis.error_reply('SETTINGS_KEY_NOT_FOUND')\nend\n" - }; +init_esm(); +init_esm4(); +init_functions(); +init_esm(); +init_esm4(); +var NOTIFICATION_TYPE = Object.freeze({ + ENTRY: "entry", + DELETION: "deletion", + KV: "kv", + KV_FILTER: "kv_filter", + PING: "ping", + PONG: "pong", + PUB: "pub", + SUB: "sub", + UNSUB: "unsub", + VERSION_INFO: "version_info" +}); +var REQUEST_TYPE = Object.freeze({ + PUB: "pub", + SUB: "sub", + UNSUB: "unsub", + PUSH_ACTION: "push_action", + KV_FILTER: "kv_filter" +}); +var RESPONSE_TYPE = Object.freeze({ + ERROR: "error", + OK: "ok" +}); +var PUSH_SERVER_ACTION_TYPE = Object.freeze({ + SEND_PUBLIC_KEY: "send-public-key", + STORE_SUBSCRIPTION: "store-subscription", + DELETE_SUBSCRIPTION: "delete-subscription", + SEND_PUSH_NOTIFICATION: "send-push-notification" +}); +var defaultOptions = { + logPingMessages: !process.env.CI, + pingTimeout: 45e3, + maxReconnectionDelay: 6e4, + maxRetries: 10, + minReconnectionDelay: 500, + reconnectOnDisconnection: true, + reconnectOnOnline: true, + // Defaults to false to avoid reconnection attempts in case the server doesn't + // respond because of a failed authentication. + reconnectOnTimeout: false, + reconnectionDelayGrowFactor: 2, + timeout: 6e4, + maxOpRetries: 4, + opRetryInterval: 2e3 +}; +var PUBSUB_ERROR = "pubsub-error"; +var PUBSUB_RECONNECTION_ATTEMPT = "pubsub-reconnection-attempt"; +var PUBSUB_RECONNECTION_FAILED = "pubsub-reconnection-failed"; +var PUBSUB_RECONNECTION_SCHEDULED = "pubsub-reconnection-scheduled"; +var PUBSUB_RECONNECTION_SUCCEEDED = "pubsub-reconnection-succeeded"; +var PUBSUB_SUBSCRIPTION_SUCCEEDED = "pubsub-subscription-succeeded"; +var TieredMap = class extends Map { + tGet(k1, k2) { + return this.get(k1)?.get(k2); + } + tHas(k1, k2) { + return !!this.get(k1)?.has(k2); + } + tSet(k1, k2, v2) { + let submap = this.get(k1); + if (!submap) { + submap = /* @__PURE__ */ new Map(); + this.set(k1, submap); + } + return submap.set(k2, v2); + } + tDelete(k1, k2) { + const submap = this.get(k1); + if (submap) { + const result = submap.delete(k2); + if (submap.size === 0) { + this.delete(k1); + } + return result; + } + return false; } -}); -var require_Scripts = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Scripts.js"(exports2) { - "use strict"; - var headers; - var lua; - var templates; - lua = require_lua(); - headers = { - refs: lua["refs.lua"], - validate_keys: lua["validate_keys.lua"], - validate_client: lua["validate_client.lua"], - refresh_expiration: lua["refresh_expiration.lua"], - process_tick: lua["process_tick.lua"], - conditions_check: lua["conditions_check.lua"], - get_time: lua["get_time.lua"] - }; - exports2.allKeys = function(id) { - return [ - /* - HASH - */ - `b_${id}_settings`, - /* - HASH - job index -> weight - */ - `b_${id}_job_weights`, - /* - ZSET - job index -> expiration - */ - `b_${id}_job_expirations`, - /* - HASH - job index -> client - */ - `b_${id}_job_clients`, - /* - ZSET - client -> sum running - */ - `b_${id}_client_running`, - /* - HASH - client -> num queued - */ - `b_${id}_client_num_queued`, - /* - ZSET - client -> last job registered - */ - `b_${id}_client_last_registered`, - /* - ZSET - client -> last seen - */ - `b_${id}_client_last_seen` - ]; - }; - templates = { - init: { - keys: exports2.allKeys, - headers: ["process_tick"], - refresh_expiration: true, - code: lua["init.lua"] - }, - group_check: { - keys: exports2.allKeys, - headers: [], - refresh_expiration: false, - code: lua["group_check.lua"] - }, - register_client: { - keys: exports2.allKeys, - headers: ["validate_keys"], - refresh_expiration: false, - code: lua["register_client.lua"] - }, - blacklist_client: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client"], - refresh_expiration: false, - code: lua["blacklist_client.lua"] - }, - heartbeat: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["heartbeat.lua"] - }, - update_settings: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["update_settings.lua"] - }, - running: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["running.lua"] - }, - queued: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client"], - refresh_expiration: false, - code: lua["queued.lua"] - }, - done: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["done.lua"] - }, - check: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: false, - code: lua["check.lua"] - }, - submit: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: true, - code: lua["submit.lua"] - }, - register: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick", "conditions_check"], - refresh_expiration: true, - code: lua["register.lua"] - }, - free: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["free.lua"] - }, - current_reservoir: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: false, - code: lua["current_reservoir.lua"] - }, - increment_reservoir: { - keys: exports2.allKeys, - headers: ["validate_keys", "validate_client", "process_tick"], - refresh_expiration: true, - code: lua["increment_reservoir.lua"] + tClear(k1) { + this.delete(k1); + } +}; +var isKvFilterFresh = (ourKvFilter, theirKvFilter) => { + if (!ourKvFilter !== !theirKvFilter) { + return false; + } else if (ourKvFilter && theirKvFilter) { + if (ourKvFilter.length !== theirKvFilter.length) { + return false; + } else { + const sortedA = [...ourKvFilter].sort(); + const sortedB = [...theirKvFilter].sort(); + for (let i2 = 0; i2 < sortedA.length; i2++) { + if (sortedA[i2] !== sortedB[i2]) { + return false; + } } - }; - exports2.names = Object.keys(templates); - exports2.keys = function(name, id) { - return templates[name].keys(id); - }; - exports2.payload = function(name) { - var template; - template = templates[name]; - return Array.prototype.concat(headers.refs, template.headers.map(function(h2) { - return headers[h2]; - }), template.refresh_expiration ? headers.refresh_expiration : "", template.code).join("\n"); - }; + } } -}); -var require_RedisConnection = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisConnection.js"(exports, module) { - "use strict"; - function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { + return true; +}; +var pubPayloadFactory = (client, channelID) => () => { + const kvFilter = client.kvFilter.get(channelID); + return kvFilter ? { kvFilter, channelID } : { channelID }; +}; +function runWithRetry(client, channelID, type, getPayload) { + let attemptNo = 0; + const { socket, options: options2 } = client; + const instance = {}; + client.pendingOperations.tSet(type, channelID, instance); + const send = () => { + if (client.socket !== socket || socket?.readyState !== WebSocket.OPEN) + return; + const currentInstance = client.pendingOperations.tGet(type, channelID); + if (currentInstance !== instance) + return; + if (attemptNo++ > options2.maxOpRetries) { + console.warn(`[pubsub] Giving up ${type} for channel`, channelID); + client.pendingOperations.tDelete(type, channelID); + return; + } + const payload = getPayload(); + socket.send(createRequest(type, payload)); + const minDelay = (attemptNo - 1) * options2.opRetryInterval; + const jitter = randomIntFromRange(0, options2.opRetryInterval); + const delay2 = Math.min(200, minDelay) + jitter; + setTimeout(send, delay2); + }; + send(); +} +function createClient(url2, options2 = {}) { + const client = { + customEventHandlers: options2.handlers || {}, + // The current number of connection attempts that failed. + // Reset to 0 upon successful connection. + // Used to compute how long to wait before the next reconnection attempt. + failedConnectionAttempts: 0, + isLocal: /\/\/(localhost|127\.0\.0\.1)([:?/]|$)/.test(url2), + // True if this client has never been connected yet. + isNew: true, + listeners: /* @__PURE__ */ Object.create(null), + messageHandlers: { ...defaultMessageHandlers, ...options2.messageHandlers }, + nextConnectionAttemptDelayID: void 0, + options: { ...defaultOptions, ...options2 }, + pendingOperations: new TieredMap(), + pingTimeoutID: void 0, + shouldReconnect: true, + // The underlying WebSocket object. + // A new one is necessary for every connection or reconnection attempt. + socket: null, + subscriptionSet: /* @__PURE__ */ new Set(), + kvFilter: /* @__PURE__ */ new Map(), + connectionTimeoutID: void 0, + url: url2.replace(/^http/, "ws"), + ...publicMethods + }; + for (const name of Object.keys(defaultClientEventHandlers)) { + client.listeners[name] = (event) => { try { - var info = gen[key](arg); - var value = info.value; + defaultClientEventHandlers[name].call(client, event); + client.customEventHandlers[name]?.call(client, event); } catch (error2) { - reject(error2); - return; + esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, error2?.message); } - if (info.done) { - resolve82(value); + }; + } + if (typeof self === "object" && self instanceof EventTarget) { + for (const name of globalEventNames) { + globalEventMap.set(name, client.listeners[name]); + } + } + if (!client.options.manual) { + client.connect(); + } + return client; +} +function createMessage(type, data, meta) { + const message = { ...meta, type, data }; + let string3; + const stringify2 = function() { + if (!string3) + string3 = JSON.stringify(this); + return string3; + }; + Object.defineProperties(message, { + [Symbol.toPrimitive]: { + value: stringify2 + } + }); + return message; +} +function createKvMessage(channelID, key, data) { + return JSON.stringify({ type: NOTIFICATION_TYPE.KV, channelID, key, data }); +} +function createPubMessage(channelID, data) { + return JSON.stringify({ type: NOTIFICATION_TYPE.PUB, channelID, data }); +} +function createRequest(type, data) { + return JSON.stringify(Object.assign({ type }, data)); +} +var defaultClientEventHandlers = { + // Emitted when the connection is closed. + close(event) { + const client = this; + console.debug("[pubsub] Event: close", event.code, event.reason); + client.failedConnectionAttempts++; + if (client.socket) { + for (const name of socketEventNames) { + client.socket.removeEventListener(name, client.listeners[name]); + } + } + client.socket = null; + client.clearAllTimers(); + if (client.shouldReconnect) { + const pendingSubscriptionMap = client.pendingOperations.get(REQUEST_TYPE.SUB); + if (pendingSubscriptionMap) { + for (const [channelID] of pendingSubscriptionMap) { + pendingSubscriptionMap.set(channelID, {}); + } + } + client.subscriptionSet.forEach((channelID) => { + if (!client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { + client.pendingOperations.tSet(REQUEST_TYPE.SUB, channelID, {}); + } + }); + } + client.subscriptionSet.clear(); + client.pendingOperations.tClear(REQUEST_TYPE.UNSUB); + client.pendingOperations.tClear(REQUEST_TYPE.KV_FILTER); + if (client.shouldReconnect && client.options.reconnectOnDisconnection) { + if (client.failedConnectionAttempts > client.options.maxRetries) { + esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_FAILED, client); } else { - Promise.resolve(value).then(_next, _throw); + if (!isDefinetelyOffline() || client.isLocal) { + client.scheduleConnectionAttempt(); + } } } - function _asyncToGenerator(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; + }, + // Emitted when an error has occured. + // The socket will be closed automatically by the engine if necessary. + error(event) { + const client = this; + console.warn("[pubsub] Event: error", event); + clearTimeout(client.pingTimeoutID); + }, + // Emitted when a message is received. + // The connection will be terminated if the message is malformed or has an + // unexpected data type (e.g. binary instead of text). + message(event) { + const client = this; + const { data } = event; + if (typeof data !== "string") { + esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, { + message: `Wrong data type: ${typeof data}` + }); + return client.destroy(); } - var Events; - var RedisConnection; - var Scripts; - var parser; - parser = require_parser2(); - Events = require_Events(); - Scripts = require_Scripts(); - RedisConnection = function() { - class RedisConnection { - constructor(options = {}) { - parser.load(options, this.defaults, this); - if (this.Redis == null) { - this.Redis = eval("require")("redis"); - } - if (this.Events == null) { - this.Events = new Events(this); - } - this.terminated = false; - if (this.client == null) { - this.client = this.Redis.createClient(this.clientOptions); + let msg = { type: "" }; + try { + msg = messageParser(data); + } catch (error2) { + esm_default("okTurtles.events/emit", PUBSUB_ERROR, client, { + message: `Malformed message: ${error2?.message}` + }); + return client.destroy(); + } + const handler = client.messageHandlers[msg.type]; + if (handler) { + handler.call(client, msg); + } else { + throw new Error(`Unhandled message type: ${msg.type}`); + } + }, + offline() { + console.info("[pubsub] Event: offline"); + const client = this; + client.clearAllTimers(); + client.failedConnectionAttempts = 0; + client.socket?.close(); + }, + online() { + console.info("[pubsub] Event: online"); + const client = this; + if (client.options.reconnectOnOnline && client.shouldReconnect) { + if (!client.socket) { + client.failedConnectionAttempts = 0; + client.scheduleConnectionAttempt(); + } + } + }, + // Emitted when the connection is established. + open() { + console.debug("[pubsub] Event: open"); + const client = this; + const { options: options2 } = this; + client.connectionTimeUsed = void 0; + client.clearAllTimers(); + esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_SUCCEEDED, client); + client.failedConnectionAttempts = -1; + client.isNew = false; + if (options2.pingTimeout > 0 && options2.pingTimeout < Infinity) { + client.pingTimeoutID = setTimeout(() => { + client.socket?.close(); + }, options2.pingTimeout); + } + for (const [channelID] of client.pendingOperations.get(REQUEST_TYPE.SUB) || []) { + runWithRetry(client, channelID, REQUEST_TYPE.SUB, pubPayloadFactory(client, channelID)); + } + }, + "reconnection-attempt"() { + console.info("[pubsub] Trying to reconnect..."); + }, + "reconnection-succeeded"() { + console.info("[pubsub] Connection re-established"); + }, + "reconnection-failed"() { + console.warn("[pubsub] Reconnection failed"); + const client = this; + client.destroy(); + }, + "reconnection-scheduled"(event) { + const { delay: delay2, nth } = event.detail; + console.info(`[pubsub] Scheduled connection attempt ${nth} in ~${delay2} ms`); + }, + "subscription-succeeded"(event) { + const { channelID } = event.detail; + console.debug(`[pubsub] Subscribed to channel ${channelID}`); + } +}; +var defaultMessageHandlers = { + [NOTIFICATION_TYPE.ENTRY](msg) { + console.debug("[pubsub] Received ENTRY:", msg); + }, + [NOTIFICATION_TYPE.PING]({ data }) { + const client = this; + if (client.options.logPingMessages) { + console.debug(`[pubsub] Ping received in ${Date.now() - Number(data)} ms`); + } + client.socket?.send(createMessage(NOTIFICATION_TYPE.PONG, data)); + clearTimeout(client.pingTimeoutID); + client.pingTimeoutID = setTimeout(() => { + client.socket?.close(); + }, client.options.pingTimeout); + }, + [NOTIFICATION_TYPE.PUB]({ channelID, data }) { + console.log(`[pubsub] Received data from channel ${channelID}:`, data); + }, + [NOTIFICATION_TYPE.KV]({ channelID, key, data }) { + console.log(`[pubsub] Received KV update from channel ${channelID} ${key}:`, data); + }, + [NOTIFICATION_TYPE.SUB](msg) { + console.debug(`[pubsub] Ignoring ${msg.type} message:`, msg.data); + }, + [NOTIFICATION_TYPE.UNSUB](msg) { + console.debug(`[pubsub] Ignoring ${msg.type} message:`, msg.data); + }, + [RESPONSE_TYPE.ERROR]({ data }) { + const { type, channelID, reason } = data; + console.warn(`[pubsub] Received ERROR response for ${type} request to ${channelID}`); + const client = this; + switch (type) { + case REQUEST_TYPE.SUB: { + console.warn(`[pubsub] Could not subscribe to ${channelID}: ${reason}`); + client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); + break; + } + case REQUEST_TYPE.UNSUB: { + console.warn(`[pubsub] Could not unsubscribe from ${channelID}: ${reason}`); + client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); + break; + } + case REQUEST_TYPE.PUSH_ACTION: { + const { actionType, message } = data; + console.warn(`[pubsub] Received ERROR for PUSH_ACTION request with the action type '${actionType}' and the following message: ${message}`); + break; + } + case REQUEST_TYPE.KV_FILTER: { + console.warn(`[pubsub] Could not set KV filter for ${channelID}: ${reason}`); + client.pendingOperations.tDelete(REQUEST_TYPE.KV_FILTER, channelID); + break; + } + default: { + console.error(`[pubsub] Malformed response: invalid request type ${type}`); + } + } + }, + [RESPONSE_TYPE.OK]({ data: { type, channelID, kvFilter } }) { + const client = this; + switch (type) { + case REQUEST_TYPE.SUB: { + if (client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID)) { + client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); + client.subscriptionSet.add(channelID); + esm_default("okTurtles.events/emit", PUBSUB_SUBSCRIPTION_SUCCEEDED, client, { channelID }); + const ourKvFilter = client.kvFilter.get(channelID); + if (!isKvFilterFresh(ourKvFilter, kvFilter)) { + console.debug(`[pubsub] Subscribed to ${channelID}, need to set new KV filter`); + this.setKvFilter(channelID, ourKvFilter); } - this.subscriber = this.client.duplicate(); - this.limiters = {}; - this.shas = {}; - this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { - return this._loadScripts(); - }).then(() => { - return { - client: this.client, - subscriber: this.subscriber - }; - }); - } - _setup(client, sub) { - client.setMaxListeners(0); - return new this.Promise((resolve82, reject) => { - client.on("error", (e2) => { - return this.Events.trigger("error", e2); - }); - if (sub) { - client.on("message", (channel, message) => { - var ref; - return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; - }); - } - if (client.ready) { - return resolve82(); - } else { - return client.once("ready", resolve82); - } - }); - } - _loadScript(name) { - return new this.Promise((resolve82, reject) => { - var payload; - payload = Scripts.payload(name); - return this.client.multi([["script", "load", payload]]).exec((err, replies) => { - if (err != null) { - return reject(err); - } - this.shas[name] = replies[0]; - return resolve82(replies[0]); - }); - }); + } else { + console.debug(`[pubsub] Received unexpected sub for ${channelID}`); } - _loadScripts() { - return this.Promise.all(Scripts.names.map((k) => { - return this._loadScript(k); - })); + break; + } + case REQUEST_TYPE.UNSUB: { + if (client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { + console.debug(`[pubsub] Unsubscribed from ${channelID}`); + client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); + client.subscriptionSet.delete(channelID); + } else { + console.debug(`[pubsub] Received unexpected unsub for ${channelID}`); } - __runCommand__(cmd) { - var _this = this; - return _asyncToGenerator(function* () { - yield _this.ready; - return new _this.Promise((resolve82, reject) => { - return _this.client.multi([cmd]).exec_atomic(function(err, replies) { - if (err != null) { - return reject(err); - } else { - return resolve82(replies[0]); - } - }); - }); - })(); + break; + } + case REQUEST_TYPE.KV_FILTER: { + if (client.pendingOperations.tHas(REQUEST_TYPE.KV_FILTER, channelID)) { + const ourKvFilter = client.kvFilter.get(channelID); + if (isKvFilterFresh(ourKvFilter, kvFilter)) { + console.debug(`[pubsub] Set KV filter for ${channelID}`, kvFilter); + client.pendingOperations.tDelete(REQUEST_TYPE.KV_FILTER, channelID); + } else { + console.debug(`[pubsub] Received stale KV filter ack for ${channelID}`, kvFilter, ourKvFilter); + } + } else { + console.debug(`[pubsub] Received unexpected kv-filter for ${channelID}`); } - __addLimiter__(instance) { - return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { - return new this.Promise((resolve82, reject) => { - var handler; - handler = (chan) => { - if (chan === channel) { - this.subscriber.removeListener("subscribe", handler); - this.limiters[channel] = instance; - return resolve82(); - } - }; - this.subscriber.on("subscribe", handler); - return this.subscriber.subscribe(channel); - }); - })); - } - __removeLimiter__(instance) { - var _this2 = this; - return this.Promise.all([instance.channel(), instance.channel_client()].map( - /* @__PURE__ */ function() { - var _ref = _asyncToGenerator(function* (channel) { - if (!_this2.terminated) { - yield new _this2.Promise((resolve82, reject) => { - return _this2.subscriber.unsubscribe(channel, function(err, chan) { - if (err != null) { - return reject(err); - } - if (chan === channel) { - return resolve82(); - } - }); - }); - } - return delete _this2.limiters[channel]; - }); - return function(_x) { - return _ref.apply(this, arguments); - }; - }() - )); - } - __scriptArgs__(name, id, args, cb) { - var keys; - keys = Scripts.keys(name, id); - return [this.shas[name], keys.length].concat(keys, args, cb); - } - __scriptFn__(name) { - return this.client.evalsha.bind(this.client); - } - disconnect(flush = true) { - var i2, k, len, ref; - ref = Object.keys(this.limiters); - for (i2 = 0, len = ref.length; i2 < len; i2++) { - k = ref[i2]; - clearInterval(this.limiters[k]._store.heartbeat); - } - this.limiters = {}; - this.terminated = true; - this.client.end(flush); - this.subscriber.end(flush); - return this.Promise.resolve(); + break; + } + default: { + console.error(`[pubsub] Malformed response: invalid request type ${type}`); + } + } + } +}; +var globalEventNames = ["offline", "online"]; +var socketEventNames = ["close", "error", "message", "open"]; +var globalEventMap = /* @__PURE__ */ new Map(); +if (typeof self === "object" && self instanceof EventTarget) { + for (const name of globalEventNames) { + const handler = (ev) => { + const h2 = globalEventMap.get(name); + return h2?.(ev); + }; + self.addEventListener(name, handler, false); + } +} +var isDefinetelyOffline = () => typeof navigator === "object" && navigator.onLine === false; +var messageParser = (data) => { + const msg = JSON.parse(data); + if (typeof msg !== "object" || msg === null) { + throw new TypeError("Message is null or not an object"); + } + const { type } = msg; + if (typeof type !== "string" || type === "") { + throw new TypeError("Message type must be a non-empty string"); + } + return msg; +}; +var publicMethods = { + clearAllTimers() { + const client = this; + clearTimeout(client.connectionTimeoutID); + clearTimeout(client.nextConnectionAttemptDelayID); + clearTimeout(client.pingTimeoutID); + client.connectionTimeoutID = void 0; + client.nextConnectionAttemptDelayID = void 0; + client.pingTimeoutID = void 0; + }, + // Performs a connection or reconnection attempt. + connect() { + const client = this; + if (client.socket !== null) { + throw new Error("connect() can only be called if there is no current socket."); + } + if (client.nextConnectionAttemptDelayID) { + throw new Error("connect() must not be called during a reconnection delay."); + } + if (!client.shouldReconnect) { + throw new Error("connect() should no longer be called on this instance."); + } + client.socket = new WebSocket(client.url); + client.socket.send = function(data) { + const send = WebSocket.prototype.send.bind(this); + if (typeof data === "object" && typeof data[Symbol.toPrimitive] === "function") { + return send(data[Symbol.toPrimitive]()); + } + return send(data); + }; + if (client.options.timeout) { + const start = performance.now(); + client.connectionTimeoutID = setTimeout(() => { + client.connectionTimeoutID = void 0; + if (client.options.reconnectOnTimeout) { + client.connectionTimeUsed = performance.now() - start; } + client.socket?.close(4e3, "timeout"); + }, client.options.timeout); + } + for (const name of socketEventNames) { + client.socket.addEventListener(name, client.listeners[name]); + } + }, + /** + * Immediately close the socket, stop listening for events and clear any cache. + * + * This method is used in unit tests. + * - In particular, no 'close' event handler will be called. + * - Any incoming or outgoing buffered data will be discarded. + * - Any pending messages will be discarded. + */ + destroy() { + const client = this; + client.clearAllTimers(); + client.pendingOperations.clear(); + client.subscriptionSet.clear(); + if (typeof self === "object" && self instanceof EventTarget) { + for (const name of globalEventNames) { + globalEventMap.delete(name); } - ; - RedisConnection.prototype.datastore = "redis"; - RedisConnection.prototype.defaults = { - Redis: null, - clientOptions: {}, - client: null, - Promise, - Events: null - }; - return RedisConnection; - }.call(void 0); - module.exports = RedisConnection; + } + if (client.socket) { + for (const name of socketEventNames) { + client.socket.removeEventListener(name, client.listeners[name]); + } + client.socket.close(); + } + client.listeners = /* @__PURE__ */ Object.create(null); + client.socket = null; + client.shouldReconnect = false; + }, + getNextRandomDelay() { + const client = this; + const { maxReconnectionDelay, minReconnectionDelay, reconnectionDelayGrowFactor } = client.options; + const minDelay = minReconnectionDelay * reconnectionDelayGrowFactor ** client.failedConnectionAttempts; + const maxDelay = minDelay * reconnectionDelayGrowFactor; + const connectionTimeUsed = client.connectionTimeUsed; + client.connectionTimeUsed = void 0; + return Math.min( + // See issue #1943: Have the connection time used 'eat into' the + // reconnection time used + Math.max(minReconnectionDelay, connectionTimeUsed ? maxReconnectionDelay - connectionTimeUsed : maxReconnectionDelay), + Math.round(minDelay + (0, Math.random)() * (maxDelay - minDelay)) + ); + }, + // Schedules a connection attempt to happen after a delay computed according to + // a randomized exponential backoff algorithm variant. + scheduleConnectionAttempt() { + const client = this; + if (!client.shouldReconnect) { + throw new Error("Cannot call `scheduleConnectionAttempt()` when `shouldReconnect` is false."); + } + if (client.nextConnectionAttemptDelayID) { + return console.warn("[pubsub] A reconnection attempt is already scheduled."); + } + const delay2 = client.getNextRandomDelay(); + const nth = client.failedConnectionAttempts + 1; + client.nextConnectionAttemptDelayID = setTimeout(() => { + esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_ATTEMPT, client); + client.nextConnectionAttemptDelayID = void 0; + client.connect(); + }, delay2); + esm_default("okTurtles.events/emit", PUBSUB_RECONNECTION_SCHEDULED, client, { delay: delay2, nth }); + }, + // Can be used to send ephemeral messages outside of any contract log. + // Does nothing if the socket is not in the OPEN state. + pub(channelID, data) { + if (this.socket?.readyState === WebSocket.OPEN) { + this.socket.send(createPubMessage(channelID, data)); + } + }, + /** + * Sends a SUB request to the server as soon as possible. + * + * - The given channel ID will be cached until we get a relevant server + * response, allowing us to resend the same request if necessary. + * - Any identical UNSUB request that has not been sent yet will be cancelled. + * - Calling this method again before the server has responded has no effect. + * @param channelID - The ID of the channel whose updates we want to subscribe to. + */ + sub(channelID) { + const client = this; + if (!client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID) && !client.subscriptionSet.has(channelID)) { + client.pendingOperations.tDelete(REQUEST_TYPE.UNSUB, channelID); + runWithRetry(client, channelID, REQUEST_TYPE.SUB, pubPayloadFactory(client, channelID)); + } + }, + /** + * Sends a KV_FILTER request to the server as soon as possible. + */ + setKvFilter(channelID, kvFilter) { + const client = this; + if (kvFilter) { + client.kvFilter.set(channelID, kvFilter); + } else { + client.kvFilter.delete(channelID); + } + if (client.subscriptionSet.has(channelID) && !client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID)) { + runWithRetry(client, channelID, REQUEST_TYPE.KV_FILTER, pubPayloadFactory(client, channelID)); + } + }, + /** + * Sends an UNSUB request to the server as soon as possible. + * + * - The given channel ID will be cached until we get a relevant server + * response, allowing us to resend the same request if necessary. + * - Any identical SUB request that has not been sent yet will be cancelled. + * - Calling this method again before the server has responded has no effect. + * @param channelID - The ID of the channel whose updates we want to unsubscribe from. + */ + unsub(channelID) { + const client = this; + if (!client.pendingOperations.tHas(REQUEST_TYPE.UNSUB, channelID) && (client.subscriptionSet.has(channelID) || client.pendingOperations.tHas(REQUEST_TYPE.SUB, channelID))) { + client.pendingOperations.tDelete(REQUEST_TYPE.SUB, channelID); + client.kvFilter.delete(channelID); + runWithRetry(client, channelID, REQUEST_TYPE.UNSUB, () => ({ channelID })); + } + } +}; +for (const name of Object.keys(defaultClientEventHandlers)) { + if (name === "error" || !socketEventNames.includes(name)) { + esm_default("okTurtles.events/on", `pubsub-${name}`, (target, detail) => { + const ev = new CustomEvent(name, { detail }); + target.listeners[name].call(target, ev); + }); + } +} +init_esm6(); +init_errors3(); +var CHELONIA_RESET = "chelonia-reset"; +var CONTRACT_IS_SYNCING = "contract-is-syncing"; +var CONTRACTS_MODIFIED = "contracts-modified"; +var EVENT_HANDLED = "event-handled"; +var EVENT_PUBLISHED = "event-published"; +var EVENT_PUBLISHING_ERROR = "event-publishing-error"; +var CONTRACT_REGISTERED = "contract-registered"; +var CONTRACT_IS_PENDING_KEY_REQUESTS = "contract-is-pending-key-requests"; +var CONTRACT_HAS_RECEIVED_KEYS = "contract-has-received-keys"; +var PERSISTENT_ACTION_FAILURE = "persistent-action-failure"; +var PERSISTENT_ACTION_SUCCESS = "persistent-action-success"; +var PERSISTENT_ACTION_TOTAL_FAILURE = "persistent-action-total_failure"; +init_SPMessage(); +init_esm(); +var chelonia_utils_default = esm_default("sbp/selectors/register", { + // This selector is a wrapper for the `chelonia/kv/set` selector that uses + // the contract queue and allows referring to keys by name, with default key + // names set to `csk` and `cek` for signatures and encryption, respectively. + // For most 'simple' use cases, this selector is a better choice than + // `chelonia/kv/set`. However, the `chelonia/kv/set` primitive is needed if + // the queueing logic needs to be more advanced, the key to use requires + // custom logic or _if the `onconflict` callback also needs to be queued_. + "chelonia/kv/queuedSet": ({ contractID, key, data, onconflict, ifMatch, encryptionKeyName = "cek", signingKeyName = "csk" }) => { + return esm_default("chelonia/queueInvocation", contractID, () => { + return esm_default("chelonia/kv/set", contractID, key, data, { + ifMatch, + encryptionKeyId: esm_default("chelonia/contract/currentKeyIdByName", contractID, encryptionKeyName), + signingKeyId: esm_default("chelonia/contract/currentKeyIdByName", contractID, signingKeyName), + onconflict + }); + }); } }); -var require_IORedisConnection = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/IORedisConnection.js"(exports, module) { - "use strict"; - function _slicedToArray(arr, i2) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i2) || _nonIterableRest(); +init_encryptedData(); +var m = /;\s*boundary=(?:"([0-9a-zA-Z'()+_,\-./:=? ]{0,69}[0-9a-zA-Z'()+_,\-./:=?])"|([0-9a-zA-Z'+_\-.]{0,69}[0-9a-zA-Z'+_\-.]))/; +var M = (a) => new ReadableStream({ pull(r) { + if (ArrayBuffer.isView(a)) r.enqueue(a.buffer.slice(a.byteOffset, a.byteOffset + a.byteLength)); + else if (a instanceof ArrayBuffer) r.enqueue(a); + else throw new TypeError("Expected ArrayBuffer or an ArrayBuffer view."); + r.close(); +} }); +var u = M; +var T = /;\s*boundary=(?:"([^"]+)"|([^;",]+))/; +var h = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-."; +var A = () => { + let a = new Uint8Array(24); + return globalThis.crypto.getRandomValues(a), Array.from(a).map((s) => h[s % h.length]).join(""); +}; +var i = { preventClose: true }; +async function* g(a, s, r) { + let d = new TextEncoder(), y = d.encode(`\r +--${a}`); + if (Array.isArray(s) && s.length < 1) { + await r.abort(Error("At least one part is required")); + return; + } + let l = 0; + for await (let e2 of s) { + l++; + let n, t; + if (!e2.body && e2.parts) if (t = e2.headers.get("content-type"), !t) n = A(), t = `multipart/mixed; boundary="${n}"`; + else if (!t.startsWith("multipart/") || !T.test(t)) { + await r.abort(Error("Invalid multipart content type: " + t)); + return; + } else { + let o2 = t.match(m); + (!o2 || !(n = o2[1] || o2[2])) && (n = A(), t = t.replace(T, `; boundary="${n}"`)); } - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); + await u(y).pipeTo(r, i), yield; + { + let o2 = [""]; + if (t) { + let p = false; + e2.headers.forEach((f, c) => { + c !== "content-type" ? o2.push(`${c}: ${f}`) : (p = true, o2.push(`${c}: ${t}`)); + }), p || o2.push(`content-type: ${t}`); + } else e2.headers.forEach((p, f) => { + o2.push(`${f}: ${p}`); + }); + e2.parts || !e2.body ? o2.push("") : o2.push("", ""); + let B3 = d.encode(o2.join(`\r +`)); + o2.length = 0, await u(B3).pipeTo(r, i), yield; } - function _iterableToArrayLimit(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; + if (e2.body) { + if (e2.body instanceof ArrayBuffer || ArrayBuffer.isView(e2.body)) await u(e2.body).pipeTo(r, i); + else if (e2.body instanceof Blob) await e2.body.stream().pipeTo(r, i); + else if (e2.body instanceof ReadableStream) await e2.body.pipeTo(r, i); + else { + await r.abort(Error("Invalid body type")); + return; + } + yield; + } else if (e2.parts) { + if (!n) { + await r.abort(Error("Runtime exception: undefined part boundary")); + return; + } + yield* g(n, e2.parts, r), yield; + } + } + if (!l) { + await r.abort(Error("At least one part is required")); + return; + } + let b = d.encode(`\r +--${a}--`); + await u(b).pipeTo(r, i); +} +var w = (a, s) => { + let r = new TransformStream(), d = g(a, s, r.writable), y = false, l = r.readable.getReader(); + return new ReadableStream({ start(e2) { + (async () => { + for (; ; ) try { + let n = await l.read(); + if (n.done) { + let t = new Uint8Array([13, 10]); + e2.enqueue(t.buffer.slice(t.byteOffset, t.byteOffset + t.byteLength)), e2.close(); + return; } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + e2.enqueue(n.value); + } catch (n) { + e2.error(n); + return; + } + })().catch(() => { + }); + }, async pull() { + if (y) return; + (await d.next()).done && (y = true, await r.writable.close()); + } }); +}; +var x = w; +var v = async (n, T2, w3, L) => { + let u2 = await globalThis.crypto.subtle.importKey("raw", T2, "HKDF", false, ["deriveKey", "deriveBits"]), d = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: n.cek_info, salt: w3 }, u2, n.params, false, L), A2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: n.nonce_info, salt: w3 }, u2, n.nonce_length << 3); + return [d, function* () { + let s = new ArrayBuffer(n.nonce_length), e2 = new DataView(s), y = new Uint8Array(s), i2 = new Uint8Array(A2), b = 4294967295, f = (n.nonce_length >> 2) - 1, l = new Array(f).fill(0); + for (; ; ) { + for (let a = 0; a <= b; a++) { + e2.setUint32(e2.byteLength - 4, a, false); + let t = new Uint8Array(n.nonce_length); + for (let r = 0; r < t.length; r++) t[r] = i2[r] ^ y[r]; + yield t; + } + for (let a = 0; a < f; a++) { + if (a === f - 1 && l[a] === b) throw new RangeError("Maximum number of segments exceeded"); + if (l[a] = (l[a] + 1) % (b + 1), e2.setUint32(e2.byteLength - 4 * (a + 2), l[a], false), l[a] !== 0) break; + } + } + }()]; +}; +var I = v; +var B = (n) => ArrayBuffer.isView(n) ? new Uint8Array(n.buffer).subarray(n.byteOffset, n.byteOffset + n.byteLength) : new Uint8Array(n); +var m2 = B; +var o = { salt: {}, recordSize: {}, keyIdLen: {}, keyId: {}, payload: {}, done: {} }; +var R = (n, T2, w3, L) => { + let u2 = new Uint8Array(16), d, A2, E2, s = 0, e2 = 0, y = new Uint8Array(256), i2 = o.salt, b = new TransformStream({ start: () => { + }, transform: async (f, l) => { + let a = m2(f), t = 0; + for (; t < f.byteLength; ) switch (i2) { + case o.salt: { + let r = a.subarray(t, t + u2.byteLength - e2); + if (u2.set(r, e2), e2 += r.byteLength, t += r.byteLength, e2 === u2.byteLength) { + e2 = 0, i2 = o.recordSize; + continue; } + break; } - return _arr; - } - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; + case o.recordSize: { + let r = a.subarray(t, t + 4 - e2), g2 = new ArrayBuffer(4), h2 = new Uint8Array(g2), c = new DataView(g2); + if (h2.set(r, e2), s |= c.getUint32(0, false), e2 += r.byteLength, t += r.byteLength, e2 === 4) { + if (s <= n.tag_length + 1 || s > (L == null ? 4294967295 : Math.min(4294967295, L))) throw new RangeError("Invalid record size: " + s); + e2 = 0, i2 = o.keyIdLen; + continue; + } + break; + } + case o.keyIdLen: { + y[0] = a[t++], i2 = o.keyId; + continue; + } + case o.keyId: { + let r = a.subarray(t, t + y[0] - e2); + if (y.set(r, 1 + e2), e2 += r.byteLength, t += r.byteLength, e2 === y[0]) { + let g2 = await w3(y.subarray(1, 1 + y[0])); + w3 = void 0; + let h2 = await I(n, g2, u2, ["decrypt"]); + A2 = h2[0], E2 = h2[1], d = new Uint8Array(s), e2 = 0, i2 = o.payload; + continue; + } + break; + } + case o.payload: { + let r = a.subarray(t, t + s - e2); + if (d.set(r, e2), e2 += r.byteLength, t += r.byteLength, e2 === s) { + let h2 = E2.next().value, c = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: h2, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), p = c.byteLength - 1; + for (; p > 0 && c[p] === 0; p--) ; + if (c[p] === 2) { + if (t !== f.byteLength) throw new Error("Unexpected terminal padding delimiter"); + i2 = o.done; + } else if (c[p] !== 1) throw new Error("Invalid padding delimiter"); + l.enqueue(c.buffer.slice(0, p)), c.fill(0), e2 = 0; + continue; + } + break; + } + default: + throw new Error("Invalid state"); } - function asyncGeneratorStep(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); + }, flush: async (f) => { + switch (i2) { + case o.done: + return; + case o.payload: { + if (e2 < 1 + n.tag_length) throw new Error("Unexpected end of data"); + let a = E2.next().value, t = m2(await globalThis.crypto.subtle.decrypt({ name: n.params.name, iv: a, tagLength: n.tag_length << 3 }, A2, d.subarray(0, e2))), r = t.byteLength - 1; + for (; r > 0 && t[r] === 0; r--) ; + if (t[r] !== 2) throw new Error("Unexpected non-terminal padding delimiter"); + f.enqueue(t.buffer.slice(0, r)), t.fill(0); return; } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + default: + throw new Error("Invalid state"); + } + } }); + return T2.pipeThrough(b), b.readable; +}; +var S = R; +var x2 = { params: { name: "AES-GCM", length: 128 }, get cek_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 49, 50, 56, 103, 99, 109, 0]); +}, get nonce_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); +}, block_size: 16, tag_length: 16, nonce_length: 12 }; +var e = { params: { name: "AES-GCM", length: 256 }, get cek_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 97, 101, 115, 50, 53, 54, 103, 99, 109, 0]); +}, get nonce_info() { + return new Uint8Array([67, 111, 110, 116, 101, 110, 116, 45, 69, 110, 99, 111, 100, 105, 110, 103, 58, 32, 110, 111, 110, 99, 101, 0]); +}, block_size: 16, tag_length: 16, nonce_length: 12 }; +var R2 = async (e2, b, f, i2) => { + let A2 = await globalThis.crypto.subtle.importKey("raw", b, "HKDF", false, ["deriveKey", "deriveBits"]), y = await globalThis.crypto.subtle.deriveKey({ name: "HKDF", hash: "SHA-256", info: e2.cek_info, salt: f }, A2, e2.params, false, i2), u2 = await globalThis.crypto.subtle.deriveBits({ name: "HKDF", hash: "SHA-256", info: e2.nonce_info, salt: f }, A2, e2.nonce_length << 3); + return [y, function* () { + let L = new ArrayBuffer(e2.nonce_length), c = new DataView(L), h2 = new Uint8Array(L), a = new Uint8Array(u2), g2 = 4294967295, o2 = (e2.nonce_length >> 2) - 1, s = new Array(o2).fill(0); + for (; ; ) { + for (let t = 0; t <= g2; t++) { + c.setUint32(c.byteLength - 4, t, false); + let n = new Uint8Array(e2.nonce_length); + for (let r = 0; r < n.length; r++) n[r] = a[r] ^ h2[r]; + yield n; + } + for (let t = 0; t < o2; t++) { + if (t === o2 - 1 && s[t] === g2) throw new RangeError("Maximum number of segments exceeded"); + if (s[t] = (s[t] + 1) % (g2 + 1), c.setUint32(c.byteLength - 4 * (t + 2), s[t], false), s[t] !== 0) break; + } + } + }()]; +}; +var E = R2; +var B2 = (e2) => ArrayBuffer.isView(e2) ? new Uint8Array(e2.buffer).subarray(e2.byteOffset, e2.byteOffset + e2.byteLength) : new Uint8Array(e2); +var w2 = B2; +var N = () => { + let e2 = new Uint8Array(16); + return globalThis.crypto.getRandomValues(e2), e2; +}; +var U = async (e2, b, f, i2, A2, y) => { + if (f <= e2.tag_length + 1 || f > 4294967295) throw new RangeError("Invalid record size: " + f); + if (i2.byteLength > 255) throw new RangeError("Key ID too long"); + if (y && y.byteLength !== 16) throw new RangeError("Invald salt length: " + y.byteLength); + let u2 = f - e2.tag_length - 1, l = y ? w2(y) : N(), [L, c] = await E(e2, A2, l, ["encrypt"]); + A2 = void 0; + let h2 = new Uint8Array(u2), a = 0, g2 = new TransformStream({ start: (o2) => { + let s = l.byteLength + 4 + 1 + i2.byteLength, t = new ArrayBuffer(s); + new Uint8Array(t, 0, l.byteLength).set(l); + let r = new DataView(t, l.byteLength, 5); + r.setUint32(0, f, false), r.setUint8(4, i2.byteLength); + let d = new Uint8Array(t, l.byteLength + 4 + 1, i2.byteLength), m3 = w2(i2); + d.set(m3), o2.enqueue(t); + }, transform: async (o2, s) => { + let t = w2(o2), n = 0; + for (; n < o2.byteLength; ) { + let r = t.subarray(n, n + u2 - a); + if (h2.set(r, a), a += r.byteLength, n += r.byteLength, a === u2) { + let m3 = c.next().value, p = new Uint8Array(u2 + 1); + p.set(h2.subarray(0, a)), p[a] = 1; + let T2 = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: m3, tagLength: e2.tag_length << 3 }, L, p); + s.enqueue(T2), a = 0; + } + } + }, flush: async (o2) => { + let t = c.next().value, n = new Uint8Array(a + 1); + n.set(h2.subarray(0, a)), n[a] = 2; + let r = await globalThis.crypto.subtle.encrypt({ name: e2.params.name, iv: t, tagLength: e2.tag_length << 3 }, L, n); + o2.enqueue(r), h2.fill(0), n.fill(0); + } }); + return b.pipeThrough(g2), g2.readable; +}; +var K = U; +init_esm6(); +init_bytes(); +init_esm(); +init_esm4(); +init_functions(); +init_esm6(); +init_esm(); +init_esm4(); +init_SPMessage(); +init_esm7(); +var wm = /* @__PURE__ */ new WeakMap(); +var Secret = class { + static [serdesDeserializeSymbol](secret) { + return new this(secret); + } + static [serdesSerializeSymbol](secret) { + return wm.get(secret); + } + static get [serdesTagSymbol]() { + return "__chelonia_Secret"; + } + constructor(value) { + wm.set(this, value); + } + valueOf() { + return wm.get(this); + } +}; +var INVITE_STATUS = { + REVOKED: "revoked", + VALID: "valid", + USED: "used" +}; +init_errors3(); +init_functions(); +init_signedData(); +var MAX_EVENTS_AFTER = Number.parseInt(process.env.MAX_EVENTS_AFTER || "", 10) || Infinity; +var copiedExistingData = Symbol("copiedExistingData"); +var findKeyIdByName = (state, name) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).find((k) => k.name === name && k._notAfterHeight == null)?.id; +var findForeignKeysByContractID = (state, contractID) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => k._notAfterHeight == null && k.foreignKey?.includes(contractID)).map((k) => k.id); +var findRevokedKeyIdsByName = (state, name) => state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys || {}).filter((k) => k.name === name && k._notAfterHeight != null).map((k) => k.id); +var findSuitableSecretKeyId = (state, permissions, purposes, ringLevel, allowedActions) => { + return state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => { + return k._notAfterHeight == null && k.ringLevel <= (ringLevel ?? Number.POSITIVE_INFINITY) && esm_default("chelonia/haveSecretKey", k.id) && (Array.isArray(permissions) ? permissions.reduce((acc, permission) => acc && (k.permissions === "*" || k.permissions.includes(permission)), true) : permissions === k.permissions) && purposes.reduce((acc, purpose) => acc && k.purpose.includes(purpose), true) && (Array.isArray(allowedActions) ? allowedActions.reduce((acc, action) => acc && (k.allowedActions === "*" || !!k.allowedActions?.includes(action)), true) : allowedActions ? allowedActions === k.allowedActions : true); + }).sort((a, b) => b.ringLevel - a.ringLevel)[0]?.id; +}; +var findSuitablePublicKeyIds = (state, permissions, purposes, ringLevel) => { + return state._vm?.authorizedKeys && Object.values(state._vm.authorizedKeys).filter((k) => k._notAfterHeight == null && k.ringLevel <= (ringLevel ?? Number.POSITIVE_INFINITY) && (Array.isArray(permissions) ? permissions.reduce((acc, permission) => acc && (k.permissions === "*" || k.permissions.includes(permission)), true) : permissions === k.permissions) && purposes.reduce((acc, purpose) => acc && k.purpose.includes(purpose), true)).sort((a, b) => b.ringLevel - a.ringLevel).map((k) => k.id); +}; +var validateActionPermissions = (msg, signingKey, state, opT, opV) => { + const data = isSignedData(opV) ? opV.valueOf() : opV; + if (signingKey.allowedActions !== "*" && (!Array.isArray(signingKey.allowedActions) || !signingKey.allowedActions.includes(data.action))) { + logEvtError(msg, `Signing key ${signingKey.id} is not allowed for action ${data.action}`); + return false; + } + if (isSignedData(opV)) { + const s = opV; + const innerSigningKey = state._vm?.authorizedKeys?.[s.signingKeyId]; + if (!innerSigningKey && msg._direction === "outgoing") + return true; + if (!innerSigningKey || !Array.isArray(innerSigningKey.purpose) || !innerSigningKey.purpose.includes("sig") || innerSigningKey.permissions !== "*" && (!Array.isArray(innerSigningKey.permissions) || !innerSigningKey.permissions.includes(opT + "#inner"))) { + logEvtError(msg, `Signing key ${s.signingKeyId} is missing permissions for operation ${opT}`); + return false; + } + if (innerSigningKey.allowedActions !== "*" && (!Array.isArray(innerSigningKey.allowedActions) || !innerSigningKey.allowedActions.includes(data.action + "#inner"))) { + logEvtError(msg, `Signing key ${innerSigningKey.id} is not allowed for action ${data.action}`); + return false; + } + } + return true; +}; +var validateKeyPermissions = (msg, config2, state, signingKeyId, opT, opV) => { + const signingKey = state._vm?.authorizedKeys?.[signingKeyId]; + if (!signingKey || !Array.isArray(signingKey.purpose) || !signingKey.purpose.includes("sig") || signingKey.permissions !== "*" && (!Array.isArray(signingKey.permissions) || !signingKey.permissions.includes(opT))) { + logEvtError(msg, `Signing key ${signingKeyId} is missing permissions for operation ${opT}`); + return false; + } + if (opT === SPMessage.OP_ACTION_UNENCRYPTED && !validateActionPermissions(msg, signingKey, state, opT, opV)) { + return false; + } + if (!config2.skipActionProcessing && opT === SPMessage.OP_ACTION_ENCRYPTED && !validateActionPermissions(msg, signingKey, state, opT, opV.valueOf())) { + return false; + } + return true; +}; +var validateKeyAddPermissions = function(contractID, signingKey, state, v2, skipPrivateCheck) { + const signingKeyPermissions = Array.isArray(signingKey.permissions) ? new Set(signingKey.permissions) : signingKey.permissions; + const signingKeyAllowedActions = Array.isArray(signingKey.allowedActions) ? new Set(signingKey.allowedActions) : signingKey.allowedActions; + if (!state._vm?.authorizedKeys?.[signingKey.id]) { + throw new Error("Singing key for OP_KEY_ADD or OP_KEY_UPDATE must exist in _vm.authorizedKeys. contractID=" + contractID + " signingKeyId=" + signingKey.id); + } + const localSigningKey = state._vm.authorizedKeys[signingKey.id]; + v2.forEach((wk) => { + const data = this.config.unwrapMaybeEncryptedData(wk); + if (!data) + return; + const k = data.data; + if (!skipPrivateCheck && signingKey._private && !data.encryptionKeyId) { + throw new Error("Signing key is private but it tried adding a public key"); + } + if (!Number.isSafeInteger(k.ringLevel) || k.ringLevel < localSigningKey.ringLevel) { + throw new Error("Signing key has ringLevel " + localSigningKey.ringLevel + " but attempted to add or update a key with ringLevel " + k.ringLevel); + } + if (signingKeyPermissions !== "*") { + if (!Array.isArray(k.permissions) || !k.permissions.reduce((acc, cv) => acc && signingKeyPermissions.has(cv), true)) { + throw new Error("Unable to add or update a key with more permissions than the signing key. signingKey permissions: " + String(signingKey?.permissions) + "; key add permissions: " + String(k.permissions)); } } - function _asyncToGenerator(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); + if (signingKeyAllowedActions !== "*" && k.allowedActions) { + if (!signingKeyAllowedActions || !Array.isArray(k.allowedActions) || !k.allowedActions.reduce((acc, cv) => acc && signingKeyAllowedActions.has(cv), true)) { + throw new Error("Unable to add or update a key with more allowed actions than the signing key. signingKey allowed actions: " + String(signingKey?.allowedActions) + "; key add allowed actions: " + String(k.allowedActions)); + } + } + }); +}; +var validateKeyDelPermissions = function(contractID, signingKey, state, v2) { + if (!state._vm?.authorizedKeys?.[signingKey.id]) { + throw new Error("Singing key for OP_KEY_DEL must exist in _vm.authorizedKeys. contractID=" + contractID + " signingKeyId=" + signingKey.id); + } + const localSigningKey = state._vm.authorizedKeys[signingKey.id]; + v2.forEach((wid) => { + const data = this.config.unwrapMaybeEncryptedData(wid); + if (!data) + return; + const id = data.data; + const k = state._vm.authorizedKeys[id]; + if (!k) { + throw new Error("Nonexisting key ID " + id); + } + if (signingKey._private) { + throw new Error("Signing key is private"); + } + if (!k._private !== !data.encryptionKeyId) { + throw new Error("_private attribute must be preserved"); + } + if (!Number.isSafeInteger(k.ringLevel) || k.ringLevel < localSigningKey.ringLevel) { + throw new Error("Signing key has ringLevel " + localSigningKey.ringLevel + " but attempted to remove a key with ringLevel " + k.ringLevel); + } + }); +}; +var validateKeyUpdatePermissions = function(contractID, signingKey, state, v2) { + const updatedMap = /* @__PURE__ */ Object.create(null); + const keys = v2.map((wuk) => { + const data = this.config.unwrapMaybeEncryptedData(wuk); + if (!data) + return void 0; + const uk = data.data; + const existingKey = state._vm.authorizedKeys[uk.oldKeyId]; + if (!existingKey) { + throw new ChelErrorWarning("Missing old key ID " + uk.oldKeyId); + } + if (!existingKey._private !== !data.encryptionKeyId) { + throw new Error("_private attribute must be preserved"); + } + if (uk.name !== existingKey.name) { + throw new Error("Name cannot be updated"); + } + if (!uk.id !== !uk.data) { + throw new Error("Both or none of the id and data attributes must be provided. Old key ID: " + uk.oldKeyId); + } + if (uk.data && existingKey.meta?.private && !uk.meta?.private) { + throw new Error("Missing private key. Old key ID: " + uk.oldKeyId); + } + if (uk.id && uk.id !== uk.oldKeyId) { + updatedMap[uk.id] = uk.oldKeyId; + } + const updatedKey = omit2(existingKey, [ + "_notAfterHeight", + "_notBeforeHeight" + ]); + if (uk.permissions) { + updatedKey.permissions = uk.permissions; + } + if (uk.allowedActions) { + updatedKey.allowedActions = uk.allowedActions; + } + if (uk.purpose) { + updatedKey.purpose = uk.purpose; + } + if (uk.meta) { + updatedKey.meta = uk.meta; + } else if (updatedKey.meta) { + Object.defineProperty(updatedKey.meta, copiedExistingData, { value: true }); + } + if (uk.id) { + updatedKey.id = uk.id; + } + if (uk.data) { + updatedKey.data = uk.data; + } + return updatedKey; + }).filter(Boolean); + validateKeyAddPermissions.call(this, contractID, signingKey, state, keys, true); + return [keys, updatedMap]; +}; +var keyAdditionProcessor = function(_msg, hash3, keys, state, contractID, _signingKey, internalSideEffectStack) { + const decryptedKeys = []; + const keysToPersist = []; + const storeSecretKey = (key, decryptedKey) => { + const decryptedDeserializedKey = deserializeKey(decryptedKey); + const transient = !!key.meta?.private?.transient; + esm_default("chelonia/storeSecretKeys", new Secret([ + { + key: decryptedDeserializedKey, + // We always set this to true because this could be done from + // an outgoing message + transient: true + } + ])); + if (!transient) { + keysToPersist.push({ key: decryptedDeserializedKey, transient }); + } + }; + for (const wkey of keys) { + const data = this.config.unwrapMaybeEncryptedData(wkey); + if (!data) + continue; + const key = data.data; + let decryptedKey; + if (key.meta?.private?.content && !has(key.meta, copiedExistingData)) { + if (key.id && !esm_default("chelonia/haveSecretKey", key.id, !key.meta.private.transient)) { + const decryptedKeyResult = this.config.unwrapMaybeEncryptedData(key.meta.private.content); + if (decryptedKeyResult) { + if (decryptedKeyResult.encryptionKeyId == null) { + throw new Error("Expected encrypted data but got unencrypted data for key with ID: " + key.id); + } + decryptedKey = decryptedKeyResult.data; + decryptedKeys.push([key.id, decryptedKey]); + storeSecretKey(key, decryptedKey); + } + } + } + if (key.name === "#sak") { + if (data.encryptionKeyId) { + throw new Error("#sak may not be encrypted"); + } + if (key.permissions && (!Array.isArray(key.permissions) || key.permissions.length !== 0)) { + throw new Error("#sak may not have permissions"); + } + if (!Array.isArray(key.purpose) || key.purpose.length !== 1 || key.purpose[0] !== "sak") { + throw new Error("#sak must have exactly one purpose: 'sak'"); + } + if (key.ringLevel !== 0) { + throw new Error("#sak must have ringLevel 0"); + } + } + if (key.name.startsWith("#inviteKey-")) { + if (!state._vm.invites) + state._vm.invites = /* @__PURE__ */ Object.create(null); + const inviteSecret = decryptedKey || (has(this.transientSecretKeys, key.id) ? serializeKey(this.transientSecretKeys[key.id], true) : void 0); + state._vm.invites[key.id] = { + status: INVITE_STATUS.VALID, + initialQuantity: key.meta.quantity, + quantity: key.meta.quantity, + expires: key.meta.expires, + inviteSecret, + responses: [] }; } - var Events; - var IORedisConnection; - var Scripts; - var parser; - parser = require_parser2(); - Events = require_Events(); - Scripts = require_Scripts(); - IORedisConnection = function() { - class IORedisConnection { - constructor(options = {}) { - parser.load(options, this.defaults, this); - if (this.Redis == null) { - this.Redis = eval("require")("ioredis"); - } - if (this.Events == null) { - this.Events = new Events(this); - } - this.terminated = false; - if (this.clusterNodes != null) { - this.client = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); - this.subscriber = new this.Redis.Cluster(this.clusterNodes, this.clientOptions); - } else if (this.client != null && this.client.duplicate == null) { - this.subscriber = new this.Redis.Cluster(this.client.startupNodes, this.client.options); - } else { - if (this.client == null) { - this.client = new this.Redis(this.clientOptions); + if (key.meta?.keyRequest?.contractID && findSuitableSecretKeyId(state, [SPMessage.OP_KEY_ADD], ["sig"])) { + const data2 = this.config.unwrapMaybeEncryptedData(key.meta.keyRequest.contractID); + if (data2 && internalSideEffectStack) { + const keyRequestContractID = data2.data; + const reference = this.config.unwrapMaybeEncryptedData(key.meta.keyRequest.reference); + internalSideEffectStack.push(() => { + esm_default("chelonia/private/queueEvent", keyRequestContractID, () => { + const rootState = esm_default(this.config.stateSelector); + const originatingContractState = rootState[contractID]; + if (esm_default("chelonia/contract/hasKeyShareBeenRespondedBy", originatingContractState, keyRequestContractID, reference)) { + return; } - this.subscriber = this.client.duplicate(); - } - this.limiters = {}; - this.ready = this.Promise.all([this._setup(this.client, false), this._setup(this.subscriber, true)]).then(() => { - this._loadScripts(); - return { - client: this.client, - subscriber: this.subscriber - }; - }); - } - _setup(client, sub) { - client.setMaxListeners(0); - return new this.Promise((resolve82, reject) => { - client.on("error", (e2) => { - return this.Events.trigger("error", e2); - }); - if (sub) { - client.on("message", (channel, message) => { - var ref; - return (ref = this.limiters[channel]) != null ? ref._store.onMessage(channel, message) : void 0; - }); + if (!has(rootState, keyRequestContractID)) { + this.config.reactiveSet(rootState, keyRequestContractID, /* @__PURE__ */ Object.create(null)); } - if (client.status === "ready") { - return resolve82(); - } else { - return client.once("ready", resolve82); + const targetState = rootState[keyRequestContractID]; + if (!targetState._volatile) { + this.config.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); } - }); - } - _loadScripts() { - return Scripts.names.forEach((name) => { - return this.client.defineCommand(name, { - lua: Scripts.payload(name) + if (!targetState._volatile.pendingKeyRequests) { + this.config.reactiveSet(rootState[keyRequestContractID]._volatile, "pendingKeyRequests", []); + } + if (targetState._volatile.pendingKeyRequests.some((pkr) => { + return pkr && pkr.contractID === contractID && pkr.hash === hash3; + })) { + return; + } + targetState._volatile.pendingKeyRequests.push({ + contractID, + name: key.name, + hash: hash3, + reference: reference?.data }); + this.setPostSyncOp(contractID, "pending-keys-for-" + keyRequestContractID, [ + "okTurtles.events/emit", + CONTRACT_IS_PENDING_KEY_REQUESTS, + { contractID: keyRequestContractID } + ]); + }).catch((e2) => { + console.error("Error while setting or updating pendingKeyRequests", { contractID, keyRequestContractID, reference }, e2); }); - } - __runCommand__(cmd) { - var _this = this; - return _asyncToGenerator(function* () { - var _, deleted; - yield _this.ready; - var _ref = yield _this.client.pipeline([cmd]).exec(); - var _ref2 = _slicedToArray(_ref, 1); - var _ref2$ = _slicedToArray(_ref2[0], 2); - _ = _ref2$[0]; - deleted = _ref2$[1]; - return deleted; - })(); - } - __addLimiter__(instance) { - return this.Promise.all([instance.channel(), instance.channel_client()].map((channel) => { - return new this.Promise((resolve82, reject) => { - return this.subscriber.subscribe(channel, () => { - this.limiters[channel] = instance; - return resolve82(); - }); - }); - })); - } - __removeLimiter__(instance) { - var _this2 = this; - return [instance.channel(), instance.channel_client()].forEach( - /* @__PURE__ */ function() { - var _ref3 = _asyncToGenerator(function* (channel) { - if (!_this2.terminated) { - yield _this2.subscriber.unsubscribe(channel); - } - return delete _this2.limiters[channel]; - }); - return function(_x) { - return _ref3.apply(this, arguments); - }; - }() - ); - } - __scriptArgs__(name, id, args, cb) { - var keys; - keys = Scripts.keys(name, id); - return [keys.length].concat(keys, args, cb); - } - __scriptFn__(name) { - return this.client[name].bind(this.client); - } - disconnect(flush = true) { - var i2, k, len, ref; - ref = Object.keys(this.limiters); - for (i2 = 0, len = ref.length; i2 < len; i2++) { - k = ref[i2]; - clearInterval(this.limiters[k]._store.heartbeat); - } - this.limiters = {}; - this.terminated = true; - if (flush) { - return this.Promise.all([this.client.quit(), this.subscriber.quit()]); - } else { - this.client.disconnect(); - this.subscriber.disconnect(); - return this.Promise.resolve(); - } - } + }); } - ; - IORedisConnection.prototype.datastore = "ioredis"; - IORedisConnection.prototype.defaults = { - Redis: null, - clientOptions: {}, - clusterNodes: null, - client: null, - Promise, - Events: null - }; - return IORedisConnection; - }.call(void 0); - module.exports = IORedisConnection; - } -}); -var require_RedisDatastore = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/RedisDatastore.js"(exports2, module14) { - "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); - } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; - } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } + } + if (keysToPersist.length) { + internalSideEffectStack?.push(() => { + esm_default("chelonia/storeSecretKeys", new Secret(keysToPersist)); + }); + } + internalSideEffectStack?.push(() => subscribeToForeignKeyContracts.call(this, contractID, state)); +}; +var subscribeToForeignKeyContracts = function(contractID, state) { + try { + Object.values(state._vm.authorizedKeys).filter((key) => !!key.foreignKey && findKeyIdByName(state, key.name) != null).forEach((key) => { + const foreignKey = String(key.foreignKey); + const fkUrl = new URL(foreignKey); + const foreignContract = fkUrl.pathname; + const foreignKeyName = fkUrl.searchParams.get("keyName"); + if (!foreignContract || !foreignKeyName) { + console.warn("Invalid foreign key: missing contract or key name", { + contractID, + keyId: key.id + }); + return; } - return _arr; - } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; - } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); + const rootState = esm_default(this.config.stateSelector); + const signingKey = findSuitableSecretKeyId(state, [SPMessage.OP_KEY_DEL], ["sig"], key.ringLevel); + const canMirrorOperations = !!signingKey; + if (!canMirrorOperations) return; + if (Array.isArray(rootState?.[foreignContract]?._volatile?.watch)) { + if (rootState[foreignContract]._volatile.watch.find((v2) => v2[0] === key.name && v2[1] === contractID)) { + return; + } } - if (info.done) { - resolve82(value); + if (!has(state._vm, "pendingWatch")) { + this.config.reactiveSet(state._vm, "pendingWatch", /* @__PURE__ */ Object.create(null)); + } + if (!has(state._vm.pendingWatch, foreignContract)) { + this.config.reactiveSet(state._vm.pendingWatch, foreignContract, []); + } + if (!state._vm.pendingWatch[foreignContract].find(([n]) => n === foreignKeyName)) { + state._vm.pendingWatch[foreignContract].push([foreignKeyName, key.id]); + } + this.setPostSyncOp(contractID, `watchForeignKeys-${contractID}`, [ + "chelonia/private/watchForeignKeys", + contractID + ]); + }); + } catch (e2) { + console.warn("Error at subscribeToForeignKeyContracts: " + (e2.message || e2)); + } +}; +var recreateEvent = (entry, state, contractsState, disableAutoDedup) => { + const { HEAD: previousHEAD, height: previousHeight, previousKeyOp } = contractsState || {}; + if (!previousHEAD) { + throw new Error("recreateEvent: Giving up because the contract has been removed"); + } + const head = entry.head(); + const [opT, rawOpV] = entry.rawOp(); + const recreateOperation = (opT2, rawOpV2) => { + const opV = rawOpV2.valueOf(); + const recreateOperationInternal = (opT3, opV2) => { + let newOpV2; + if (opT3 === SPMessage.OP_KEY_ADD) { + if (!Array.isArray(opV2)) + throw new Error("Invalid message format"); + newOpV2 = opV2.filter((k) => { + const kId = k.valueOf().id; + return !has(state._vm.authorizedKeys, kId) || state._vm.authorizedKeys[kId]._notAfterHeight != null; + }); + if (newOpV2.length === 0) { + console.info("Omitting empty OP_KEY_ADD", { head }); + } else if (newOpV2.length === opV2.length) { + return opV2; + } + } else if (opT3 === SPMessage.OP_KEY_DEL) { + if (!Array.isArray(opV2)) + throw new Error("Invalid message format"); + newOpV2 = opV2.filter((keyId2) => { + const kId = Object(keyId2).valueOf(); + return has(state._vm.authorizedKeys, kId) && state._vm.authorizedKeys[kId]._notAfterHeight == null; + }); + if (newOpV2.length === 0) { + console.info("Omitting empty OP_KEY_DEL", { head }); + } else if (newOpV2.length === opV2.length) { + return opV2; + } + } else if (opT3 === SPMessage.OP_KEY_UPDATE) { + if (!Array.isArray(opV2)) + throw new Error("Invalid message format"); + newOpV2 = opV2.filter((k) => { + const oKId = k.valueOf().oldKeyId; + const nKId = k.valueOf().id; + return nKId == null || has(state._vm.authorizedKeys, oKId) && state._vm.authorizedKeys[oKId]._notAfterHeight == null; + }); + if (newOpV2.length === 0) { + console.info("Omitting empty OP_KEY_UPDATE", { head }); + } else if (newOpV2.length === opV2.length) { + return opV2; + } + } else if (opT3 === SPMessage.OP_ATOMIC) { + if (!Array.isArray(opV2)) + throw new Error("Invalid message format"); + newOpV2 = opV2.map(([t, v2]) => [t, recreateOperationInternal(t, v2)]).filter(([, v2]) => !!v2); + if (newOpV2.length === 0) { + console.info("Omitting empty OP_ATOMIC", { head }); + } else if (newOpV2.length === opV2.length && newOpV2.reduce((acc, cv, i2) => acc && cv === opV2[i2], true)) { + return opV2; + } else { + return newOpV2; + } } else { - Promise.resolve(value).then(_next, _throw); + return opV2; } + }; + const newOpV = recreateOperationInternal(opT2, opV); + if (newOpV === opV) { + return rawOpV2; + } else if (newOpV === void 0) { + return; } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; + if (typeof rawOpV2.recreate !== "function") { + throw new Error("Unable to recreate operation"); } - var BottleneckError; - var IORedisConnection2; - var RedisConnection2; - var RedisDatastore; - var parser3; - parser3 = require_parser2(); - BottleneckError = require_BottleneckError(); - RedisConnection2 = require_RedisConnection(); - IORedisConnection2 = require_IORedisConnection(); - RedisDatastore = class RedisDatastore { - constructor(instance, storeOptions, storeInstanceOptions) { - this.instance = instance; - this.storeOptions = storeOptions; - this.originalId = this.instance.id; - this.clientId = this.instance._randomIndex(); - parser3.load(storeInstanceOptions, storeInstanceOptions, this); - this.clients = {}; - this.capacityPriorityCounters = {}; - this.sharedConnection = this.connection != null; - if (this.connection == null) { - this.connection = this.instance.datastore === "redis" ? new RedisConnection2({ - Redis: this.Redis, - clientOptions: this.clientOptions, - Promise: this.Promise, - Events: this.instance.Events - }) : this.instance.datastore === "ioredis" ? new IORedisConnection2({ - Redis: this.Redis, - clientOptions: this.clientOptions, - clusterNodes: this.clusterNodes, - Promise: this.Promise, - Events: this.instance.Events - }) : void 0; - } - this.instance.connection = this.connection; - this.instance.datastore = this.connection.datastore; - this.ready = this.connection.ready.then((clients) => { - this.clients = clients; - return this.runScript("init", this.prepareInitSettings(this.clearDatastore)); - }).then(() => { - return this.connection.__addLimiter__(this.instance); - }).then(() => { - return this.runScript("register_client", [this.instance.queued()]); - }).then(() => { - var base2; - if (typeof (base2 = this.heartbeat = setInterval(() => { - return this.runScript("heartbeat", []).catch((e2) => { - return this.instance.Events.trigger("error", e2); - }); - }, this.heartbeatInterval)).unref === "function") { - base2.unref(); - } - return this.clients; - }); - } - __publish__(message) { - var _this = this; - return _asyncToGenerator2(function* () { - var client; - var _ref = yield _this.ready; - client = _ref.client; - return client.publish(_this.instance.channel(), `message:${message.toString()}`); - })(); + return rawOpV2.recreate(newOpV); + }; + const newRawOpV = disableAutoDedup ? rawOpV : recreateOperation(opT, rawOpV); + if (!newRawOpV) + return; + const newOp = [opT, newRawOpV]; + entry = SPMessage.cloneWith(head, newOp, { + previousKeyOp, + previousHEAD, + height: previousHeight + 1 + }); + return entry; +}; +var getContractIDfromKeyId = (contractID, signingKeyId, state) => { + if (!signingKeyId) + return; + return signingKeyId && state._vm?.authorizedKeys?.[signingKeyId]?.foreignKey ? new URL(state._vm.authorizedKeys[signingKeyId].foreignKey).pathname : contractID; +}; +function eventsAfter(contractID, { sinceHeight, limit, sinceHash, stream = true }) { + if (!contractID) { + throw new Error("Missing contract ID"); + } + let lastUrl; + const fetchEventsStreamReader = async () => { + requestLimit = Math.min(limit ?? MAX_EVENTS_AFTER, remainingEvents); + lastUrl = `${this.config.connectionURL}/eventsAfter/${contractID}/${sinceHeight}${Number.isInteger(requestLimit) ? `/${requestLimit}` : ""}`; + const eventsResponse = await this.config.fetch(lastUrl, { signal }); + if (!eventsResponse.ok) { + const msg = `${eventsResponse.status}: ${eventsResponse.statusText}`; + if (eventsResponse.status === 404 || eventsResponse.status === 410) { + throw new ChelErrorResourceGone(msg, { cause: eventsResponse.status }); } - onMessage(channel, message) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var capacity, counter, data, drained, e2, newCapacity, pos, priorityClient, rawCapacity, type; - try { - pos = message.indexOf(":"); - var _ref2 = [message.slice(0, pos), message.slice(pos + 1)]; - type = _ref2[0]; - data = _ref2[1]; - if (type === "capacity") { - return yield _this2.instance._drainAll(data.length > 0 ? ~~data : void 0); - } else if (type === "capacity-priority") { - var _data$split = data.split(":"); - var _data$split2 = _slicedToArray2(_data$split, 3); - rawCapacity = _data$split2[0]; - priorityClient = _data$split2[1]; - counter = _data$split2[2]; - capacity = rawCapacity.length > 0 ? ~~rawCapacity : void 0; - if (priorityClient === _this2.clientId) { - drained = yield _this2.instance._drainAll(capacity); - newCapacity = capacity != null ? capacity - (drained || 0) : ""; - return yield _this2.clients.client.publish(_this2.instance.channel(), `capacity-priority:${newCapacity}::${counter}`); - } else if (priorityClient === "") { - clearTimeout(_this2.capacityPriorityCounters[counter]); - delete _this2.capacityPriorityCounters[counter]; - return _this2.instance._drainAll(capacity); - } else { - return _this2.capacityPriorityCounters[counter] = setTimeout( - /* @__PURE__ */ _asyncToGenerator2(function* () { - var e3; - try { - delete _this2.capacityPriorityCounters[counter]; - yield _this2.runScript("blacklist_client", [priorityClient]); - return yield _this2.instance._drainAll(capacity); - } catch (error2) { - e3 = error2; - return _this2.instance.Events.trigger("error", e3); - } - }), - 1e3 - ); + throw new ChelErrorUnexpectedHttpResponseCode(msg, { cause: eventsResponse.status }); + } + if (!eventsResponse.body) + throw new Error("Missing body"); + latestHeight = parseInt(eventsResponse.headers.get("shelter-headinfo-height"), 10); + if (!Number.isSafeInteger(latestHeight)) + throw new Error("Invalid latest height"); + requestCount++; + return eventsResponse.body.getReader(); + }; + if (!Number.isSafeInteger(sinceHeight) || sinceHeight < 0) { + throw new TypeError("Invalid since height value. Expected positive integer."); + } + const signal = this.abortController.signal; + let requestCount = 0; + let remainingEvents = limit ?? Number.POSITIVE_INFINITY; + let eventsStreamReader; + let latestHeight; + let state = "fetch"; + let requestLimit; + let count; + let buffer = ""; + let currentEvent; + const s = new ReadableStream({ + // The pull function is called whenever the internal buffer of the stream + // becomes empty and needs more data. + async pull(controller) { + try { + for (; ; ) { + switch (state) { + // When in 'fetch' state, initiate a new fetch request to obtain a + // stream reader for events. + case "fetch": { + eventsStreamReader = await fetchEventsStreamReader(); + state = "read-new-response"; + count = 0; + break; + } + case "read-eos": + // End of stream case + case "read-new-response": + // Just started reading a new response + case "read": { + const { done, value } = await eventsStreamReader.read(); + if (done) { + if (remainingEvents === 0 || sinceHeight >= latestHeight) { + controller.close(); + return; + } else if (state === "read-new-response" || buffer) { + throw new Error("Invalid response: done too early"); + } else { + state = "fetch"; + break; + } } - } else if (type === "message") { - return _this2.instance.Events.trigger("message", data); - } else if (type === "blocked") { - return yield _this2.instance._dropAllQueued(); + if (!value) { + throw new Error("Invalid response: missing body"); + } + buffer = buffer + Buffer3.from(value).toString().trim(); + if (!buffer) + break; + if (state === "read-new-response") { + if (buffer[0] !== "[") { + throw new Error("Invalid response: no array start delimiter"); + } + buffer = buffer.slice(1); + } else if (state === "read-eos") { + throw new Error("Invalid data at the end of response"); + } + state = "events"; + break; } - } catch (error2) { - e2 = error2; - return _this2.instance.Events.trigger("error", e2); - } - })(); - } - __disconnect__(flush) { - clearInterval(this.heartbeat); - if (this.sharedConnection) { - return this.connection.__removeLimiter__(this.instance); - } else { - return this.connection.disconnect(flush); - } - } - runScript(name, args) { - var _this3 = this; - return _asyncToGenerator2(function* () { - if (!(name === "init" || name === "register_client")) { - yield _this3.ready; - } - return new _this3.Promise((resolve82, reject) => { - var all_args, arr; - all_args = [Date.now(), _this3.clientId].concat(args); - _this3.instance.Events.trigger("debug", `Calling Redis script: ${name}.lua`, all_args); - arr = _this3.connection.__scriptArgs__(name, _this3.originalId, all_args, function(err, replies) { - if (err != null) { - return reject(err); + case "events": { + const nextIdx = buffer.search(/(?<=\s*)[,\]]/); + if (nextIdx < 0) { + state = "read"; + break; } - return resolve82(replies); - }); - return _this3.connection.__scriptFn__(name)(...arr); - }).catch((e2) => { - if (e2.message === "SETTINGS_KEY_NOT_FOUND") { - if (name === "heartbeat") { - return _this3.Promise.resolve(); + let enqueued = false; + try { + const eventValue = buffer.slice(0, nextIdx).trim(); + if (eventValue) { + if (count === requestLimit) { + throw new Error("Received too many events"); + } + currentEvent = JSON.parse(b64ToStr(JSON.parse(eventValue))).message; + if (count === 0) { + const hash3 = SPMessage.deserializeHEAD(currentEvent).hash; + const height = SPMessage.deserializeHEAD(currentEvent).head.height; + if (height !== sinceHeight || sinceHash && sinceHash !== hash3) { + if (height === sinceHeight && sinceHash && sinceHash !== hash3) { + throw new ChelErrorForkedChain(`Forked chain: hash(${hash3}) !== since(${sinceHash})`); + } else { + throw new Error(`Unexpected data: hash(${hash3}) !== since(${sinceHash || ""}) or height(${height}) !== since(${sinceHeight})`); + } + } + } + if (count++ !== 0 || requestCount !== 0) { + controller.enqueue(currentEvent); + enqueued = true; + remainingEvents--; + } + } + if (buffer[nextIdx] === "]") { + if (currentEvent) { + const deserialized = SPMessage.deserializeHEAD(currentEvent); + sinceHeight = deserialized.head.height; + sinceHash = deserialized.hash; + state = "read-eos"; + } else { + state = "eod"; + } + buffer = buffer.slice(nextIdx + 1).trim(); + } else if (currentEvent) { + buffer = buffer.slice(nextIdx + 1).trimStart(); + } else { + throw new Error("Missing end delimiter"); + } + if (enqueued) { + return; + } + } catch (e2) { + console.error("[chelonia] Error during event parsing", e2); + throw e2; + } + break; + } + case "eod": { + if (remainingEvents === 0 || sinceHeight >= latestHeight) { + controller.close(); } else { - return _this3.runScript("init", _this3.prepareInitSettings(false)).then(() => { - return _this3.runScript(name, args); - }); + throw new Error("Unexpected end of data"); } - } else if (e2.message === "UNKNOWN_CLIENT") { - return _this3.runScript("register_client", [_this3.instance.queued()]).then(() => { - return _this3.runScript(name, args); - }); - } else { - return _this3.Promise.reject(e2); + return; } - }); - })(); - } - prepareArray(arr) { - var i2, len, results, x3; - results = []; - for (i2 = 0, len = arr.length; i2 < len; i2++) { - x3 = arr[i2]; - results.push(x3 != null ? x3.toString() : ""); - } - return results; - } - prepareObject(obj) { - var arr, k, v2; - arr = []; - for (k in obj) { - v2 = obj[k]; - arr.push(k, v2 != null ? v2.toString() : ""); + } } - return arr; - } - prepareInitSettings(clear) { - var args; - args = this.prepareObject(Object.assign({}, this.storeOptions, { - id: this.originalId, - version: this.instance.version, - groupTimeout: this.timeout, - clientTimeout: this.clientTimeout - })); - args.unshift(clear ? 1 : 0, this.instance.version); - return args; + } catch (e2) { + console.error("[eventsAfter] Error", { lastUrl }, e2); + eventsStreamReader?.cancel("Error during pull").catch((e22) => { + console.error("Error canceling underlying event stream reader on error", e2, e22); + }); + throw e2; } - convertBool(b) { - return !!b; + } + }); + if (stream) + return s; + return collectEventStream(s); +} +function buildShelterAuthorizationHeader(contractID, state) { + if (!state) + state = esm_default(this.config.stateSelector)[contractID]; + const SAKid = findKeyIdByName(state, "#sak"); + if (!SAKid) { + throw new Error(`Missing #sak in ${contractID}`); + } + const SAK = this.transientSecretKeys[SAKid]; + if (!SAK) { + throw new Error(`Missing secret #sak (${SAKid}) in ${contractID}`); + } + const deserializedSAK = typeof SAK === "string" ? deserializeKey(SAK) : SAK; + const nonceBytes = new Uint8Array(15); + globalThis.crypto.getRandomValues(nonceBytes); + const data = `${contractID} ${esm_default("chelonia/time")}.${Buffer3.from(nonceBytes).toString("base64")}`; + return `shelter ${data}.${sign(deserializedSAK, data)}`; +} +function verifyShelterAuthorizationHeader(authorization, rootState) { + const regex = /^shelter (([a-zA-Z0-9]+) ([0-9]+)\.([a-zA-Z0-9+/=]{20}))\.([a-zA-Z0-9+/=]+)$/i; + if (authorization.length > 1024) { + throw new Error("Authorization header too long"); + } + const matches = authorization.match(regex); + if (!matches) { + throw new Error("Unable to parse shelter authorization header"); + } + const [, data, contractID, timestamp, , signature] = matches; + if (Math.abs(parseInt(timestamp) - Date.now()) > 6e4) { + throw new Error("Invalid signature time range"); + } + if (!rootState) + rootState = esm_default("chelonia/rootState"); + if (!has(rootState, contractID)) { + throw new Error(`Contract ${contractID} from shelter authorization header not found`); + } + const SAKid = findKeyIdByName(rootState[contractID], "#sak"); + if (!SAKid) { + throw new Error(`Missing #sak in ${contractID}`); + } + const SAK = rootState[contractID]._vm.authorizedKeys[SAKid].data; + if (!SAK) { + throw new Error(`Missing secret #sak (${SAKid}) in ${contractID}`); + } + const deserializedSAK = deserializeKey(SAK); + verifySignature(deserializedSAK, data, signature); + return contractID; +} +var clearObject = (o2) => { + Object.keys(o2).forEach((k) => delete o2[k]); +}; +var reactiveClearObject = (o2, fn) => { + Object.keys(o2).forEach((k) => fn(o2, k)); +}; +var checkCanBeGarbageCollected = function(id) { + const rootState = esm_default(this.config.stateSelector); + return ( + // Check persistent references + (!has(rootState.contracts, id) || !rootState.contracts[id] || !has(rootState.contracts[id], "references")) && // Check ephemeral references + !has(this.ephemeralReferenceCount, id) && // Check foreign keys (i.e., that no keys from this contract are being watched) + (!has(rootState, id) || !has(rootState[id], "_volatile") || !has(rootState[id]._volatile, "watch") || rootState[id]._volatile.watch.length === 0 || rootState[id]._volatile.watch.filter(([, cID]) => this.subscriptionSet.has(cID)).length === 0) + ); +}; +var collectEventStream = async (s) => { + const reader = s.getReader(); + const r = []; + for (; ; ) { + const { done, value } = await reader.read(); + if (done) + break; + r.push(value); + } + return r; +}; +var logEvtError = (msg, ...args) => { + if (msg._direction === "outgoing") { + console.warn(...args); + } else { + console.error(...args); + } +}; +var handleFetchResult = (type) => { + return function(r) { + if (!r.ok) { + const msg = `${r.status}: ${r.statusText}`; + if (r.status === 404 || r.status === 410) { + throw new ChelErrorResourceGone(msg, { cause: r.status }); } - __updateSettings__(options2) { - var _this4 = this; - return _asyncToGenerator2(function* () { - yield _this4.runScript("update_settings", _this4.prepareObject(options2)); - return parser3.overwrite(options2, options2, _this4.storeOptions); - })(); + throw new ChelErrorUnexpectedHttpResponseCode(msg, { cause: r.status }); + } + return r[type](); + }; +}; +var supportsRequestStreams = typeof window !== "object" || (() => { + let duplexAccessed = false; + const hasContentType = new Request("", { + body: new ReadableStream(), + method: "POST", + get duplex() { + duplexAccessed = true; + return "half"; + } + }).headers.has("content-type"); + return duplexAccessed && !hasContentType; +})(); +var streamToUint8Array = async (s) => { + const reader = s.getReader(); + const chunks = []; + let length2 = 0; + for (; ; ) { + const result = await reader.read(); + if (result.done) + break; + chunks.push(coerce(result.value)); + length2 += result.value.byteLength; + } + const body = new Uint8Array(length2); + chunks.reduce((offset, chunk) => { + body.set(chunk, offset); + return offset + chunk.byteLength; + }, 0); + return body; +}; +var ArrayBufferToUint8ArrayStream = async function(connectionURL, s) { + if (supportsRequestStreams === true) { + await this.config.fetch(`${connectionURL}/streams-test`, { + method: "POST", + body: new ReadableStream({ + start(c) { + c.enqueue(Buffer4.from("ok")); + c.close(); + } + }), + duplex: "half" + }).then((r) => { + if (!r.ok) + throw new Error("Unexpected response"); + supportsRequestStreams = 2; + }).catch(() => { + console.info("files: Disabling streams support because the streams test failed"); + supportsRequestStreams = false; + }); + } + if (!supportsRequestStreams) { + return await streamToUint8Array(s); + } + return s.pipeThrough( + // eslint-disable-next-line no-undef + new TransformStream({ + transform(chunk, controller) { + controller.enqueue(coerce(chunk)); } - __running__() { - return this.runScript("running", []); + }) + ); +}; +var computeChunkDescriptors = (inStream) => { + let length2 = 0; + const [lengthStream, cidStream] = inStream.tee(); + const lengthPromise = new Promise((resolve82, reject) => { + lengthStream.pipeTo(new WritableStream({ + write(chunk) { + length2 += chunk.byteLength; + }, + close() { + resolve82(length2); + }, + abort(reason) { + reject(reason); } - __queued__() { - return this.runScript("queued", []); + })); + }); + const cidPromise = createCIDfromStream(cidStream, multicodes.SHELTER_FILE_CHUNK); + return Promise.all([lengthPromise, cidPromise]); +}; +var fileStream = (chelonia, manifest2) => { + const dataGenerator = async function* () { + let readSize = 0; + for (const chunk of manifest2.chunks) { + if (!Array.isArray(chunk) || typeof chunk[0] !== "number" || typeof chunk[1] !== "string") { + throw new Error("Invalid chunk descriptor"); + } + const chunkResponse = await chelonia.config.fetch(`${chelonia.config.connectionURL}/file/${chunk[1]}`, { + method: "GET", + signal: chelonia.abortController.signal + }); + if (!chunkResponse.ok) { + throw new Error("Unable to retrieve manifest"); + } + const chunkBinary = await chunkResponse.arrayBuffer(); + if (chunkBinary.byteLength !== chunk[0]) + throw new Error("mismatched chunk size"); + readSize += chunkBinary.byteLength; + if (readSize > manifest2.size) + throw new Error("read size exceeds declared size"); + if (createCID(coerce(chunkBinary), multicodes.SHELTER_FILE_CHUNK) !== chunk[1]) { + throw new Error("mismatched chunk hash"); + } + yield chunkBinary; + } + if (readSize !== manifest2.size) + throw new Error("mismatched size"); + }; + const dataIterator = dataGenerator(); + return new ReadableStream({ + async pull(controller) { + try { + const chunk = await dataIterator.next(); + if (chunk.done) { + controller.close(); + return; + } + controller.enqueue(chunk.value); + } catch (e2) { + controller.error(e2); } - __done__() { - return this.runScript("done", []); + } + }); +}; +var aes256gcmHandlers = { + upload: (_chelonia, manifestOptions) => { + const params = manifestOptions["cipher-params"]; + let IKM = params?.IKM; + const recordSize = params?.rs ?? 1 << 16; + if (!IKM) { + IKM = new Uint8Array(33); + self.crypto.getRandomValues(IKM); + } + const keyId2 = blake32Hash("aes256gcm-keyId" + blake32Hash(IKM)).slice(-8); + const binaryKeyId = Buffer4.from(keyId2); + return { + cipherParams: { + keyId: keyId2 + }, + streamHandler: async (stream) => { + return await K(e, stream, recordSize, binaryKeyId, IKM); + }, + downloadParams: { + IKM: Buffer4.from(IKM).toString("base64"), + rs: recordSize } - __groupCheck__() { - var _this5 = this; - return _asyncToGenerator2(function* () { - return _this5.convertBool(yield _this5.runScript("group_check", [])); - })(); + }; + }, + download: (chelonia, downloadParams, manifest2) => { + const IKMb64 = downloadParams.IKM; + if (!IKMb64) { + throw new Error("Missing IKM in downloadParams"); + } + const IKM = Buffer4.from(IKMb64, "base64"); + const keyId2 = blake32Hash("aes256gcm-keyId" + blake32Hash(IKM)).slice(-8); + if (!manifest2["cipher-params"] || !manifest2["cipher-params"].keyId) { + throw new Error("Missing cipher-params"); + } + if (keyId2 !== manifest2["cipher-params"].keyId) { + throw new Error("Key ID mismatch"); + } + const maxRecordSize = downloadParams.rs ?? 1 << 27; + return { + payloadHandler: async () => { + const bytes = await streamToUint8Array(S(e, fileStream(chelonia, manifest2), (actualKeyId) => { + if (Buffer4.from(actualKeyId).toString() !== keyId2) { + throw new Error("Invalid key ID"); + } + return IKM; + }, maxRecordSize)); + return new Blob([bytes], { type: manifest2.type || "application/octet-stream" }); } - __incrementReservoir__(incr) { - return this.runScript("increment_reservoir", [incr]); + }; + } +}; +var noneHandlers = { + upload: () => { + return { + cipherParams: void 0, + streamHandler: (stream) => { + return stream; + }, + downloadParams: void 0 + }; + }, + download: (chelonia, _downloadParams, manifest2) => { + return { + payloadHandler: async () => { + const bytes = await streamToUint8Array(fileStream(chelonia, manifest2)); + return new Blob([bytes], { type: manifest2.type || "application/octet-stream" }); } - __currentReservoir__() { - return this.runScript("current_reservoir", []); + }; + } +}; +var cipherHandlers = { + aes256gcm: aes256gcmHandlers, + none: noneHandlers +}; +var files_default = esm_default("sbp/selectors/register", { + "chelonia/fileUpload": async function(chunks, manifestOptions, { billableContractID } = {}) { + if (!Array.isArray(chunks)) + chunks = [chunks]; + const chunkDescriptors = []; + const cipherHandler = await cipherHandlers[manifestOptions.cipher]?.upload?.(this, manifestOptions); + if (!cipherHandler) + throw new Error("Unsupported cipher"); + const cipherParams = cipherHandler.cipherParams; + const transferParts = await Promise.all(chunks.map(async (chunk, i2) => { + const stream2 = chunk.stream(); + const encryptedStream = await cipherHandler.streamHandler(stream2); + const [body, s] = encryptedStream.tee(); + chunkDescriptors.push(computeChunkDescriptors(s)); + return { + headers: new Headers([ + ["content-disposition", `form-data; name="${i2}"; filename="${i2}"`], + ["content-type", "application/octet-stream"] + ]), + body + }; + })); + transferParts.push({ + headers: new Headers([ + ["content-disposition", 'form-data; name="manifest"; filename="manifest.json"'], + ["content-type", "application/vnd.shelter.filemanifest"] + ]), + body: new ReadableStream({ + async start(controller) { + const chunks2 = await Promise.all(chunkDescriptors); + const manifest2 = { + version: "1.0.0", + // ?? undefined coerces null and undefined to undefined + // This ensures that null or undefined values don't make it to the + // JSON (otherwise, null values _would_ be stringified as 'null') + type: manifestOptions.type ?? void 0, + meta: manifestOptions.meta ?? void 0, + cipher: manifestOptions.cipher, + "cipher-params": cipherParams, + size: chunks2.reduce((acc, [cv]) => acc + cv, 0), + chunks: chunks2, + "name-map": manifestOptions["name-map"] ?? void 0, + alternatives: manifestOptions.alternatives ?? void 0 + }; + controller.enqueue(Buffer4.from(JSON.stringify(manifest2))); + controller.close(); + } + }) + }); + const boundary = typeof self.crypto?.randomUUID === "function" ? self.crypto.randomUUID() : new Array(36).fill("").map(() => "abcdefghijklmnopqrstuvwxyz"[(0, Math.random)() * 26 | 0]).join(""); + const stream = x(boundary, transferParts); + const deletionToken = "deletionToken" + generateSalt(); + const deletionTokenHash = blake32Hash(deletionToken); + const uploadResponse = await this.config.fetch(`${this.config.connectionURL}/file`, { + method: "POST", + signal: this.abortController.signal, + body: await ArrayBufferToUint8ArrayStream.call(this, this.config.connectionURL, stream), + headers: new Headers([ + ...billableContractID ? [["authorization", buildShelterAuthorizationHeader.call(this, billableContractID)]] : [], + ["content-type", `multipart/form-data; boundary=${boundary}`], + ["shelter-deletion-token-digest", deletionTokenHash] + ]), + duplex: "half" + }); + if (!uploadResponse.ok) + throw new Error("Error uploading file"); + return { + download: { + manifestCid: await uploadResponse.text(), + downloadParams: cipherHandler.downloadParams + }, + delete: deletionToken + }; + }, + "chelonia/fileDownload": async function(downloadOptions, manifestChecker) { + const { manifestCid, downloadParams } = downloadOptions.valueOf(); + const manifestResponse = await this.config.fetch(`${this.config.connectionURL}/file/${manifestCid}`, { + method: "GET", + signal: this.abortController.signal + }); + if (!manifestResponse.ok) { + throw new Error("Unable to retrieve manifest"); + } + const manifestBinary = await manifestResponse.arrayBuffer(); + if (createCID(coerce(manifestBinary), multicodes.SHELTER_FILE_MANIFEST) !== manifestCid) { + throw new Error("mismatched manifest hash"); + } + const manifest2 = JSON.parse(Buffer4.from(manifestBinary).toString()); + if (typeof manifest2 !== "object") + throw new Error("manifest format is invalid"); + if (manifest2.version !== "1.0.0") + throw new Error("unsupported manifest version"); + if (!Array.isArray(manifest2.chunks)) + throw new Error("missing required field: chunks"); + if (manifestChecker) { + const proceed = await manifestChecker?.(manifest2); + if (!proceed) + return false; + } + const cipherHandler = await cipherHandlers[manifest2.cipher]?.download?.(this, downloadParams, manifest2); + if (!cipherHandler) + throw new Error("Unsupported cipher"); + return cipherHandler.payloadHandler(); + }, + "chelonia/fileDelete": async function(manifestCid, credentials = {}) { + if (!manifestCid) { + throw new TypeError("A manifest CID must be provided"); + } + if (!Array.isArray(manifestCid)) + manifestCid = [manifestCid]; + return await Promise.allSettled(manifestCid.map(async (cid) => { + const hasCredential = has(credentials, cid); + const hasToken = has(credentials[cid], "token") && credentials[cid].token; + const hasBillableContractID = has(credentials[cid], "billableContractID") && credentials[cid].billableContractID; + if (!hasCredential || hasToken === hasBillableContractID) { + throw new TypeError(`Either a token or a billable contract ID must be provided for ${cid}`); + } + const response = await this.config.fetch(`${this.config.connectionURL}/deleteFile/${cid}`, { + method: "POST", + signal: this.abortController.signal, + headers: new Headers([ + [ + "authorization", + hasToken ? `bearer ${credentials[cid].token.valueOf()}` : buildShelterAuthorizationHeader.call(this, credentials[cid].billableContractID) + ] + ]) + }); + if (!response.ok) { + throw new Error(`Unable to delete file ${cid}`); } - __check__(weight) { - var _this6 = this; - return _asyncToGenerator2(function* () { - return _this6.convertBool(yield _this6.runScript("check", _this6.prepareArray([weight]))); - })(); + })); + } +}); +init_esm(); +init_functions(); +init_esm4(); +init_SPMessage(); +init_esm6(); +init_db(); +init_encryptedData(); +init_errors3(); +init_signedData(); +var missingDecryptionKeyIdsMap = /* @__PURE__ */ new WeakMap(); +var getMsgMeta = function(message, contractID, state, index) { + const signingKeyId = message.signingKeyId(); + let innerSigningKeyId = null; + const config2 = this.config; + const result = { + signingKeyId, + get signingContractID() { + return getContractIDfromKeyId(contractID, signingKeyId, state); + }, + get innerSigningKeyId() { + if (innerSigningKeyId === null) { + const value = message.message(); + const data = config2.unwrapMaybeEncryptedData(value); + if (data?.data && isSignedData(data.data)) { + innerSigningKeyId = data.data.signingKeyId; + } else { + innerSigningKeyId = void 0; + } + return innerSigningKeyId; } - __register__(index, weight, expiration) { - var _this7 = this; - return _asyncToGenerator2(function* () { - var reservoir, success, wait; - var _ref4 = yield _this7.runScript("register", _this7.prepareArray([index, weight, expiration])); - var _ref5 = _slicedToArray2(_ref4, 3); - success = _ref5[0]; - wait = _ref5[1]; - reservoir = _ref5[2]; - return { - success: _this7.convertBool(success), - wait, - reservoir - }; - })(); + }, + get innerSigningContractID() { + return getContractIDfromKeyId(contractID, result.innerSigningKeyId, state); + }, + index + }; + return result; +}; +var keysToMap = function(keys_, height, authorizedKeys) { + const keys = keys_.map((key) => { + const data = this.config.unwrapMaybeEncryptedData(key); + if (!data) + return void 0; + if (data.encryptionKeyId) { + data.data._private = data.encryptionKeyId; + } + return data.data; + }).filter(Boolean); + const keysCopy = cloneDeep(keys); + return Object.fromEntries(keysCopy.map((key) => { + key._notBeforeHeight = height; + if (authorizedKeys?.[key.id]) { + if (authorizedKeys[key.id]._notAfterHeight == null) { + throw new ChelErrorKeyAlreadyExists(`Cannot set existing unrevoked key: ${key.id}`); + } + key._notBeforeHeight = Math.min(height, authorizedKeys[key.id]._notBeforeHeight ?? 0); + } else { + key._notBeforeHeight = height; + } + delete key._notAfterHeight; + return [key.id, key]; + })); +}; +var keyRotationHelper = (contractID, state, config2, updatedKeysMap, requiredPermissions, outputSelector, outputMapper, internalSideEffectStack) => { + if (!internalSideEffectStack || !Array.isArray(state._volatile?.watch)) + return; + const rootState = esm_default(config2.stateSelector); + const watchMap = /* @__PURE__ */ Object.create(null); + state._volatile.watch.forEach(([name, cID]) => { + if (!updatedKeysMap[name] || watchMap[cID] === null) { + return; + } + if (!watchMap[cID]) { + if (!rootState.contracts[cID]?.type || !findSuitableSecretKeyId(rootState[cID], [SPMessage.OP_KEY_UPDATE], ["sig"])) { + watchMap[cID] = null; + return; } - __submit__(queueLength, weight) { - var _this8 = this; - return _asyncToGenerator2(function* () { - var blocked, e2, maxConcurrent, overweight, reachedHWM, strategy; - try { - var _ref6 = yield _this8.runScript("submit", _this8.prepareArray([queueLength, weight])); - var _ref7 = _slicedToArray2(_ref6, 3); - reachedHWM = _ref7[0]; - blocked = _ref7[1]; - strategy = _ref7[2]; - return { - reachedHWM: _this8.convertBool(reachedHWM), - blocked: _this8.convertBool(blocked), - strategy - }; - } catch (error2) { - e2 = error2; - if (e2.message.indexOf("OVERWEIGHT") === 0) { - var _e$message$split = e2.message.split(":"); - var _e$message$split2 = _slicedToArray2(_e$message$split, 3); - overweight = _e$message$split2[0]; - weight = _e$message$split2[1]; - maxConcurrent = _e$message$split2[2]; - throw new BottleneckError(`Impossible to add a job having a weight of ${weight} to a limiter having a maxConcurrent setting of ${maxConcurrent}`); - } else { - throw e2; - } - } - })(); + watchMap[cID] = []; + } + watchMap[cID].push(name); + }); + Object.entries(watchMap).forEach(([cID, names]) => { + if (!Array.isArray(names) || !names.length) + return; + const [keyNamesToUpdate, signingKeyId] = names.map((name) => { + const foreignContractKey = rootState[cID]?._vm?.authorizedKeys?.[updatedKeysMap[name].oldKeyId]; + if (!foreignContractKey) + return void 0; + const signingKeyId2 = findSuitableSecretKeyId(rootState[cID], requiredPermissions, ["sig"], foreignContractKey.ringLevel); + if (signingKeyId2) { + return [ + [name, foreignContractKey.name], + signingKeyId2, + rootState[cID]._vm.authorizedKeys[signingKeyId2].ringLevel + ]; } - __free__(index, weight) { - var _this9 = this; - return _asyncToGenerator2(function* () { - var running; - running = yield _this9.runScript("free", _this9.prepareArray([index])); - return { - running - }; - })(); + return void 0; + }).filter(Boolean).reduce((acc, [name, signingKeyId2, ringLevel]) => { + acc[0].push(name); + return ringLevel < acc[2] ? [acc[0], signingKeyId2, ringLevel] : acc; + }, [[], void 0, Number.POSITIVE_INFINITY]); + if (!signingKeyId) + return; + const contractName = rootState.contracts[cID]?.type; + internalSideEffectStack?.push(() => { + esm_default(outputSelector, { + contractID: cID, + contractName, + data: keyNamesToUpdate.map(outputMapper).map((v2) => { + return v2; + }), + signingKeyId + }).catch((e2) => { + console.warn(`Error mirroring key operation (${outputSelector}) from ${contractID} to ${cID}: ${e2?.message || e2}`); + }); + }); + }); +}; +var internals_default = esm_default("sbp/selectors/register", { + // DO NOT CALL ANY OF THESE YOURSELF! + "chelonia/private/state": function() { + return this.state; + }, + "chelonia/private/invoke": function(instance, invocation) { + if (this._instance !== instance) { + console.info("['chelonia/private/invoke] Not proceeding with invocation as Chelonia was restarted", { invocation }); + return; + } + if (Array.isArray(invocation)) { + return esm_default(...invocation); + } else if (typeof invocation === "function") { + return invocation(); + } else { + throw new TypeError(`[chelonia/private/invoke] Expected invocation to be an array or a function. Saw ${typeof invocation} instead.`); + } + }, + "chelonia/private/queueEvent": function(queueName, invocation) { + return esm_default("okTurtles.eventQueue/queueEvent", queueName, [ + "chelonia/private/invoke", + this._instance, + invocation + ]); + }, + "chelonia/private/verifyManifestSignature": function(contractName, manifestHash, manifest2) { + if (!has(manifest2, "signature") || typeof manifest2.signature.keyId !== "string" || typeof manifest2.signature.value !== "string") { + throw new Error(`Invalid or missing signature field for manifest ${manifestHash} (named ${contractName})`); + } + const rootState = esm_default(this.config.stateSelector); + if (!has(rootState, "contractSigningKeys")) { + this.config.reactiveSet(rootState, "contractSigningKeys", /* @__PURE__ */ Object.create(null)); + } + const contractNameLookupKey = `name:${contractName}`; + let signatureValidated = false; + if (process.env.UNSAFE_TRUST_ALL_MANIFEST_SIGNING_KEYS !== "true" && has(rootState.contractSigningKeys, contractNameLookupKey)) { + console.info(`[chelonia] verifying signature for ${manifestHash} with an existing key`); + if (!has(rootState.contractSigningKeys[contractNameLookupKey], manifest2.signature.keyId)) { + console.error(`The manifest with ${manifestHash} (named ${contractName}) claims to be signed with a key with ID ${manifest2.signature.keyId}, which is not trusted. The trusted key IDs for this name are:`, Object.keys(rootState.contractSigningKeys[contractNameLookupKey])); + throw new Error(`Invalid or missing signature in manifest ${manifestHash} (named ${contractName}). It claims to be signed with a key with ID ${manifest2.signature.keyId}, which has not been authorized for this contract before.`); + } + const signingKey = rootState.contractSigningKeys[contractNameLookupKey][manifest2.signature.keyId]; + verifySignature(signingKey, manifest2.body + manifest2.head, manifest2.signature.value); + console.info(`[chelonia] successful signature verification for ${manifestHash} (named ${contractName}) using the already-trusted key ${manifest2.signature.keyId}.`); + signatureValidated = true; + } + const body = JSON.parse(manifest2.body); + if (!signatureValidated) { + console.info(`[chelonia] verifying signature for ${manifestHash} (named ${contractName}) for the first time`); + if (!has(body, "signingKeys") || !Array.isArray(body.signingKeys)) { + throw new Error(`Invalid manifest file ${manifestHash} (named ${contractName}). Its body doesn't contain a 'signingKeys' list'`); + } + let contractSigningKeys; + try { + contractSigningKeys = Object.fromEntries(body.signingKeys.map((serializedKey) => { + return [keyId(serializedKey), serializedKey]; + })); + } catch (e2) { + console.error(`[chelonia] Error parsing the public keys list for ${manifestHash} (named ${contractName})`, e2); + throw e2; + } + if (!has(contractSigningKeys, manifest2.signature.keyId)) { + throw new Error(`Invalid or missing signature in manifest ${manifestHash} (named ${contractName}). It claims to be signed with a key with ID ${manifest2.signature.keyId}, which is not listed in its 'signingKeys' field.`); } + verifySignature(contractSigningKeys[manifest2.signature.keyId], manifest2.body + manifest2.head, manifest2.signature.value); + console.info(`[chelonia] successful signature verification for ${manifestHash} (named ${contractName}) using ${manifest2.signature.keyId}. The following key IDs will now be trusted for this contract name`, Object.keys(contractSigningKeys)); + signatureValidated = true; + rootState.contractSigningKeys[contractNameLookupKey] = contractSigningKeys; + } + return body; + }, + "chelonia/private/loadManifest": async function(contractName, manifestHash) { + if (!contractName || typeof contractName !== "string") { + throw new Error("Invalid or missing contract name"); + } + if (this.manifestToContract[manifestHash]) { + console.warn("[chelonia]: already loaded manifest", manifestHash); + return; + } + const manifestSource = await esm_default("chelonia/out/fetchResource", manifestHash, { + code: multicodes.SHELTER_CONTRACT_MANIFEST + }); + const manifest2 = JSON.parse(manifestSource); + const body = esm_default("chelonia/private/verifyManifestSignature", contractName, manifestHash, manifest2); + if (body.name !== contractName) { + throw new Error(`Mismatched contract name. Expected ${contractName} but got ${body.name}`); + } + const contractInfo = this.config.contracts.defaults.preferSlim && body.contractSlim || body.contract; + console.info(`[chelonia] loading contract '${contractInfo.file}'@'${body.version}' from manifest: ${manifestHash}`); + const source = await esm_default("chelonia/out/fetchResource", contractInfo.hash, { + code: multicodes.SHELTER_CONTRACT_TEXT + }); + const reduceAllow = (acc, v2) => { + acc[v2] = true; + return acc; }; - module14.exports = RedisDatastore; - } -}); -var require_States = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/States.js"(exports2, module14) { - "use strict"; - var BottleneckError; - var States; - BottleneckError = require_BottleneckError(); - States = class States { - constructor(status1) { - this.status = status1; - this._jobs = {}; - this.counts = this.status.map(function() { - return 0; + const allowedSels = [ + "okTurtles.events/on", + "chelonia/defineContract", + "chelonia/out/keyRequest" + ].concat(this.config.contracts.defaults.allowedSelectors).reduce(reduceAllow, {}); + const allowedDoms = this.config.contracts.defaults.allowedDomains.reduce(reduceAllow, {}); + const contractSBP = (selector, ...args) => { + const domain = domainFromSelector(selector); + if (selector.startsWith(contractName + "/")) { + selector = `${manifestHash}/${selector}`; + } + if (allowedSels[selector] || allowedDoms[domain]) { + return esm_default(selector, ...args); + } else { + console.error("[chelonia] selector not on allowlist", { + selector, + allowedSels, + allowedDoms }); + throw new Error(`[chelonia] selector not on allowlist: '${selector}'`); } - next(id) { - var current, next; - current = this._jobs[id]; - next = current + 1; - if (current != null && next < this.status.length) { - this.counts[current]--; - this.counts[next]++; - return this._jobs[id]++; - } else if (current != null) { - this.counts[current]--; - return delete this._jobs[id]; - } - } - start(id) { - var initial; - initial = 0; - this._jobs[id] = initial; - return this.counts[initial]++; - } - remove(id) { - var current; - current = this._jobs[id]; - if (current != null) { - this.counts[current]--; - delete this._jobs[id]; + }; + const saferEval = new Function(` + return function (globals) { + // almost a real sandbox + // stops (() => this)().fetch + // needs additional step of locking down Function constructor to stop: + // new (()=>{}).constructor("console.log(typeof this.fetch)")() + globals.self = globals + globals.globalThis = globals + with (new Proxy(globals, { + get (o, p) { return o[p] }, + has (o, p) { /* console.log('has', p); */ return true } + })) { + (function () { + 'use strict' + ${source} + })() } - return current != null; - } - jobStatus(id) { - var ref; - return (ref = this.status[this._jobs[id]]) != null ? ref : null; } - statusJobs(status) { - var k, pos, ref, results, v2; - if (status != null) { - pos = this.status.indexOf(status); - if (pos < 0) { - throw new BottleneckError(`status must be one of ${this.status.join(", ")}`); - } - ref = this._jobs; - results = []; - for (k in ref) { - v2 = ref[k]; - if (v2 === pos) { - results.push(k); - } + `)(); + this.defContractSBP = contractSBP; + this.defContractManifest = manifestHash; + saferEval({ + // pass in globals that we want access to by default in the sandbox + // note: you can undefine these by setting them to undefined in exposedGlobals + crypto: { + getRandomValues: (v2) => globalThis.crypto.getRandomValues(v2) + }, + ...typeof window === "object" && window && { + alert: window.alert.bind(window), + confirm: window.confirm.bind(window), + prompt: window.prompt.bind(window) + }, + isNaN, + console, + Object, + Error, + TypeError, + RangeError, + Math, + Symbol, + Date, + Array, + BigInt, + Boolean, + String, + Number, + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint16Array, + Uint32Array, + Float32Array, + Float64Array, + ArrayBuffer, + JSON, + RegExp, + parseFloat, + parseInt, + Promise, + Function, + Map, + WeakMap, + ...this.config.contracts.defaults.exposedGlobals, + require: (dep) => { + return dep === "@sbp/sbp" ? contractSBP : this.config.contracts.defaults.modules[dep]; + }, + sbp: contractSBP, + fetchServerTime: async (fallback = true) => { + try { + const response = await this.config.fetch(`${this.config.connectionURL}/time`, { + signal: this.abortController.signal + }); + return handleFetchResult("text")(response); + } catch (e2) { + console.warn("[fetchServerTime] Error", e2); + if (fallback) { + return new Date(esm_default("chelonia/time")).toISOString(); } - return results; - } else { - return Object.keys(this._jobs); + throw new ChelErrorFetchServerTimeFailed("Can not fetch server time. Please check your internet connection."); } } - statusCounts() { - return this.counts.reduce((acc, v2, i2) => { - acc[this.status[i2]] = v2; - return acc; - }, {}); - } + }); + if (contractName !== this.defContract.name) { + throw new Error(`Invalid contract name for manifest ${manifestHash}. Expected ${contractName} but got ${this.defContract.name}`); + } + this.defContractSelectors.forEach((s) => { + allowedSels[s] = true; + }); + this.manifestToContract[manifestHash] = { + slim: contractInfo === body.contractSlim, + info: contractInfo, + contract: this.defContract }; - module14.exports = States; - } -}); -var require_Sync = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Sync.js"(exports2, module14) { - "use strict"; - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; + }, + // Warning: avoid using this unless you know what you're doing. Prefer using /remove. + "chelonia/private/removeImmediately": function(contractID, params) { + const state = esm_default(this.config.stateSelector); + const contractName = state.contracts[contractID]?.type; + if (!contractName) { + console.error("[chelonia/private/removeImmediately] Missing contract name for contract", { + contractID + }); + return; + } + const manifestHash = this.config.contracts.manifests[contractName]; + if (manifestHash) { + const destructor = `${manifestHash}/${contractName}/_cleanup`; + if (esm_default("sbp/selectors/fn", destructor)) { + try { + esm_default(destructor, { contractID, resync: !!params?.resync, state: state[contractID] }); + } catch (e2) { + console.error(`[chelonia/private/removeImmediately] Error at destructor for ${contractID}`, e2); + } } - if (info.done) { - resolve82(value); + } + if (params?.resync) { + Object.keys(state.contracts[contractID]).filter((k) => k !== "references").forEach((k) => this.config.reactiveDel(state.contracts[contractID], k)); + Object.keys(state[contractID]).filter((k) => k !== "_volatile").forEach((k) => this.config.reactiveDel(state[contractID], k)); + if (state[contractID]._volatile) { + Object.keys(state[contractID]._volatile).filter((k) => k !== "watch").forEach((k) => this.config.reactiveDel(state[contractID]._volatile, k)); + } + } else { + delete this.ephemeralReferenceCount[contractID]; + if (params?.permanent) { + this.config.reactiveSet(state.contracts, contractID, null); } else { - Promise.resolve(value).then(_next, _throw); + this.config.reactiveDel(state.contracts, contractID); } + this.config.reactiveDel(state, contractID); } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); - } - _next(void 0); - }); - }; - } - var DLList; - var Sync; - DLList = require_DLList(); - Sync = class Sync { - constructor(name, Promise2) { - this.schedule = this.schedule.bind(this); - this.name = name; - this.Promise = Promise2; - this._running = 0; - this._queue = new DLList(); + this.subscriptionSet.delete(contractID); + esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { + added: [], + removed: [contractID], + permanent: params?.permanent, + resync: params?.resync + }); + }, + // used by, e.g. 'chelonia/contract/wait' + "chelonia/private/noop": function() { + }, + "chelonia/private/out/sync": function(contractIDs, params) { + const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; + const forcedSync = !!params?.force; + return Promise.all(listOfIds.map((contractID) => { + if (!forcedSync && this.subscriptionSet.has(contractID)) { + const rootState = esm_default(this.config.stateSelector); + if (!rootState[contractID]?._volatile?.dirty) { + return esm_default("chelonia/private/queueEvent", contractID, ["chelonia/private/noop"]); + } } - isEmpty() { - return this._queue.length === 0; + return esm_default("chelonia/private/queueEvent", contractID, [ + "chelonia/private/in/syncContract", + contractID, + params + ]).catch((err) => { + console.error(`[chelonia] failed to sync ${contractID}:`, err); + throw err; + }); + })); + }, + "chelonia/private/out/publishEvent": function(entry, { maxAttempts = 5, headers, billableContractID, bearer, disableAutoDedup } = {}, hooks) { + const contractID = entry.contractID(); + const originalEntry = entry; + return esm_default("chelonia/private/queueEvent", `publish:${contractID}`, async () => { + let attempt = 1; + let lastAttemptedHeight; + await hooks?.prepublish?.(entry); + const onreceivedHandler = (_contractID, message) => { + if (entry.hash() === message.hash()) { + esm_default("okTurtles.events/off", EVENT_HANDLED, onreceivedHandler); + hooks.onprocessed(entry); + } + }; + if (typeof hooks?.onprocessed === "function") { + esm_default("okTurtles.events/on", EVENT_HANDLED, onreceivedHandler); } - _tryToRun() { - var _this = this; - return _asyncToGenerator2(function* () { - var args, cb, error2, reject, resolve82, returned, task; - if (_this._running < 1 && _this._queue.length > 0) { - _this._running++; - var _this$_queue$shift = _this._queue.shift(); - task = _this$_queue$shift.task; - args = _this$_queue$shift.args; - resolve82 = _this$_queue$shift.resolve; - reject = _this$_queue$shift.reject; - cb = yield _asyncToGenerator2(function* () { - try { - returned = yield task(...args); - return function() { - return resolve82(returned); - }; - } catch (error1) { - error2 = error1; - return function() { - return reject(error2); - }; - } - })(); - _this._running--; - _this._tryToRun(); - return cb(); + while (true) { + lastAttemptedHeight = entry.height(); + const newEntry = await esm_default("chelonia/private/queueEvent", contractID, async () => { + const rootState = esm_default(this.config.stateSelector); + const state = rootState[contractID]; + const isFirstMessage = entry.isFirstMessage(); + if (!state && !isFirstMessage) { + console.info(`[chelonia] Not sending message as contract state has been removed: ${entry.description()}`); + return; } - })(); - } - schedule(task, ...args) { - var promise, reject, resolve82; - resolve82 = reject = null; - promise = new this.Promise(function(_resolve, _reject) { - resolve82 = _resolve; - return reject = _reject; + if (hooks?.preSendCheck) { + if (!await hooks.preSendCheck(entry, state)) { + console.info(`[chelonia] Not sending message as preSendCheck hook returned non-truish value: ${entry.description()}`); + return; + } + } + await esm_default("chelonia/private/in/processMessage", entry, cloneDeep(state || {})); + if (!isFirstMessage) { + return recreateEvent(entry, state, rootState.contracts[contractID], disableAutoDedup); + } + return entry; }); - this._queue.push({ - task, - args, - resolve: resolve82, - reject + if (!newEntry) + return; + await hooks?.beforeRequest?.(newEntry, entry); + entry = newEntry; + const r = await this.config.fetch(`${this.config.connectionURL}/event`, { + method: "POST", + body: entry.serialize(), + headers: { + ...headers, + ...bearer && { + Authorization: `Bearer ${bearer}` + }, + ...billableContractID && { + Authorization: buildShelterAuthorizationHeader.call(this, billableContractID) + }, + "Content-Type": "text/plain" + }, + signal: this.abortController.signal }); - this._tryToRun(); - return promise; - } - }; - module14.exports = Sync; - } -}); -var require_version = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/version.json"(exports2, module14) { - module14.exports = { version: "2.19.5" }; - } -}); -var require_Group = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Group.js"(exports2, module14) { - "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); - } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; + if (r.ok) { + await hooks?.postpublish?.(entry); + return entry; } - } catch (err) { - _d = true; - _e = err; - } finally { try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + if (r.status === 409) { + if (attempt + 1 > maxAttempts) { + console.error(`[chelonia] failed to publish ${entry.description()} after ${attempt} attempts`, entry); + throw new Error(`publishEvent: ${r.status} - ${r.statusText}. attempt ${attempt}`); + } + const randDelay = randomIntFromRange(0, 1500); + console.warn(`[chelonia] publish attempt ${attempt} of ${maxAttempts} failed. Waiting ${randDelay} msec before resending ${entry.description()}`); + attempt += 1; + await delay(randDelay); + if (!entry.isFirstMessage() && entry.height() === lastAttemptedHeight) { + await esm_default("chelonia/private/out/sync", contractID, { force: true }); + } + } else { + const message = (await r.json())?.message; + console.error(`[chelonia] ERROR: failed to publish ${entry.description()}: ${r.status} - ${r.statusText}: ${message}`, entry); + throw new Error(`publishEvent: ${r.status} - ${r.statusText}: ${message}`); + } + } catch (e2) { + esm_default("okTurtles.events/off", EVENT_HANDLED, onreceivedHandler); + throw e2; } } - return _arr; - } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; - } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); - return; - } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + }).then((entry2) => { + esm_default("okTurtles.events/emit", EVENT_PUBLISHED, { + contractID, + message: entry2, + originalMessage: originalEntry + }); + return entry2; + }).catch((e2) => { + esm_default("okTurtles.events/emit", EVENT_PUBLISHING_ERROR, { + contractID, + message: entry, + originalMessage: originalEntry, + error: e2 + }); + throw e2; + }); + }, + "chelonia/private/out/latestHEADinfo": function(contractID) { + return this.config.fetch(`${this.config.connectionURL}/latestHEADinfo/${contractID}`, { + cache: "no-store", + signal: this.abortController.signal + }).then(handleFetchResult("json")); + }, + "chelonia/private/postKeyShare": function(contractID, previousVolatileState, signingKey) { + const cheloniaState = esm_default(this.config.stateSelector); + const targetState = cheloniaState[contractID]; + if (!targetState) + return; + if (previousVolatileState && has(previousVolatileState, "watch")) { + if (!targetState._volatile) { + this.config.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); + } + if (!targetState._volatile.watch) { + this.config.reactiveSet(targetState._volatile, "watch", previousVolatileState.watch); + } else if (targetState._volatile.watch !== previousVolatileState.watch) { + previousVolatileState.watch.forEach((pWatch) => { + if (!targetState._volatile.watch.some((tWatch) => { + return tWatch[0] === pWatch[0] && tWatch[1] === pWatch[1]; + })) { + targetState._volatile.watch.push(pWatch); } - _next(void 0); }); - }; + } } - var Events2; - var Group; - var IORedisConnection2; - var RedisConnection2; - var Scripts2; - var parser3; - parser3 = require_parser2(); - Events2 = require_Events(); - RedisConnection2 = require_RedisConnection(); - IORedisConnection2 = require_IORedisConnection(); - Scripts2 = require_Scripts(); - Group = function() { - class Group2 { - constructor(limiterOptions = {}) { - this.deleteKey = this.deleteKey.bind(this); - this.limiterOptions = limiterOptions; - parser3.load(this.limiterOptions, this.defaults, this); - this.Events = new Events2(this); - this.instances = {}; - this.Bottleneck = require_Bottleneck(); - this._startAutoCleanup(); - this.sharedConnection = this.connection != null; - if (this.connection == null) { - if (this.limiterOptions.datastore === "redis") { - this.connection = new RedisConnection2(Object.assign({}, this.limiterOptions, { - Events: this.Events - })); - } else if (this.limiterOptions.datastore === "ioredis") { - this.connection = new IORedisConnection2(Object.assign({}, this.limiterOptions, { - Events: this.Events - })); + if (!Array.isArray(targetState._volatile?.pendingKeyRequests)) + return; + this.config.reactiveSet(targetState._volatile, "pendingKeyRequests", targetState._volatile.pendingKeyRequests.filter((pkr) => pkr?.name !== signingKey.name)); + }, + "chelonia/private/in/processMessage": async function(message, state, internalSideEffectStack, contractName) { + const [opT, opV] = message.op(); + const hash3 = message.hash(); + const height = message.height(); + const contractID = message.contractID(); + const manifestHash = message.manifest(); + const signingKeyId = message.signingKeyId(); + const direction = message.direction(); + const config2 = this.config; + const self2 = this; + const opName = Object.entries(SPMessage).find(([, y]) => y === opT)?.[0]; + console.debug("PROCESSING OPCODE:", opName, "to", contractID); + if (state?._volatile?.dirty) { + console.debug("IGNORING OPCODE BECAUSE CONTRACT STATE IS MARKED AS DIRTY.", "OPCODE:", opName, "CONTRACT:", contractID); + return; + } + if (!state._vm) + state._vm = /* @__PURE__ */ Object.create(null); + const opFns = { + /* + There are two types of "errors" that we need to consider: + 1. "Ignoring" errors + 2. "Failure" errors + Example: OP_KEY_ADD + 1. IGNORING: an error is thrown because we wanted to add a key but the + key we wanted to add is already there. This is not a hard error, it's an + ignoring error. We don't care that the operation failed in this case because the intent was accomplished. + 2. FAILURE: an error is thrown while attempting to add a key that doesn't exist. + Example: OP_ACTION_ENCRYPTED + 1. IGNORING: An error is thrown because we don't have the key to decrypt the action. We ignore it. + 2. FAILURE: An error is thrown by the process function during processing. + Handling these in OP_ATOMIC + • ALL errors of class "IGNORING" should be ignored. They should not + impact our ability to process the rest of the operations in the OP_ATOMIC. + No matter how many of these are thrown, it doesn't affect the rest of the operations. + • ANY error of class "FAILURE" will call the rest of the operations to + fail and the state to be reverted to prior to the OP_ATOMIC. No side-effects should be run. Because an intention failed. + */ + async [SPMessage.OP_ATOMIC](v2) { + for (let i2 = 0; i2 < v2.length; i2++) { + const u2 = v2[i2]; + try { + if (u2[0] === SPMessage.OP_ATOMIC) + throw new Error("Cannot nest OP_ATOMIC"); + if (!validateKeyPermissions(message, config2, state, signingKeyId, u2[0], u2[1])) { + throw new Error("Inside OP_ATOMIC: no matching signing key was defined"); + } + await opFns[u2[0]](u2[1]); + } catch (e_) { + const e2 = e_; + if (e2 && typeof e2 === "object") { + if (e2.name === "ChelErrorDecryptionKeyNotFound") { + console.warn(`[chelonia] [OP_ATOMIC] WARN '${e2.name}' in processMessage for ${message.description()}: ${e2.message}`, e2, message.serialize()); + if (e2.cause) { + const missingDecryptionKeyIds = missingDecryptionKeyIdsMap.get(message); + if (missingDecryptionKeyIds) { + missingDecryptionKeyIds.add(e2.cause); + } else { + missingDecryptionKeyIdsMap.set(message, /* @__PURE__ */ new Set([e2.cause])); + } + } + continue; + } else { + logEvtError(message, `[chelonia] [OP_ATOMIC] ERROR '${e2.name}' in processMessage for ${message.description()}: ${e2.message || e2}`, e2, message.serialize()); + } + console.warn(`[chelonia] [OP_ATOMIC] Error processing ${message.description()}: ${message.serialize()}. Any side effects will be skipped!`); + if (config2.strictProcessing) { + throw e2; + } + config2.hooks.processError?.(e2, message, getMsgMeta.call(self2, message, contractID, state)); + if (e2.name === "ChelErrorWarning") + continue; + } else { + logEvtError(message, "Inside OP_ATOMIC: Non-object or null error thrown", contractID, message, i2, e2); } + throw e2; } } - key(key = "") { - var ref; - return (ref = this.instances[key]) != null ? ref : (() => { - var limiter; - limiter = this.instances[key] = new this.Bottleneck(Object.assign(this.limiterOptions, { - id: `${this.id}-${key}`, - timeout: this.timeout, - connection: this.connection - })); - this.Events.trigger("created", limiter, key); - return limiter; - })(); + }, + [SPMessage.OP_CONTRACT](v2) { + state._vm.type = v2.type; + const keys = keysToMap.call(self2, v2.keys, height); + state._vm.authorizedKeys = keys; + keyAdditionProcessor.call(self2, message, hash3, v2.keys, state, contractID, signingKey, internalSideEffectStack); + }, + [SPMessage.OP_ACTION_ENCRYPTED](v2) { + if (config2.skipActionProcessing) { + if (!config2.skipDecryptionAttempts) { + console.log("OP_ACTION_ENCRYPTED: skipped action processing"); + } + return; } - deleteKey(key = "") { - var _this = this; - return _asyncToGenerator2(function* () { - var deleted, instance; - instance = _this.instances[key]; - if (_this.connection) { - deleted = yield _this.connection.__runCommand__(["del", ...Scripts2.allKeys(`${_this.id}-${key}`)]); + return opFns[SPMessage.OP_ACTION_UNENCRYPTED](v2.valueOf()); + }, + async [SPMessage.OP_ACTION_UNENCRYPTED](v2) { + if (!config2.skipActionProcessing) { + let innerSigningKeyId; + if (isSignedData(v2)) { + innerSigningKeyId = v2.signingKeyId; + v2 = v2.valueOf(); + } + const { data, meta, action } = v2; + if (!config2.whitelisted(action)) { + throw new Error(`chelonia: action not whitelisted: '${action}'`); + } + await esm_default(`${manifestHash}/${action}/process`, { + data, + meta, + hash: hash3, + height, + contractID, + direction: message.direction(), + signingKeyId, + get signingContractID() { + return getContractIDfromKeyId(contractID, signingKeyId, state); + }, + innerSigningKeyId, + get innerSigningContractID() { + return getContractIDfromKeyId(contractID, innerSigningKeyId, state); } - if (instance != null) { - delete _this.instances[key]; - yield instance.disconnect(); + }, state); + } + }, + [SPMessage.OP_KEY_SHARE](wv) { + const data = config2.unwrapMaybeEncryptedData(wv); + if (!data) + return; + const v2 = data.data; + for (const key of v2.keys) { + if (key.id && key.meta?.private?.content) { + if (!has(state._vm, "sharedKeyIds")) + state._vm.sharedKeyIds = []; + if (!state._vm.sharedKeyIds.some((sK) => sK.id === key.id)) { + state._vm.sharedKeyIds.push({ + id: key.id, + contractID: v2.contractID, + height, + keyRequestHash: v2.keyRequestHash, + keyRequestHeight: v2.keyRequestHeight + }); } - return instance != null || deleted > 0; - })(); + } } - limiters() { - var k, ref, results, v2; - ref = this.instances; - results = []; - for (k in ref) { - v2 = ref[k]; - results.push({ - key: k, - limiter: v2 + if (has(v2, "keyRequestHash") && state._vm.authorizedKeys[signingKeyId].meta?.keyRequest) { + state._vm.authorizedKeys[signingKeyId].meta.keyRequest.responded = hash3; + } + internalSideEffectStack?.push(async () => { + delete self2.postSyncOperations[contractID]?.["pending-keys-for-" + v2.contractID]; + const cheloniaState = esm_default(self2.config.stateSelector); + const targetState = cheloniaState[v2.contractID]; + const missingDecryptionKeyIds = cheloniaState.contracts[v2.contractID]?.missingDecryptionKeyIds; + let newestEncryptionKeyHeight = Number.POSITIVE_INFINITY; + for (const key of v2.keys) { + if (key.id && key.meta?.private?.content) { + const transient = direction === "outgoing" || key.meta.private.transient; + if (!esm_default("chelonia/haveSecretKey", key.id, !transient)) { + try { + const decrypted = key.meta.private.content.valueOf(); + esm_default("chelonia/storeSecretKeys", new Secret([ + { + key: deserializeKey(decrypted), + transient + } + ])); + if (missingDecryptionKeyIds?.includes(key.id)) { + newestEncryptionKeyHeight = Number.NEGATIVE_INFINITY; + } else if ( + // Otherwise, we make an educated guess on whether a re-sync + // is needed based on the height. + targetState?._vm?.authorizedKeys?.[key.id]?._notBeforeHeight != null && Array.isArray(targetState._vm.authorizedKeys[key.id].purpose) && targetState._vm.authorizedKeys[key.id].purpose.includes("enc") + ) { + newestEncryptionKeyHeight = Math.min(newestEncryptionKeyHeight, targetState._vm.authorizedKeys[key.id]._notBeforeHeight); + } + } catch (e_) { + const e2 = e_; + if (e2?.name === "ChelErrorDecryptionKeyNotFound") { + console.warn(`OP_KEY_SHARE (${hash3} of ${contractID}) missing secret key: ${e2.message}`, e2); + } else { + console.error(`OP_KEY_SHARE (${hash3} of ${contractID}) error '${e2.message || e2}':`, e2); + } + } + } + } + } + const mustResync = !!(newestEncryptionKeyHeight < cheloniaState.contracts[v2.contractID]?.height); + if (mustResync) { + if (!has(targetState, "_volatile")) { + config2.reactiveSet(targetState, "_volatile", /* @__PURE__ */ Object.create(null)); + } + config2.reactiveSet(targetState._volatile, "dirty", true); + if (!Object.keys(targetState).some((k) => k !== "_volatile")) { + return; + } + const keyDict = /* @__PURE__ */ Object.create(null); + targetState._volatile?.watch?.forEach(([keyName, contractID2]) => { + if (!keyDict[keyName]) { + keyDict[keyName] = [contractID2]; + return; + } + keyDict[keyName].push(contractID2); + }); + const contractIdsToUpdate = Array.from(new Set(Object.entries(keyDict).flatMap(([keyName, contractIDs]) => { + const keyId2 = findKeyIdByName(targetState, keyName); + if ( + // Does the key exist? (i.e., is it a current key) + keyId2 && // Is it an encryption key? (signing keys don't build up a + // potentially invalid state because the private key isn't + // required for validation; however, missing encryption keys + // prevent message processing) + targetState._vm.authorizedKeys[keyId2].purpose.includes("enc") && // Is this a newly set key? (avoid re-syncing contracts that + // haven't been affected by the `OP_KEY_SHARE`) + targetState._vm.authorizedKeys[keyId2]._notBeforeHeight >= newestEncryptionKeyHeight + ) { + return contractIDs; + } + return []; + }))); + contractIdsToUpdate.forEach((contractID2) => { + const targetState2 = cheloniaState[contractID2]; + if (!targetState2) + return; + if (!has(targetState2, "_volatile")) { + config2.reactiveSet(targetState2, "_volatile", /* @__PURE__ */ Object.create(null)); + } + config2.reactiveSet(targetState2._volatile, "dirty", true); + }); + if (self2.subscriptionSet.has(v2.contractID)) { + const resync = esm_default("chelonia/private/queueEvent", v2.contractID, [ + "chelonia/private/in/syncContract", + v2.contractID + ]).then(() => { + esm_default("chelonia/private/out/sync", contractIdsToUpdate.filter((contractID2) => { + return self2.subscriptionSet.has(contractID2); + }), { force: true, resync: true }).catch((e2) => { + console.error("[chelonia] Error resyncing contracts with foreign key references after key rotation", e2); + }); + }).catch((e2) => { + console.error(`[chelonia] Error during sync for ${v2.contractID} during OP_KEY_SHARE for ${contractID}`); + if (v2.contractID === contractID) { + throw e2; + } + }); + if (v2.contractID !== contractID) { + await resync; + } + } + } + const previousVolatileState = targetState?._volatile; + esm_default("chelonia/private/queueEvent", v2.contractID, [ + "chelonia/private/postKeyShare", + v2.contractID, + mustResync ? previousVolatileState : null, + signingKey + ]).then(() => { + esm_default("chelonia/private/queueEvent", contractID, () => { + esm_default("okTurtles.events/emit", CONTRACT_HAS_RECEIVED_KEYS, { + contractID: v2.contractID, + sharedWithContractID: contractID, + signingKeyId, + get signingKeyName() { + return state._vm?.authorizedKeys?.[signingKeyId]?.name; + } + }); + }).catch((e2) => { + console.error(`[chelonia] Error while emitting the CONTRACT_HAS_RECEIVED_KEYS event for ${contractID}`, e2); }); + }); + }); + }, + [SPMessage.OP_KEY_REQUEST](wv) { + const data = config2.unwrapMaybeEncryptedData(wv); + const v2 = data?.data || { + contractID: "(private)", + replyWith: { context: void 0 }, + request: "*" + }; + const originatingContractID = v2.contractID; + if (state._vm?.invites?.[signingKeyId]?.quantity != null) { + if (state._vm.invites[signingKeyId].quantity > 0) { + if (--state._vm.invites[signingKeyId].quantity <= 0) { + state._vm.invites[signingKeyId].status = INVITE_STATUS.USED; + } + } else { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it exceeds allowed quantity: " + originatingContractID); + return; } - return results; } - keys() { - return Object.keys(this.instances); + if (state._vm?.invites?.[signingKeyId]?.expires != null) { + if (state._vm.invites[signingKeyId].expires < Date.now()) { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it expired at " + state._vm.invites[signingKeyId].expires + ": " + originatingContractID); + return; + } } - clusterKeys() { - var _this2 = this; - return _asyncToGenerator2(function* () { - var cursor, end, found, i2, k, keys, len, next, start; - if (_this2.connection == null) { - return _this2.Promise.resolve(_this2.keys()); - } - keys = []; - cursor = null; - start = `b_${_this2.id}-`.length; - end = "_settings".length; - while (cursor !== 0) { - var _ref = yield _this2.connection.__runCommand__(["scan", cursor != null ? cursor : 0, "match", `b_${_this2.id}-*_settings`, "count", 1e4]); - var _ref2 = _slicedToArray2(_ref, 2); - next = _ref2[0]; - found = _ref2[1]; - cursor = ~~next; - for (i2 = 0, len = found.length; i2 < len; i2++) { - k = found[i2]; - keys.push(k.slice(start, -end)); - } + if (config2.skipActionProcessing || direction === "outgoing") { + return; + } + if (!has(v2.replyWith, "context")) { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it is missing the context attribute"); + return; + } + const context = v2.replyWith.context; + if (data && (!Array.isArray(context) || context[0] !== originatingContractID)) { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it is signed by the wrong contract"); + return; + } + if (v2.request !== "*") { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it has an unsupported request attribute", v2.request); + return; + } + if (!state._vm.pendingKeyshares) + state._vm.pendingKeyshares = /* @__PURE__ */ Object.create(null); + state._vm.pendingKeyshares[message.hash()] = context ? [ + // Full-encryption (i.e., KRS encryption) requires that this request + // was encrypted and that the invite is marked as private + !!data?.encryptionKeyId, + message.height(), + signingKeyId, + context + ] : [!!data?.encryptionKeyId, message.height(), signingKeyId]; + if (data) { + internalSideEffectStack?.push(() => { + self2.setPostSyncOp(contractID, "respondToAllKeyRequests-" + message.contractID(), [ + "chelonia/private/respondToAllKeyRequests", + contractID + ]); + }); + } + }, + [SPMessage.OP_KEY_REQUEST_SEEN](wv) { + if (config2.skipActionProcessing) { + return; + } + const data = config2.unwrapMaybeEncryptedData(wv); + if (!data) + return; + const v2 = data.data; + if (state._vm.pendingKeyshares && v2.keyRequestHash in state._vm.pendingKeyshares) { + const hash4 = v2.keyRequestHash; + const pending = state._vm.pendingKeyshares[hash4]; + delete state._vm.pendingKeyshares[hash4]; + if (pending.length !== 4) + return; + const keyId2 = pending[2]; + const originatingContractID = pending[3][0]; + if (Array.isArray(state._vm?.invites?.[keyId2]?.responses)) { + state._vm?.invites?.[keyId2]?.responses.push(originatingContractID); + } + if (!has(state._vm, "keyshares")) + state._vm.keyshares = /* @__PURE__ */ Object.create(null); + const success = v2.success; + state._vm.keyshares[hash4] = { + contractID: originatingContractID, + height, + success, + ...success && { + hash: v2.keyShareHash } - return keys; - })(); + }; } - _startAutoCleanup() { - var _this3 = this; - var base2; - clearInterval(this.interval); - return typeof (base2 = this.interval = setInterval( - /* @__PURE__ */ _asyncToGenerator2(function* () { - var e2, k, ref, results, time3, v2; - time3 = Date.now(); - ref = _this3.instances; - results = []; - for (k in ref) { - v2 = ref[k]; - try { - if (yield v2._store.__groupCheck__(time3)) { - results.push(_this3.deleteKey(k)); - } else { - results.push(void 0); + }, + [SPMessage.OP_PROP_DEL]: notImplemented, + [SPMessage.OP_PROP_SET](v2) { + if (!state._vm.props) + state._vm.props = {}; + state._vm.props[v2.key] = v2.value; + }, + [SPMessage.OP_KEY_ADD](v2) { + const keys = keysToMap.call(self2, v2, height, state._vm.authorizedKeys); + const keysArray = Object.values(v2); + keysArray.forEach((k) => { + if (has(state._vm.authorizedKeys, k.id) && state._vm.authorizedKeys[k.id]._notAfterHeight == null) { + throw new ChelErrorWarning("Cannot use OP_KEY_ADD on existing keys. Key ID: " + k.id); + } + }); + validateKeyAddPermissions.call(self2, contractID, signingKey, state, v2); + state._vm.authorizedKeys = { ...state._vm.authorizedKeys, ...keys }; + keyAdditionProcessor.call(self2, message, hash3, v2, state, contractID, signingKey, internalSideEffectStack); + }, + [SPMessage.OP_KEY_DEL](v2) { + if (!state._vm.authorizedKeys) + state._vm.authorizedKeys = /* @__PURE__ */ Object.create(null); + if (!state._volatile) + state._volatile = /* @__PURE__ */ Object.create(null); + if (!state._volatile.pendingKeyRevocations) { + state._volatile.pendingKeyRevocations = /* @__PURE__ */ Object.create(null); + } + validateKeyDelPermissions.call(self2, contractID, signingKey, state, v2); + const keyIds = v2.map((k) => { + const data = config2.unwrapMaybeEncryptedData(k); + if (!data) + return void 0; + return data.data; + }).filter((keyId2) => { + if (!keyId2 || typeof keyId2 !== "string") + return false; + if (!has(state._vm.authorizedKeys, keyId2) || state._vm.authorizedKeys[keyId2]._notAfterHeight != null) { + console.warn("Attempted to delete non-existent key from contract", { + contractID, + keyId: keyId2 + }); + return false; + } + return true; + }); + keyIds.forEach((keyId2) => { + const key = state._vm.authorizedKeys[keyId2]; + state._vm.authorizedKeys[keyId2]._notAfterHeight = height; + if (has(state._volatile.pendingKeyRevocations, keyId2)) { + delete state._volatile.pendingKeyRevocations[keyId2]; + } + if (key.foreignKey) { + const fkUrl = new URL(key.foreignKey); + const foreignContract = fkUrl.pathname; + const foreignKeyName = fkUrl.searchParams.get("keyName"); + if (!foreignContract || !foreignKeyName) { + throw new Error("Invalid foreign key: missing contract or key name"); + } + internalSideEffectStack?.push(() => { + esm_default("chelonia/private/queueEvent", foreignContract, () => { + const rootState = esm_default(config2.stateSelector); + if (Array.isArray(rootState[foreignContract]?._volatile?.watch)) { + const oldWatch = rootState[foreignContract]._volatile.watch; + rootState[foreignContract]._volatile.watch = oldWatch.filter(([name, cID]) => name !== foreignKeyName || cID !== contractID); + if (oldWatch.length !== rootState[foreignContract]._volatile.watch.length) { + esm_default("chelonia/contract/release", foreignContract, { try: true }).catch((e2) => { + console.error(`[chelonia] Error at OP_KEY_DEL internalSideEffectStack while attempting to release foreign contract ${foreignContract}`, e2); + }); } - } catch (error2) { - e2 = error2; - results.push(v2.Events.trigger("error", e2)); } - } - return results; - }), - this.timeout / 2 - )).unref === "function" ? base2.unref() : void 0; - } - updateSettings(options2 = {}) { - parser3.overwrite(options2, this.defaults, this); - parser3.overwrite(options2, options2, this.limiterOptions); - if (options2.timeout != null) { - return this._startAutoCleanup(); + }).catch((e2) => { + console.error("Error stopping watching events after removing key", { contractID, foreignContract, foreignKeyName, fkUrl }, e2); + }); + }); + const pendingWatch = state._vm.pendingWatch?.[foreignContract]; + if (pendingWatch) { + state._vm.pendingWatch[foreignContract] = pendingWatch.filter(([, kId]) => kId !== keyId2); + } + } + if (key.name.startsWith("#inviteKey-") && state._vm.invites[key.id]) { + state._vm.invites[key.id].status = INVITE_STATUS.REVOKED; } + }); + if (Array.isArray(state._volatile?.watch)) { + const updatedKeysMap = /* @__PURE__ */ Object.create(null); + keyIds.forEach((keyId2) => { + updatedKeysMap[state._vm.authorizedKeys[keyId2].name] = { + name: state._vm.authorizedKeys[keyId2].name, + oldKeyId: keyId2 + }; + }); + keyRotationHelper(contractID, state, config2, updatedKeysMap, [SPMessage.OP_KEY_DEL], "chelonia/out/keyDel", (name) => updatedKeysMap[name[0]].oldKeyId, internalSideEffectStack); } - disconnect(flush = true) { - var ref; - if (!this.sharedConnection) { - return (ref = this.connection) != null ? ref.disconnect(flush) : void 0; + }, + [SPMessage.OP_KEY_UPDATE](v2) { + if (!state._volatile) + state._volatile = /* @__PURE__ */ Object.create(null); + if (!state._volatile.pendingKeyRevocations) { + state._volatile.pendingKeyRevocations = /* @__PURE__ */ Object.create(null); + } + const [updatedKeys, updatedMap] = validateKeyUpdatePermissions.call(self2, contractID, signingKey, state, v2); + const keysToDelete = Object.values(updatedMap); + for (const keyId2 of keysToDelete) { + if (has(state._volatile.pendingKeyRevocations, keyId2)) { + delete state._volatile.pendingKeyRevocations[keyId2]; } + state._vm.authorizedKeys[keyId2]._notAfterHeight = height; } - } - ; - Group2.prototype.defaults = { - timeout: 1e3 * 60 * 5, - connection: null, - Promise, - id: "group-key" - }; - return Group2; - }.call(void 0); - module14.exports = Group; - } -}); -var require_Batcher = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Batcher.js"(exports2, module14) { - "use strict"; - var Batcher; - var Events2; - var parser3; - parser3 = require_parser2(); - Events2 = require_Events(); - Batcher = function() { - class Batcher2 { - constructor(options2 = {}) { - this.options = options2; - parser3.load(this.options, this.defaults, this); - this.Events = new Events2(this); - this._arr = []; - this._resetPromise(); - this._lastFlush = Date.now(); + for (const key of updatedKeys) { + if (!has(state._vm.authorizedKeys, key.id)) { + key._notBeforeHeight = height; + state._vm.authorizedKeys[key.id] = cloneDeep(key); + } } - _resetPromise() { - return this._promise = new this.Promise((res, rej) => { - return this._resolve = res; + keyAdditionProcessor.call(self2, message, hash3, updatedKeys, state, contractID, signingKey, internalSideEffectStack); + if (Array.isArray(state._volatile?.watch)) { + const updatedKeysMap = /* @__PURE__ */ Object.create(null); + updatedKeys.forEach((key) => { + if (key.data) { + updatedKeysMap[key.name] = cloneDeep(key); + updatedKeysMap[key.name].oldKeyId = updatedMap[key.id]; + } }); + keyRotationHelper(contractID, state, config2, updatedKeysMap, [SPMessage.OP_KEY_UPDATE], "chelonia/out/keyUpdate", (name) => ({ + name: name[1], + oldKeyId: updatedKeysMap[name[0]].oldKeyId, + id: updatedKeysMap[name[0]].id, + data: updatedKeysMap[name[0]].data + }), internalSideEffectStack); } - _flush() { - clearTimeout(this._timeout); - this._lastFlush = Date.now(); - this._resolve(); - this.Events.trigger("batch", this._arr); - this._arr = []; - return this._resetPromise(); + }, + [SPMessage.OP_PROTOCOL_UPGRADE]: notImplemented + }; + if (!this.config.skipActionProcessing && !this.manifestToContract[manifestHash]) { + const rootState = esm_default(this.config.stateSelector); + if (!contractName) { + contractName = has(rootState.contracts, contractID) && rootState.contracts[contractID] && has(rootState.contracts[contractID], "type") ? rootState.contracts[contractID].type : opT === SPMessage.OP_CONTRACT ? opV.type : ""; + } + if (!contractName) { + throw new Error(`Unable to determine the name for a contract and refusing to load it (contract ID was ${contractID} and its manifest hash was ${manifestHash})`); + } + await esm_default("chelonia/private/loadManifest", contractName, manifestHash); + } + let processOp = true; + if (config2.preOp) { + processOp = config2.preOp(message, state) !== false && processOp; + } + let signingKey; + { + const stateForValidation = opT === SPMessage.OP_CONTRACT && !state?._vm?.authorizedKeys ? { + _vm: { + authorizedKeys: keysToMap.call(this, opV.keys, height) } - add(data) { - var ret; - this._arr.push(data); - ret = this._promise; - if (this._arr.length === this.maxSize) { - this._flush(); - } else if (this.maxTime != null && this._arr.length === 1) { - this._timeout = setTimeout(() => { - return this._flush(); - }, this.maxTime); + } : state; + if (!validateKeyPermissions(message, config2, stateForValidation, signingKeyId, opT, opV)) { + throw new Error("No matching signing key was defined"); + } + signingKey = stateForValidation._vm.authorizedKeys[signingKeyId]; + } + if (config2[`preOp_${opT}`]) { + processOp = config2[`preOp_${opT}`](message, state) !== false && processOp; + } + if (processOp) { + await opFns[opT](opV); + config2.postOp?.(message, state); + config2[`postOp_${opT}`]?.(message, state); + } + }, + "chelonia/private/in/enqueueHandleEvent": function(contractID, event) { + return esm_default("chelonia/private/queueEvent", contractID, async () => { + await esm_default("chelonia/private/in/handleEvent", contractID, event); + esm_default("chelonia/private/enqueuePostSyncOps", contractID); + }); + }, + "chelonia/private/in/syncContract": async function(contractID, params) { + const state = esm_default(this.config.stateSelector); + if (state.contracts[contractID] === null) { + throw new ChelErrorResourceGone("Cannot sync permanently deleted contract " + contractID); + } + try { + this.currentSyncs[contractID] = { firstSync: !state.contracts[contractID]?.type }; + esm_default("okTurtles.events/emit", CONTRACT_IS_SYNCING, contractID, true); + const currentVolatileState = state[contractID]?._volatile || /* @__PURE__ */ Object.create(null); + if (currentVolatileState?.dirty || params?.resync) { + delete currentVolatileState.dirty; + currentVolatileState.resyncing = true; + esm_default("chelonia/private/removeImmediately", contractID, { resync: true }); + this.config.reactiveSet(state, contractID, /* @__PURE__ */ Object.create(null)); + this.config.reactiveSet(state[contractID], "_volatile", currentVolatileState); + } + const { HEAD: latestHEAD } = await esm_default("chelonia/out/latestHEADInfo", contractID); + console.debug(`[chelonia] syncContract: ${contractID} latestHash is: ${latestHEAD}`); + const { HEAD: recentHEAD, height: recentHeight } = state.contracts[contractID] || {}; + const isSubscribed = this.subscriptionSet.has(contractID); + if (!isSubscribed) { + const entry = this.pending.find((entry2) => entry2?.contractID === contractID); + if (!entry) { + this.pending.push({ contractID }); + } + } + this.postSyncOperations[contractID] = this.postSyncOperations[contractID] ?? /* @__PURE__ */ Object.create(null); + if (latestHEAD !== recentHEAD) { + console.debug(`[chelonia] Synchronizing Contract ${contractID}: our recent was ${recentHEAD || "undefined"} but the latest is ${latestHEAD}`); + const eventsStream = esm_default("chelonia/out/eventsAfter", contractID, { + sinceHeight: recentHeight ?? 0, + sinceHash: recentHEAD ?? contractID + }); + let latestHashFound = false; + const eventReader = eventsStream.getReader(); + for (let skip = has(state.contracts, contractID) && has(state.contracts[contractID], "HEAD"); ; skip = false) { + const { done, value: event } = await eventReader.read(); + if (done) { + if (!latestHashFound) { + throw new ChelErrorForkedChain(`expected hash ${latestHEAD} in list of events for contract ${contractID}`); + } + break; } - return ret; + if (!latestHashFound) { + latestHashFound = SPMessage.deserializeHEAD(event).hash === latestHEAD; + } + if (skip) + continue; + await esm_default("chelonia/private/in/handleEvent", contractID, event); + } + } else if (!isSubscribed) { + this.subscriptionSet.add(contractID); + esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { + added: [contractID], + removed: [] + }); + const entryIndex = this.pending.findIndex((entry) => entry?.contractID === contractID); + if (entryIndex !== -1) { + this.pending.splice(entryIndex, 1); } + console.debug(`[chelonia] added already synchronized ${contractID} to subscription set`); + } else { + console.debug(`[chelonia] contract ${contractID} was already synchronized`); } - ; - Batcher2.prototype.defaults = { - maxTime: null, - maxSize: null, - Promise - }; - return Batcher2; - }.call(void 0); - module14.exports = Batcher; - } -}); -var require_Bottleneck = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/Bottleneck.js"(exports2, module14) { - "use strict"; - function _slicedToArray2(arr, i2) { - return _arrayWithHoles2(arr) || _iterableToArrayLimit2(arr, i2) || _nonIterableRest2(); + esm_default("chelonia/private/enqueuePostSyncOps", contractID); + } catch (e2) { + console.error(`[chelonia] syncContract error: ${e2.message || e2}`, e2); + this.config.hooks.syncContractError?.(e2, contractID); + throw e2; + } finally { + if (state[contractID]?._volatile?.resyncing) { + this.config.reactiveDel(state[contractID]._volatile, "resyncing"); + } + delete this.currentSyncs[contractID]; + esm_default("okTurtles.events/emit", CONTRACT_IS_SYNCING, contractID, false); } - function _iterableToArrayLimit2(arr, i2) { - var _arr = []; - var _n = true; - var _d = false; - var _e = void 0; - try { - for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { - _arr.push(_s.value); - if (i2 && _arr.length === i2) break; + }, + "chelonia/private/enqueuePostSyncOps": function(contractID) { + if (!has(this.postSyncOperations, contractID)) + return; + Object.entries(this.postSyncOperations[contractID]).forEach(([key, op]) => { + delete this.postSyncOperations[contractID][key]; + esm_default("chelonia/private/queueEvent", contractID, op).catch((e2) => { + console.error(`Post-sync operation for ${contractID} failed`, { contractID, op, error: e2 }); + }); + }); + }, + "chelonia/private/watchForeignKeys": function(externalContractID) { + const state = esm_default(this.config.stateSelector); + const externalContractState = state[externalContractID]; + const pendingWatch = externalContractState?._vm?.pendingWatch; + if (!pendingWatch || !Object.keys(pendingWatch).length) + return; + const signingKey = findSuitableSecretKeyId(externalContractState, [SPMessage.OP_KEY_DEL], ["sig"]); + const canMirrorOperations = !!signingKey; + if (!canMirrorOperations) { + console.info("[chelonia/private/watchForeignKeys]: Returning as operations cannot be mirrored", { externalContractID }); + return; + } + Object.entries(pendingWatch).forEach(([contractID, keys]) => { + if (!Array.isArray(keys) || // Check that the keys exist and haven't been revoked + !keys.reduce((acc, [, id]) => { + return acc || has(externalContractState._vm.authorizedKeys, id); + }, false)) { + console.info("[chelonia/private/watchForeignKeys]: Skipping as none of the keys to watch exist", { + externalContractID, + contractID + }); + return; + } + esm_default("chelonia/private/queueEvent", contractID, [ + "chelonia/private/in/syncContractAndWatchKeys", + contractID, + externalContractID + ]).catch((e2) => { + console.error(`Error at syncContractAndWatchKeys for contractID ${contractID} and externalContractID ${externalContractID}`, e2); + }); + }); + }, + "chelonia/private/in/syncContractAndWatchKeys": async function(contractID, externalContractID) { + const rootState = esm_default(this.config.stateSelector); + const externalContractState = rootState[externalContractID]; + const pendingWatch = externalContractState?._vm?.pendingWatch?.[contractID]?.splice(0); + if (!Array.isArray(pendingWatch) || // Check that the keys exist and haven't been revoked + !pendingWatch.reduce((acc, [, id]) => { + return acc || has(externalContractState._vm.authorizedKeys, id) && findKeyIdByName(externalContractState, externalContractState._vm.authorizedKeys[id].name) != null; + }, false)) { + console.info("[chelonia/private/syncContractAndWatchKeys]: Skipping as none of the keys to watch exist", { + externalContractID, + contractID + }); + return; + } + if (!this.subscriptionSet.has(contractID)) { + await esm_default("chelonia/private/in/syncContract", contractID); + } + const contractState = rootState[contractID]; + const keysToDelete = []; + const keysToUpdate = []; + pendingWatch.forEach(([keyName, externalId]) => { + const keyId2 = findKeyIdByName(contractState, keyName); + if (!keyId2) { + keysToDelete.push(externalId); + return; + } else if (keyId2 !== externalId) { + keysToUpdate.push(externalId); + } + if (!contractState._volatile) { + this.config.reactiveSet(contractState, "_volatile", Object.create(null, { + watch: { + value: [[keyName, externalContractID]], + configurable: true, + enumerable: true, + writable: true + } + })); + } else { + if (!contractState._volatile.watch) { + this.config.reactiveSet(contractState._volatile, "watch", [ + [keyName, externalContractID] + ]); } - } catch (err) { - _d = true; - _e = err; - } finally { - try { - if (!_n && _i["return"] != null) _i["return"](); - } finally { - if (_d) throw _e; + if (Array.isArray(contractState._volatile.watch) && !contractState._volatile.watch.find((v2) => v2[0] === keyName && v2[1] === externalContractID)) { + contractState._volatile.watch.push([keyName, externalContractID]); } } - return _arr; + }); + if (keysToDelete.length || keysToUpdate.length) { + if (!externalContractState._volatile) { + this.config.reactiveSet(externalContractState, "_volatile", /* @__PURE__ */ Object.create(null)); + } + if (!externalContractState._volatile.pendingKeyRevocations) { + this.config.reactiveSet(externalContractState._volatile, "pendingKeyRevocations", /* @__PURE__ */ Object.create(null)); + } + keysToDelete.forEach((id) => this.config.reactiveSet(externalContractState._volatile.pendingKeyRevocations, id, "del")); + keysToUpdate.forEach((id) => this.config.reactiveSet(externalContractState._volatile.pendingKeyRevocations, id, true)); + esm_default("chelonia/private/queueEvent", externalContractID, [ + "chelonia/private/deleteOrRotateRevokedKeys", + externalContractID + ]).catch((e2) => { + console.error(`Error at deleteOrRotateRevokedKeys for contractID ${contractID} and externalContractID ${externalContractID}`, e2); + }); } - function _toArray(arr) { - return _arrayWithHoles2(arr) || _iterableToArray(arr) || _nonIterableRest2(); + }, + // The following function gets called when we start watching a contract for + // foreign keys for the first time, and it ensures that, at the point the + // watching starts, keys are in sync between the two contracts (later on, + // this will be handled automatically for incoming OP_KEY_DEL and + // OP_KEY_UPDATE). + // For any given foreign key, there are three possible states: + // 1. The key is in sync with the foreign contract. In this case, there's + // nothing left to do. + // 2. The key has been rotated in the foreign contract (replaced by another + // key of the same name). We need to mirror this operation manually + // since watching only affects new messages we receive. + // 3. The key has been removed in the foreign contract. We also need to + // mirror the operation. + "chelonia/private/deleteOrRotateRevokedKeys": function(contractID) { + const rootState = esm_default(this.config.stateSelector); + const contractState = rootState[contractID]; + const pendingKeyRevocations = contractState?._volatile?.pendingKeyRevocations; + if (!pendingKeyRevocations || Object.keys(pendingKeyRevocations).length === 0) + return; + const keysToUpdate = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === true).map(([id]) => id); + const [, keyUpdateSigningKeyId, keyUpdateArgs] = keysToUpdate.reduce((acc, keyId2) => { + const key = contractState._vm?.authorizedKeys?.[keyId2]; + if (!key || !key.foreignKey) + return acc; + const foreignKey = String(key.foreignKey); + const fkUrl = new URL(foreignKey); + const foreignContractID = fkUrl.pathname; + const foreignKeyName = fkUrl.searchParams.get("keyName"); + if (!foreignKeyName) + throw new Error("Missing foreign key name"); + const foreignState = rootState[foreignContractID]; + if (!foreignState) + return acc; + const fKeyId = findKeyIdByName(foreignState, foreignKeyName); + if (!fKeyId) { + if (pendingKeyRevocations[keyId2] === true) { + this.config.reactiveSet(pendingKeyRevocations, keyId2, "del"); + } + return acc; + } + const [currentRingLevel, currentSigningKeyId, currentKeyArgs] = acc; + const ringLevel = Math.min(currentRingLevel, key.ringLevel ?? Number.POSITIVE_INFINITY); + if (ringLevel >= currentRingLevel) { + currentKeyArgs.push({ + name: key.name, + oldKeyId: keyId2, + id: fKeyId, + data: foreignState._vm.authorizedKeys[fKeyId].data + }); + return [currentRingLevel, currentSigningKeyId, currentKeyArgs]; + } else if (Number.isFinite(ringLevel)) { + const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_UPDATE], ["sig"], ringLevel); + if (signingKeyId) { + currentKeyArgs.push({ + name: key.name, + oldKeyId: keyId2, + id: fKeyId, + data: foreignState._vm.authorizedKeys[fKeyId].data + }); + return [ringLevel, signingKeyId, currentKeyArgs]; + } + } + return acc; + }, [ + Number.POSITIVE_INFINITY, + "", + [] + ]); + if (keyUpdateArgs.length !== 0) { + const contractName = contractState._vm.type; + esm_default("chelonia/out/keyUpdate", { + contractID, + contractName, + data: keyUpdateArgs, + signingKeyId: keyUpdateSigningKeyId + }).catch((e2) => { + console.error(`[chelonia/private/deleteOrRotateRevokedKeys] Error sending OP_KEY_UPDATE for ${contractID}`, e2.message); + }); } - function _nonIterableRest2() { - throw new TypeError("Invalid attempt to destructure non-iterable instance"); + const keysToDelete = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === "del").map(([id]) => id); + const [, keyDelSigningKeyId, keyIdsToDelete] = keysToDelete.reduce((acc, keyId2) => { + const [currentRingLevel, currentSigningKeyId, currentKeyIds] = acc; + const ringLevel = Math.min(currentRingLevel, contractState._vm?.authorizedKeys?.[keyId2]?.ringLevel ?? Number.POSITIVE_INFINITY); + if (ringLevel >= currentRingLevel) { + currentKeyIds.push(keyId2); + return [currentRingLevel, currentSigningKeyId, currentKeyIds]; + } else if (Number.isFinite(ringLevel)) { + const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_DEL], ["sig"], ringLevel); + if (signingKeyId) { + currentKeyIds.push(keyId2); + return [ringLevel, signingKeyId, currentKeyIds]; + } + } + return acc; + }, [Number.POSITIVE_INFINITY, "", []]); + if (keyIdsToDelete.length !== 0) { + const contractName = contractState._vm.type; + esm_default("chelonia/out/keyDel", { + contractID, + contractName, + data: keyIdsToDelete, + signingKeyId: keyDelSigningKeyId + }).catch((e2) => { + console.error(`[chelonia/private/deleteRevokedKeys] Error sending OP_KEY_DEL for ${contractID}`, e2.message); + }); } - function _iterableToArray(iter) { - if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); + }, + "chelonia/private/respondToAllKeyRequests": function(contractID) { + const state = esm_default(this.config.stateSelector); + const contractState = state[contractID] ?? {}; + const pending = contractState?._vm?.pendingKeyshares; + if (!pending) + return; + const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_ATOMIC, SPMessage.OP_KEY_REQUEST_SEEN, SPMessage.OP_KEY_SHARE], ["sig"]); + if (!signingKeyId) { + console.log("Unable to respond to key request because there is no suitable secret key with OP_KEY_REQUEST_SEEN permission"); + return; } - function _arrayWithHoles2(arr) { - if (Array.isArray(arr)) return arr; + Object.entries(pending).map(([hash3, entry]) => { + if (!Array.isArray(entry) || entry.length !== 4) { + return void 0; + } + const [, , , [originatingContractID]] = entry; + return esm_default("chelonia/private/queueEvent", originatingContractID, [ + "chelonia/private/respondToKeyRequest", + contractID, + signingKeyId, + hash3 + ]).catch((e2) => { + console.error(`respondToAllKeyRequests: Error responding to key request ${hash3} from ${originatingContractID} to ${contractID}`, e2); + }); + }); + }, + "chelonia/private/respondToKeyRequest": async function(contractID, signingKeyId, hash3) { + const state = esm_default(this.config.stateSelector); + const contractState = state[contractID]; + const entry = contractState?._vm?.pendingKeyshares?.[hash3]; + const instance = this._instance; + if (!Array.isArray(entry) || entry.length !== 4) { + return; } - function asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error2) { - reject(error2); + const [keyShareEncryption, height, , [originatingContractID, rv, originatingContractHeight, headJSON]] = entry; + entry.pop(); + const krsEncryption = !!contractState._vm.authorizedKeys?.[signingKeyId]?._private; + await esm_default("chelonia/private/in/syncContract", originatingContractID); + if (instance !== this._instance) + return; + const originatingState = state[originatingContractID]; + const contractName = state.contracts[contractID].type; + const originatingContractName = originatingState._vm.type; + const v2 = signedIncomingData(originatingContractID, originatingState, rv, originatingContractHeight, headJSON).valueOf(); + const { encryptionKeyId } = v2; + const responseKey = encryptedIncomingData(contractID, contractState, v2.responseKey, height, this.transientSecretKeys, headJSON).valueOf(); + const deserializedResponseKey = deserializeKey(responseKey); + const responseKeyId = keyId(deserializedResponseKey); + Promise.resolve().then(() => { + if (instance !== this._instance) return; + if (!has(originatingState._vm.authorizedKeys, responseKeyId) || originatingState._vm.authorizedKeys[responseKeyId]._notAfterHeight != null) { + throw new Error(`Unable to respond to key request for ${originatingContractID}. Key ${responseKeyId} is not valid.`); } - if (info.done) { - resolve82(value); - } else { - Promise.resolve(value).then(_next, _throw); + esm_default("chelonia/storeSecretKeys", new Secret([{ key: deserializedResponseKey }])); + const keys = pick2(state.secretKeys, Object.entries(contractState._vm.authorizedKeys).filter(([, key]) => !!key.meta?.private?.shareable).map(([kId]) => kId)); + if (!keys || Object.keys(keys).length === 0) { + console.info("respondToAllKeyRequests: no keys to share", { + contractID, + originatingContractID + }); + return; } - } - function _asyncToGenerator2(fn) { - return function() { - var self2 = this, args = arguments; - return new Promise(function(resolve82, reject) { - var gen = fn.apply(self2, args); - function _next(value) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "next", value); - } - function _throw(err) { - asyncGeneratorStep2(gen, resolve82, reject, _next, _throw, "throw", err); + const keySharePayload = { + contractID, + keys: Object.entries(keys).map(([keyId2, key]) => ({ + id: keyId2, + meta: { + private: { + content: encryptedOutgoingData(originatingContractID, encryptionKeyId, key), + shareable: true + } } - _next(void 0); - }); + })), + keyRequestHash: hash3, + keyRequestHeight: height }; - } - var Bottleneck2; - var DEFAULT_PRIORITY; - var Events2; - var Job; - var LocalDatastore; - var NUM_PRIORITIES; - var Queues; - var RedisDatastore; - var States; - var Sync; - var parser3; - var splice = [].splice; - NUM_PRIORITIES = 10; - DEFAULT_PRIORITY = 5; - parser3 = require_parser2(); - Queues = require_Queues(); - Job = require_Job(); - LocalDatastore = require_LocalDatastore(); - RedisDatastore = require_RedisDatastore(); - Events2 = require_Events(); - States = require_States(); - Sync = require_Sync(); - Bottleneck2 = function() { - class Bottleneck3 { - constructor(options2 = {}, ...invalid) { - var storeInstanceOptions, storeOptions; - this._addToQueue = this._addToQueue.bind(this); - this._validateOptions(options2, invalid); - parser3.load(options2, this.instanceDefaults, this); - this._queues = new Queues(NUM_PRIORITIES); - this._scheduled = {}; - this._states = new States(["RECEIVED", "QUEUED", "RUNNING", "EXECUTING"].concat(this.trackDoneStatus ? ["DONE"] : [])); - this._limiter = null; - this.Events = new Events2(this); - this._submitLock = new Sync("submit", this.Promise); - this._registerLock = new Sync("register", this.Promise); - storeOptions = parser3.load(options2, this.storeDefaults, {}); - this._store = function() { - if (this.datastore === "redis" || this.datastore === "ioredis" || this.connection != null) { - storeInstanceOptions = parser3.load(options2, this.redisStoreDefaults, {}); - return new RedisDatastore(this, storeOptions, storeInstanceOptions); - } else if (this.datastore === "local") { - storeInstanceOptions = parser3.load(options2, this.localStoreDefaults, {}); - return new LocalDatastore(this, storeOptions, storeInstanceOptions); + if (!contractState?._vm?.pendingKeyshares?.[hash3]) { + return; + } + return keySharePayload; + }).then((keySharePayload) => { + if (instance !== this._instance || !keySharePayload) + return; + return esm_default("chelonia/out/keyShare", { + contractID: originatingContractID, + contractName: originatingContractName, + data: keyShareEncryption ? encryptedOutgoingData(originatingContractID, findSuitablePublicKeyIds(originatingState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", keySharePayload) : keySharePayload, + signingKeyId: responseKeyId + }).then((msg) => { + if (instance !== this._instance) + return; + const payload = { keyRequestHash: hash3, keyShareHash: msg.hash(), success: true }; + const connectionKeyPayload = { + contractID: originatingContractID, + keys: [ + { + id: responseKeyId, + meta: { + private: { + content: encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", responseKey), + shareable: true + } + } + } + ] + }; + esm_default("chelonia/out/atomic", { + contractID, + contractName, + signingKeyId, + data: [ + [ + "chelonia/out/keyRequestResponse", + { + data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload + } + ], + [ + // Upon successful key share, we want to share deserializedResponseKey + // with ourselves + "chelonia/out/keyShare", + { + data: keyShareEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", connectionKeyPayload) : connectionKeyPayload + } + ] + ] + }).catch((e2) => { + console.error("Error at respondToKeyRequest while sending keyRequestResponse", e2); + }); + }); + }).catch((e2) => { + console.error("Error at respondToKeyRequest", e2); + const payload = { keyRequestHash: hash3, success: false }; + if (!contractState?._vm?.pendingKeyshares?.[hash3]) { + return; + } + esm_default("chelonia/out/keyRequestResponse", { + contractID, + contractName, + signingKeyId, + data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload + }).catch((e3) => { + console.error("Error at respondToKeyRequest while sending keyRequestResponse in error handler", e3); + }); + }); + }, + "chelonia/private/in/handleEvent": async function(contractID, rawMessage) { + const state = esm_default(this.config.stateSelector); + const { preHandleEvent, postHandleEvent, handleEventError } = this.config.hooks; + let processingErrored = false; + let message; + try { + if (!this.config.acceptAllMessages && !this.pending.some((entry) => entry?.contractID === contractID) && !this.subscriptionSet.has(contractID)) { + console.warn(`[chelonia] WARN: ignoring unexpected event for ${contractID}:`, rawMessage); + return; + } + const contractStateCopy = state[contractID] ? cloneDeep(state[contractID]) : /* @__PURE__ */ Object.create(null); + message = SPMessage.deserialize(rawMessage, this.transientSecretKeys, contractStateCopy, this.config.unwrapMaybeEncryptedData); + if (message.contractID() !== contractID) { + throw new Error(`[chelonia] Wrong contract ID. Expected ${contractID} but got ${message.contractID()}`); + } + if (!message.isFirstMessage() && (!has(state.contracts, contractID) || !has(state, contractID))) { + throw new ChelErrorUnrecoverable("The event is not for a first message but the contract state is missing"); + } + preHandleEvent?.(message); + const proceed = handleEvent.checkMessageOrdering.call(this, message); + if (proceed === false) + return; + if (state[contractID]?._volatile?.dirty) { + console.info(`[chelonia] Ignoring message ${message.description()} as the contract is marked as dirty`); + return; + } + const internalSideEffectStack = !this.config.skipSideEffects ? [] : void 0; + missingDecryptionKeyIdsMap.delete(message); + try { + await handleEvent.processMutation.call(this, message, contractStateCopy, internalSideEffectStack); + } catch (e_) { + const e2 = e_; + if (e2?.name === "ChelErrorDecryptionKeyNotFound") { + console.warn(`[chelonia] WARN '${e2.name}' in processMutation for ${message.description()}: ${e2.message}`, e2, message.serialize()); + if (e2.cause) { + const missingDecryptionKeyIds = missingDecryptionKeyIdsMap.get(message); + if (missingDecryptionKeyIds) { + missingDecryptionKeyIds.add(e2.cause); } else { - throw new Bottleneck3.prototype.BottleneckError(`Invalid datastore type: ${this.datastore}`); + missingDecryptionKeyIdsMap.set(message, /* @__PURE__ */ new Set([e2.cause])); } - }.call(this); - this._queues.on("leftzero", () => { - var ref; - return (ref = this._store.heartbeat) != null ? typeof ref.ref === "function" ? ref.ref() : void 0 : void 0; - }); - this._queues.on("zero", () => { - var ref; - return (ref = this._store.heartbeat) != null ? typeof ref.unref === "function" ? ref.unref() : void 0 : void 0; - }); - } - _validateOptions(options2, invalid) { - if (!(options2 != null && typeof options2 === "object" && invalid.length === 0)) { - throw new Bottleneck3.prototype.BottleneckError("Bottleneck v2 takes a single object argument. Refer to https://github.com/SGrondin/bottleneck#upgrading-to-v2 if you're upgrading from Bottleneck v1."); } + } else { + console.error(`[chelonia] ERROR '${e2.name}' in processMutation for ${message.description()}: ${e2.message || e2}`, e2, message.serialize()); } - ready() { - return this._store.ready; - } - clients() { - return this._store.clients; - } - channel() { - return `b_${this.id}`; - } - channel_client() { - return `b_${this.id}_${this._store.clientId}`; + console.warn(`[chelonia] Error processing ${message.description()}: ${message.serialize()}. Any side effects will be skipped!`); + if (this.config.strictProcessing) { + throw e2; } - publish(message) { - return this._store.__publish__(message); + processingErrored = e2?.name !== "ChelErrorWarning"; + this.config.hooks.processError?.(e2, message, getMsgMeta.call(this, message, contractID, contractStateCopy)); + if (e2.name === "ChelErrorUnrecoverable" || e2.name === "ChelErrorForkedChain" || message.isFirstMessage()) { + throw e2; } - disconnect(flush = true) { - return this._store.__disconnect__(flush); + } + if (!processingErrored) { + if (Array.isArray(internalSideEffectStack) && internalSideEffectStack.length > 0) { + await Promise.all(internalSideEffectStack.map((fn) => Promise.resolve(fn({ state: contractStateCopy, message })).catch((e_) => { + const e2 = e_; + console.error(`[chelonia] ERROR '${e2.name}' in internal side effect for ${message.description()}: ${e2.message}`, e2, { message: message.serialize() }); + }))); } - chain(_limiter) { - this._limiter = _limiter; - return this; + if (!this.config.skipActionProcessing && !this.config.skipSideEffects) { + await handleEvent.processSideEffects.call(this, message, contractStateCopy)?.catch((e_) => { + const e2 = e_; + console.error(`[chelonia] ERROR '${e2.name}' in sideEffect for ${message.description()}: ${e2.message}`, e2, { message: message.serialize() }); + this.config.hooks.sideEffectError?.(e2, message); + }); } - queued(priority) { - return this._queues.queued(priority); - } - clusterQueued() { - return this._store.__queued__(); + } + try { + const state2 = esm_default(this.config.stateSelector); + await handleEvent.applyProcessResult.call(this, { + message, + state: state2, + contractState: contractStateCopy, + processingErrored, + postHandleEvent + }); + } catch (e_) { + const e2 = e_; + console.error(`[chelonia] ERROR '${e2.name}' for ${message.description()} marking the event as processed: ${e2.message}`, e2, { message: message.serialize() }); + } + } catch (e_) { + const e2 = e_; + console.error(`[chelonia] ERROR in handleEvent: ${e2.message || e2}`, e2); + try { + handleEventError?.(e2, message); + } catch (e22) { + console.error("[chelonia] Ignoring user error in handleEventError hook:", e22); + } + throw e2; + } finally { + if (message) { + missingDecryptionKeyIdsMap.delete(message); + } + } + } +}); +var eventsToReingest = []; +var reprocessDebounced = debounce((contractID) => esm_default("chelonia/private/out/sync", contractID, { force: true }).catch((e2) => { + console.error(`[chelonia] Error at reprocessDebounced for ${contractID}`, e2); +}), 1e3); +var handleEvent = { + checkMessageOrdering(message) { + const contractID = message.contractID(); + const hash3 = message.hash(); + const height = message.height(); + const state = esm_default(this.config.stateSelector); + const latestProcessedHeight = state.contracts[contractID]?.height; + if (!Number.isSafeInteger(height)) { + throw new ChelErrorDBBadPreviousHEAD(`Message ${hash3} in contract ${contractID} has an invalid height.`); + } + if (message.isFirstMessage() ? latestProcessedHeight != null : !(latestProcessedHeight < height)) { + if (!this.config.strictOrdering) { + return false; + } + throw new ChelErrorAlreadyProcessed(`Message ${hash3} with height ${height} in contract ${contractID} has already been processed. Current height: ${latestProcessedHeight}.`); + } + if (latestProcessedHeight + 1 < height) { + if (this.config.strictOrdering) { + throw new ChelErrorDBBadPreviousHEAD(`Unexpected message ${hash3} with height ${height} in contract ${contractID}: height is too high. Current height: ${latestProcessedHeight}.`); + } + if (eventsToReingest.length > 100) { + throw new ChelErrorUnrecoverable("more than 100 different bad previousHEAD errors"); + } + if (!eventsToReingest.includes(hash3)) { + console.warn(`[chelonia] WARN bad previousHEAD for ${message.description()}, will attempt to re-sync contract to reingest message`); + eventsToReingest.push(hash3); + reprocessDebounced(contractID); + return false; + } else { + console.error(`[chelonia] ERROR already attempted to reingest ${message.description()}, will not attempt again!`); + throw new ChelErrorDBBadPreviousHEAD(`Already attempted to reingest ${hash3}`); + } + } + const reprocessIdx = eventsToReingest.indexOf(hash3); + if (reprocessIdx !== -1) { + console.warn(`[chelonia] WARN: successfully reingested ${message.description()}`); + eventsToReingest.splice(reprocessIdx, 1); + } + }, + async processMutation(message, state, internalSideEffectStack) { + const contractID = message.contractID(); + if (message.isFirstMessage()) { + if (Object.keys(state).some((k) => k !== "_volatile")) { + throw new ChelErrorUnrecoverable(`state for ${contractID} is already set`); + } + } + await esm_default("chelonia/private/in/processMessage", message, state, internalSideEffectStack); + }, + processSideEffects(message, state) { + const opT = message.opType(); + if (![ + SPMessage.OP_ATOMIC, + SPMessage.OP_ACTION_ENCRYPTED, + SPMessage.OP_ACTION_UNENCRYPTED + ].includes(opT)) { + return; + } + const contractID = message.contractID(); + const manifestHash = message.manifest(); + const hash3 = message.hash(); + const height = message.height(); + const signingKeyId = message.signingKeyId(); + const callSideEffect = async (field) => { + const wv = this.config.unwrapMaybeEncryptedData(field); + if (!wv) + return; + let v2 = wv.data; + let innerSigningKeyId; + if (isSignedData(v2)) { + innerSigningKeyId = v2.signingKeyId; + v2 = v2.valueOf(); + } + const { action, data, meta } = v2; + const mutation = { + data, + meta, + hash: hash3, + height, + contractID, + description: message.description(), + direction: message.direction(), + signingKeyId, + get signingContractID() { + return getContractIDfromKeyId(contractID, signingKeyId, state); + }, + innerSigningKeyId, + get innerSigningContractID() { + return getContractIDfromKeyId(contractID, innerSigningKeyId, state); } - empty() { - return this.queued() === 0 && this._submitLock.isEmpty(); + }; + return await esm_default(`${manifestHash}/${action}/sideEffect`, mutation, state); + }; + const msg = Object(message.message()); + if (opT !== SPMessage.OP_ATOMIC) { + return callSideEffect(msg); + } + const reducer = (acc, [opT2, opV]) => { + if ([SPMessage.OP_ACTION_ENCRYPTED, SPMessage.OP_ACTION_UNENCRYPTED].includes(opT2)) { + acc.push(Object(opV)); + } + return acc; + }; + const actionsOpV = msg.reduce(reducer, []); + return Promise.allSettled(actionsOpV.map((action) => callSideEffect(action))).then((results) => { + const errors2 = results.filter((r) => r.status === "rejected").map((r) => r.reason); + if (errors2.length > 0) { + console.error("Side-effect errors", contractID, errors2); + throw new AggregateError(errors2, `Error at side effects for ${contractID}`); + } + }); + }, + async applyProcessResult({ message, state, contractState, processingErrored, postHandleEvent }) { + const contractID = message.contractID(); + const hash3 = message.hash(); + const height = message.height(); + await esm_default("chelonia/db/addEntry", message); + if (!processingErrored) { + this.config.reactiveSet(state, contractID, contractState); + try { + postHandleEvent?.(message); + } catch (e2) { + console.error(`[chelonia] ERROR '${e2.name}' for ${message.description()} in event post-handling: ${e2.message}`, e2, { message: message.serialize() }); + } + } + if (message.isFirstMessage()) { + const { type } = message.opValue(); + if (!has(state.contracts, contractID)) { + this.config.reactiveSet(state.contracts, contractID, /* @__PURE__ */ Object.create(null)); + } + this.config.reactiveSet(state.contracts[contractID], "type", type); + console.debug(`contract ${type} registered for ${contractID}`); + } + if (message.isKeyOp()) { + this.config.reactiveSet(state.contracts[contractID], "previousKeyOp", hash3); + } + this.config.reactiveSet(state.contracts[contractID], "HEAD", hash3); + this.config.reactiveSet(state.contracts[contractID], "height", height); + const missingDecryptionKeyIdsForMessage = missingDecryptionKeyIdsMap.get(message); + if (missingDecryptionKeyIdsForMessage) { + let missingDecryptionKeyIds = state.contracts[contractID].missingDecryptionKeyIds; + if (!missingDecryptionKeyIds) { + missingDecryptionKeyIds = []; + this.config.reactiveSet(state.contracts[contractID], "missingDecryptionKeyIds", missingDecryptionKeyIds); + } + missingDecryptionKeyIdsForMessage.forEach((keyId2) => { + if (missingDecryptionKeyIds.includes(keyId2)) + return; + missingDecryptionKeyIds.push(keyId2); + }); + } + if (!this.subscriptionSet.has(contractID)) { + const entry = this.pending.find((entry2) => entry2?.contractID === contractID); + if (entry) { + const index = this.pending.indexOf(entry); + if (index !== -1) { + this.pending.splice(index, 1); } - running() { - return this._store.__running__(); + } + this.subscriptionSet.add(contractID); + esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { + added: [contractID], + removed: [] + }); + } + if (!processingErrored) { + esm_default("okTurtles.events/emit", hash3, contractID, message); + esm_default("okTurtles.events/emit", EVENT_HANDLED, contractID, message); + } + } +}; +var notImplemented = (v2) => { + throw new Error(`chelonia: action not implemented to handle: ${JSON.stringify(v2)}.`); +}; +init_signedData(); +init_esm(); +var wallBase = Date.now(); +var monotonicBase = performance.now(); +var resyncTimeout; +var watchdog; +var syncServerTime = async function() { + const startTime = performance.now(); + const time3 = await this.config.fetch(`${this.config.connectionURL}/time`, { + signal: this.abortController.signal + }); + const requestTimeElapsed = performance.now(); + if (requestTimeElapsed - startTime > 8e3) { + throw new Error("Error fetching server time: request took too long"); + } + if (!time3.ok) + throw new Error("Error fetching server time"); + const serverTime = new Date(await time3.text()).valueOf(); + if (Number.isNaN(serverTime)) + throw new Error("Unable to parse server time"); + const newMonotonicBase = performance.now(); + wallBase = serverTime + (requestTimeElapsed - startTime) / 2 + // Also take into account the time elapsed between `requestTimeElapsed` + // and this line (which should be very little) + (newMonotonicBase - requestTimeElapsed); + monotonicBase = newMonotonicBase; +}; +var time_sync_default = esm_default("sbp/selectors/register", { + "chelonia/private/startClockSync": function() { + if (resyncTimeout !== void 0) { + throw new Error("chelonia/private/startClockSync has already been called"); + } + const resync = (delay2 = 3e5) => { + if (resyncTimeout !== null) + return; + const timeout = setTimeout(() => { + syncServerTime.call(this).then(() => { + if (resyncTimeout === timeout) + resyncTimeout = null; + resync(); + }).catch((e2) => { + if (resyncTimeout === timeout) { + resyncTimeout = null; + console.error("Error re-syncing server time; will re-attempt in 5s", e2); + setTimeout(() => resync(0), 5e3); + } else { + console.error("Error re-syncing server time; another attempt is in progress", e2); + } + }); + }, delay2); + resyncTimeout = timeout; + }; + let wallLast = Date.now(); + let monotonicLast = performance.now(); + watchdog = setInterval(() => { + const wallNow = Date.now(); + const monotonicNow = performance.now(); + const difference2 = Math.abs(Math.abs(wallNow - wallLast) - Math.abs(monotonicNow - monotonicLast)); + if (difference2 > 10) { + if (resyncTimeout != null) + clearTimeout(resyncTimeout); + resyncTimeout = null; + resync(0); + } + wallLast = wallNow; + monotonicLast = monotonicNow; + }, 1e4); + resyncTimeout = null; + resync(0); + }, + "chelonia/private/stopClockSync": () => { + if (resyncTimeout !== void 0) { + if (watchdog != null) + clearInterval(watchdog); + if (resyncTimeout != null) + clearTimeout(resyncTimeout); + watchdog = void 0; + resyncTimeout = void 0; + } + }, + // Get an estimate of the server's current time based on the time elapsed as + // measured locally (using a monotonic clock), which is used as an offset, and + // a previously retrieved server time. The time value is returned as a UNIX + // _millisecond_ timestamp (milliseconds since 1 Jan 1970 00:00:00 UTC) + "chelonia/time": function() { + const monotonicNow = performance.now(); + const wallNow = wallBase - monotonicBase + monotonicNow; + return Math.round(wallNow); + } +}); +var ACTION_REGEX = /^((([\w.]+)\/([^/]+))(?:\/(?:([^/]+)\/)?)?)\w*/; +var chelonia_default = esm_default("sbp/selectors/register", { + // https://www.wordnik.com/words/chelonia + // https://gitlab.okturtles.org/okturtles/group-income/-/wikis/E2E-Protocol/Framework.md#alt-names + "chelonia/_init": function() { + this.config = { + // TODO: handle connecting to multiple servers for federation + get connectionURL() { + throw new Error("Invalid use of connectionURL before initialization"); + }, + // override! + set connectionURL(value) { + Object.defineProperty(this, "connectionURL", { value, writable: true }); + }, + stateSelector: "chelonia/private/state", + // override to integrate with, for example, vuex + contracts: { + defaults: { + modules: {}, + // '' => resolved module import + exposedGlobals: {}, + allowedDomains: [], + allowedSelectors: [], + preferSlim: false + }, + overrides: {}, + // override default values per-contract + manifests: {} + // override! contract names => manifest hashes + }, + whitelisted: (action) => !!this.whitelistedActions[action], + reactiveSet: (obj, key, value) => { + obj[key] = value; + return value; + }, + // example: set to Vue.set + fetch: (...args) => fetch(...args), + reactiveDel: (obj, key) => { + delete obj[key]; + }, + // acceptAllMessages disables checking whether we are expecting a message + // or not for processing + acceptAllMessages: false, + skipActionProcessing: false, + skipDecryptionAttempts: false, + skipSideEffects: false, + // Strict processing will treat all processing errors as unrecoverable + // This is useful, e.g., in the server, to prevent invalid messages from + // being added to the database + strictProcessing: false, + // Strict ordering will throw on past events with ChelErrorAlreadyProcessed + // Similarly, future events will not be reingested and will throw + // with ChelErrorDBBadPreviousHEAD + strictOrdering: false, + connectionOptions: { + maxRetries: Infinity, + // See https://github.com/okTurtles/group-income/issues/1183 + reconnectOnTimeout: true + // can be enabled since we are not doing auth via web sockets + }, + hooks: { + preHandleEvent: null, + // async (message: SPMessage) => {} + postHandleEvent: null, + // async (message: SPMessage) => {} + processError: null, + // (e: Error, message: SPMessage) => {} + sideEffectError: null, + // (e: Error, message: SPMessage) => {} + handleEventError: null, + // (e: Error, message: SPMessage) => {} + syncContractError: null, + // (e: Error, contractID: string) => {} + pubsubError: null + // (e:Error, socket: Socket) + }, + unwrapMaybeEncryptedData + }; + this._instance = /* @__PURE__ */ Object.create(null); + this.abortController = new AbortController(); + this.state = { + contracts: {}, + // contractIDs => { type, HEAD } (contracts we've subscribed to) + pending: [] + // prevents processing unexpected data from a malicious server + }; + this.manifestToContract = {}; + this.whitelistedActions = {}; + this.currentSyncs = /* @__PURE__ */ Object.create(null); + this.postSyncOperations = /* @__PURE__ */ Object.create(null); + this.sideEffectStacks = /* @__PURE__ */ Object.create(null); + this.sideEffectStack = (contractID) => { + let stack = this.sideEffectStacks[contractID]; + if (!stack) { + this.sideEffectStacks[contractID] = stack = []; + } + return stack; + }; + this.setPostSyncOp = (contractID, key, op) => { + this.postSyncOperations[contractID] = this.postSyncOperations[contractID] || /* @__PURE__ */ Object.create(null); + this.postSyncOperations[contractID][key] = op; + }; + const secretKeyGetter = (o2, p) => { + if (has(o2, p)) + return o2[p]; + const rootState = esm_default(this.config.stateSelector); + if (rootState?.secretKeys && has(rootState.secretKeys, p)) { + const key = deserializeKey(rootState.secretKeys[p]); + o2[p] = key; + return key; + } + }; + const secretKeyList = (o2) => { + const rootState = esm_default(this.config.stateSelector); + const stateKeys = Object.keys(rootState?.secretKeys || {}); + return Array.from(/* @__PURE__ */ new Set([...Object.keys(o2), ...stateKeys])); + }; + this.transientSecretKeys = new Proxy(/* @__PURE__ */ Object.create(null), { + get: secretKeyGetter, + ownKeys: secretKeyList + }); + this.ephemeralReferenceCount = /* @__PURE__ */ Object.create(null); + this.subscriptionSet = /* @__PURE__ */ new Set(); + this.pending = []; + }, + "chelonia/config": function() { + return { + ...cloneDeep(this.config), + fetch: this.config.fetch, + reactiveSet: this.config.reactiveSet, + reactiveDel: this.config.reactiveDel + }; + }, + "chelonia/configure": async function(config2) { + merge2(this.config, config2); + Object.assign(this.config.hooks, config2.hooks || {}); + if (config2.contracts) { + Object.assign(this.config.contracts.defaults, config2.contracts.defaults || {}); + const manifests = this.config.contracts.manifests; + console.debug("[chelonia] preloading manifests:", Object.keys(manifests)); + for (const contractName in manifests) { + await esm_default("chelonia/private/loadManifest", contractName, manifests[contractName]); + } + } + if (has(config2, "skipDecryptionAttempts")) { + if (config2.skipDecryptionAttempts) { + this.config.unwrapMaybeEncryptedData = (data) => { + if (data == null) + return; + if (!isEncryptedData(data)) { + return { + encryptionKeyId: null, + data + }; + } + }; + } else { + this.config.unwrapMaybeEncryptedData = unwrapMaybeEncryptedData; + } + } + }, + "chelonia/reset": async function(newState, postCleanupFn) { + if (typeof newState === "function" && typeof postCleanupFn === "undefined") { + postCleanupFn = newState; + newState = void 0; + } + if (this.pubsub) { + esm_default("chelonia/private/stopClockSync"); + } + Object.keys(this.postSyncOperations).forEach((cID) => { + esm_default("chelonia/private/enqueuePostSyncOps", cID); + }); + await esm_default("chelonia/contract/waitPublish"); + await esm_default("chelonia/contract/wait"); + Object.keys(this.postSyncOperations).forEach((cID) => { + esm_default("chelonia/private/enqueuePostSyncOps", cID); + }); + await esm_default("chelonia/contract/waitPublish"); + await esm_default("chelonia/contract/wait"); + const result = await postCleanupFn?.(); + const rootState = esm_default(this.config.stateSelector); + this._instance = /* @__PURE__ */ Object.create(null); + this.abortController.abort(); + this.abortController = new AbortController(); + reactiveClearObject(rootState, this.config.reactiveDel); + this.config.reactiveSet(rootState, "contracts", /* @__PURE__ */ Object.create(null)); + clearObject(this.ephemeralReferenceCount); + this.pending.splice(0); + clearObject(this.currentSyncs); + clearObject(this.postSyncOperations); + clearObject(this.sideEffectStacks); + const removedContractIDs = Array.from(this.subscriptionSet); + this.subscriptionSet.clear(); + esm_default("chelonia/clearTransientSecretKeys"); + esm_default("okTurtles.events/emit", CHELONIA_RESET); + esm_default("okTurtles.events/emit", CONTRACTS_MODIFIED, Array.from(this.subscriptionSet), { + added: [], + removed: removedContractIDs + }); + if (this.pubsub) { + esm_default("chelonia/private/startClockSync"); + } + if (newState) { + Object.entries(newState).forEach(([key, value]) => { + this.config.reactiveSet(rootState, key, value); + }); + } + return result; + }, + "chelonia/storeSecretKeys": function(wkeys) { + const rootState = esm_default(this.config.stateSelector); + if (!rootState.secretKeys) { + this.config.reactiveSet(rootState, "secretKeys", /* @__PURE__ */ Object.create(null)); + } + let keys = wkeys.valueOf(); + if (!keys) + return; + if (!Array.isArray(keys)) + keys = [keys]; + keys.forEach(({ key, transient }) => { + if (!key) + return; + if (typeof key === "string") { + key = deserializeKey(key); + } + const id = keyId(key); + if (!has(this.transientSecretKeys, id)) { + this.transientSecretKeys[id] = key; + } + if (transient) + return; + if (!has(rootState.secretKeys, id)) { + this.config.reactiveSet(rootState.secretKeys, id, serializeKey(key, true)); + } + }); + }, + "chelonia/clearTransientSecretKeys": function(ids) { + if (Array.isArray(ids)) { + ids.forEach((id) => { + delete this.transientSecretKeys[id]; + }); + } else { + Object.keys(this.transientSecretKeys).forEach((id) => { + delete this.transientSecretKeys[id]; + }); + } + }, + "chelonia/haveSecretKey": function(keyId2, persistent) { + if (!persistent && has(this.transientSecretKeys, keyId2)) + return true; + const rootState = esm_default(this.config.stateSelector); + return !!rootState?.secretKeys && has(rootState.secretKeys, keyId2); + }, + "chelonia/contract/isResyncing": function(contractIDOrState) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + return !!contractIDOrState?._volatile?.dirty || !!contractIDOrState?._volatile?.resyncing; + }, + "chelonia/contract/hasKeyShareBeenRespondedBy": function(contractIDOrState, requestedToContractID, reference) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const result = Object.values(contractIDOrState?._vm.authorizedKeys || {}).some((r) => { + return r?.meta?.keyRequest?.responded && r.meta.keyRequest.contractID === requestedToContractID && (!reference || r.meta.keyRequest.reference === reference); + }); + return result; + }, + "chelonia/contract/waitingForKeyShareTo": function(contractIDOrState, requestingContractID, reference) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const result = contractIDOrState._volatile?.pendingKeyRequests?.filter((r) => { + return r && (!requestingContractID || r.contractID === requestingContractID) && (!reference || r.reference === reference); + })?.map(({ name }) => name); + if (!result?.length) + return null; + return result; + }, + "chelonia/contract/successfulKeySharesByContractID": function(contractIDOrState, requestingContractID) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const keyShares = Object.values(contractIDOrState._vm.keyshares || {}); + if (!keyShares?.length) + return; + const result = /* @__PURE__ */ Object.create(null); + keyShares.forEach((kS) => { + if (!kS.success) + return; + if (requestingContractID && kS.contractID !== requestingContractID) + return; + if (!result[kS.contractID]) + result[kS.contractID] = []; + result[kS.contractID].push({ height: kS.height, hash: kS.hash }); + }); + Object.keys(result).forEach((cID) => { + result[cID].sort((a, b) => { + return b.height - a.height; + }); + }); + return result; + }, + "chelonia/contract/hasKeysToPerformOperation": function(contractIDOrState, operation) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const op = operation !== "*" ? [operation] : operation; + return !!findSuitableSecretKeyId(contractIDOrState, op, ["sig"]); + }, + // Did sourceContractIDOrState receive an OP_KEY_SHARE to perform the given + // operation on contractIDOrState? + "chelonia/contract/receivedKeysToPerformOperation": function(sourceContractIDOrState, contractIDOrState, operation) { + const rootState = esm_default(this.config.stateSelector); + if (typeof sourceContractIDOrState === "string") { + sourceContractIDOrState = rootState[sourceContractIDOrState]; + } + if (typeof contractIDOrState === "string") { + contractIDOrState = rootState[contractIDOrState]; + } + const op = operation !== "*" ? [operation] : operation; + const keyId2 = findSuitableSecretKeyId(contractIDOrState, op, ["sig"]); + return sourceContractIDOrState?._vm?.sharedKeyIds?.some((sK) => sK.id === keyId2); + }, + "chelonia/contract/currentKeyIdByName": function(contractIDOrState, name, requireSecretKey) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const currentKeyId = findKeyIdByName(contractIDOrState, name); + if (requireSecretKey && !esm_default("chelonia/haveSecretKey", currentKeyId)) { + return; + } + return currentKeyId; + }, + "chelonia/contract/foreignKeysByContractID": function(contractIDOrState, foreignContractID) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + return findForeignKeysByContractID(contractIDOrState, foreignContractID); + }, + "chelonia/contract/historicalKeyIdsByName": function(contractIDOrState, name) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const currentKeyId = findKeyIdByName(contractIDOrState, name); + const revokedKeyIds = findRevokedKeyIdsByName(contractIDOrState, name); + return currentKeyId ? [currentKeyId, ...revokedKeyIds] : revokedKeyIds; + }, + "chelonia/contract/suitableSigningKey": function(contractIDOrState, permissions, purposes, ringLevel, allowedActions) { + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractIDOrState = rootState[contractIDOrState]; + } + const keyId2 = findSuitableSecretKeyId(contractIDOrState, permissions, purposes, ringLevel, allowedActions); + return keyId2; + }, + "chelonia/contract/setPendingKeyRevocation": function(contractID, names) { + const rootState = esm_default(this.config.stateSelector); + const state = rootState[contractID]; + if (!state._volatile) + this.config.reactiveSet(state, "_volatile", /* @__PURE__ */ Object.create(null)); + if (!state._volatile.pendingKeyRevocations) { + this.config.reactiveSet(state._volatile, "pendingKeyRevocations", /* @__PURE__ */ Object.create(null)); + } + for (const name of names) { + const keyId2 = findKeyIdByName(state, name); + if (keyId2) { + this.config.reactiveSet(state._volatile.pendingKeyRevocations, keyId2, true); + } else { + console.warn("[setPendingKeyRevocation] Unable to find keyId for name", { + contractID, + name + }); + } + } + }, + "chelonia/shelterAuthorizationHeader"(contractID) { + return buildShelterAuthorizationHeader.call(this, contractID); + }, + // The purpose of the 'chelonia/crypto/*' selectors is so that they can be called + // from contracts without including the crypto code (i.e., importing crypto.js) + // This function takes a function as a parameter that returns a string + // It does not a string directly to prevent accidentally logging the value, + // which is a secret + "chelonia/crypto/keyId": (inKey) => { + return keyId(inKey.valueOf()); + }, + // TODO: allow connecting to multiple servers at once + "chelonia/connect": function(options2 = {}) { + if (!this.config.connectionURL) + throw new Error("config.connectionURL missing"); + if (!this.config.connectionOptions) + throw new Error("config.connectionOptions missing"); + if (this.pubsub) { + this.pubsub.destroy(); + } + let pubsubURL = this.config.connectionURL; + if (true) { + pubsubURL += `?debugID=${randomHexString(6)}`; + } + if (this.pubsub) { + esm_default("chelonia/private/stopClockSync"); + } + esm_default("chelonia/private/startClockSync"); + this.pubsub = createClient(pubsubURL, { + ...this.config.connectionOptions, + handlers: { + ...options2.handlers, + // Every time we get a REQUEST_TYPE.SUB response, which happens for + // 'new' subscriptions as well as every time the connection is reset + "subscription-succeeded": function(event) { + const { channelID } = event.detail; + if (this.subscriptionSet.has(channelID)) { + esm_default("chelonia/private/out/sync", channelID, { force: true }).catch((err) => { + console.warn(`[chelonia] Syncing contract ${channelID} failed: ${err.message}`); + }); + } + options2.handlers?.["subscription-succeeded"]?.call(this, event); } - done() { - return this._store.__done__(); + }, + // Map message handlers to transparently handle encryption and signatures + messageHandlers: { + ...Object.fromEntries(Object.entries(options2.messageHandlers || {}).map(([k, v2]) => { + switch (k) { + case NOTIFICATION_TYPE.PUB: + return [ + k, + (msg) => { + if (!msg.channelID) { + console.info("[chelonia] Discarding pub event without channelID"); + return; + } + if (!this.subscriptionSet.has(msg.channelID)) { + console.info(`[chelonia] Discarding pub event for ${msg.channelID} because it's not in the current subscriptionSet`); + return; + } + esm_default("chelonia/queueInvocation", msg.channelID, () => { + v2.call(this.pubsub, parseEncryptedOrUnencryptedMessage(this, { + contractID: msg.channelID, + serializedData: msg.data + })); + }).catch((e2) => { + console.error(`[chelonia] Error processing pub event for ${msg.channelID}`, e2); + }); + } + ]; + case NOTIFICATION_TYPE.KV: + return [ + k, + (msg) => { + if (!msg.channelID || !msg.key) { + console.info("[chelonia] Discarding kv event without channelID or key"); + return; + } + if (!this.subscriptionSet.has(msg.channelID)) { + console.info(`[chelonia] Discarding kv event for ${msg.channelID} because it's not in the current subscriptionSet`); + return; + } + esm_default("chelonia/queueInvocation", msg.channelID, () => { + v2.call(this.pubsub, [ + msg.key, + parseEncryptedOrUnencryptedMessage(this, { + contractID: msg.channelID, + meta: msg.key, + serializedData: JSON.parse(Buffer6.from(msg.data).toString()) + }) + ]); + }).catch((e2) => { + console.error(`[chelonia] Error processing kv event for ${msg.channelID} and key ${msg.key}`, msg, e2); + }); + } + ]; + case NOTIFICATION_TYPE.DELETION: + return [ + k, + (msg) => v2.call(this.pubsub, msg.data) + ]; + default: + return [k, v2]; + } + })), + [NOTIFICATION_TYPE.ENTRY](msg) { + const { contractID } = SPMessage.deserializeHEAD(msg.data); + esm_default("chelonia/private/in/enqueueHandleEvent", contractID, msg.data); } - jobStatus(id) { - return this._states.jobStatus(id); + } + }); + if (!this.contractsModifiedListener) { + this.contractsModifiedListener = () => esm_default("chelonia/pubsub/update"); + esm_default("okTurtles.events/on", CONTRACTS_MODIFIED, this.contractsModifiedListener); + } + return this.pubsub; + }, + // This selector is defined primarily for ingesting web push notifications, + // although it can be used as a general-purpose API to process events received + // from other external sources that are not managed by Chelonia itself (i.e. sources + // other than the Chelonia-managed websocket connection and RESTful API). + "chelonia/handleEvent": async function(event) { + const { contractID } = SPMessage.deserializeHEAD(event); + return await esm_default("chelonia/private/in/enqueueHandleEvent", contractID, event); + }, + "chelonia/defineContract": function(contract) { + if (!ACTION_REGEX.exec(contract.name)) + throw new Error(`bad contract name: ${contract.name}`); + if (!contract.metadata) + contract.metadata = { validate() { + }, create: () => ({}) }; + if (!contract.getters) + contract.getters = {}; + contract.state = (contractID) => esm_default(this.config.stateSelector)[contractID]; + contract.manifest = this.defContractManifest; + contract.sbp = this.defContractSBP; + this.defContractSelectors = []; + this.defContract = contract; + this.defContractSelectors.push(...esm_default("sbp/selectors/register", { + // expose getters for Vuex integration and other conveniences + [`${contract.manifest}/${contract.name}/getters`]: () => contract.getters, + // 2 ways to cause sideEffects to happen: by defining a sideEffect function in the + // contract, or by calling /pushSideEffect w/async SBP call. Can also do both. + [`${contract.manifest}/${contract.name}/pushSideEffect`]: (contractID, asyncSbpCall) => { + const [sel] = asyncSbpCall; + if (sel.startsWith(contract.name + "/")) { + asyncSbpCall[0] = `${contract.manifest}/${sel}`; + } + this.sideEffectStack(contractID).push(asyncSbpCall); + } + })); + for (const action in contract.actions) { + contractNameFromAction(action); + this.whitelistedActions[action] = true; + this.defContractSelectors.push(...esm_default("sbp/selectors/register", { + [`${contract.manifest}/${action}/process`]: async (message, state) => { + const { meta, data, contractID } = message; + state = state || contract.state(contractID); + const gProxy = gettersProxy(state, contract.getters); + await contract.metadata.validate(meta, { state, ...gProxy, contractID }); + await contract.actions[action].validate(data, { + state, + ...gProxy, + meta, + message, + contractID + }); + this.sideEffectStacks[contractID] = []; + await contract.actions[action].process(message, { state, ...gProxy }); + }, + // 'mutation' is an object that's similar to 'message', but not identical + [`${contract.manifest}/${action}/sideEffect`]: async (mutation, state) => { + if (contract.actions[action].sideEffect) { + state = state || contract.state(mutation.contractID); + if (!state) { + console.warn(`[${contract.manifest}/${action}/sideEffect]: Skipping side-effect since there is no contract state for contract ${mutation.contractID}`); + return; + } + const stateCopy = cloneDeep(state); + const gProxy = gettersProxy(stateCopy, contract.getters); + await contract.actions[action].sideEffect(mutation, { state: stateCopy, ...gProxy }); + } + const sideEffects = this.sideEffectStack(mutation.contractID); + while (sideEffects.length > 0) { + const sideEffect = sideEffects.shift(); + try { + await contract.sbp(...sideEffect); + } catch (e_) { + const e2 = e_; + console.error(`[chelonia] ERROR: '${e2.name}' ${e2.message}, for pushed sideEffect of ${mutation.description}:`, sideEffect); + this.sideEffectStacks[mutation.contractID] = []; + throw e2; + } + } } - jobs(status) { - return this._states.statusJobs(status); + })); + } + for (const method in contract.methods) { + this.defContractSelectors.push(...esm_default("sbp/selectors/register", { + [`${contract.manifest}/${method}`]: contract.methods[method] + })); + } + esm_default("okTurtles.events/emit", CONTRACT_REGISTERED, contract); + }, + "chelonia/queueInvocation": (contractID, sbpInvocation) => { + return esm_default("chelonia/private/queueEvent", contractID, ["chelonia/private/noop"]).then(() => esm_default("chelonia/private/queueEvent", "public:" + contractID, sbpInvocation)); + }, + "chelonia/begin": async (...invocations) => { + for (const invocation of invocations) { + await esm_default(...invocation); + } + }, + // call this manually to resubscribe/unsubscribe from contracts as needed + // if you are using a custom stateSelector and reload the state (e.g. upon login) + "chelonia/pubsub/update": function() { + const client = this.pubsub; + const subscribedIDs = [...client.subscriptionSet]; + const currentIDs = Array.from(this.subscriptionSet); + const leaveSubscribed = intersection2(subscribedIDs, currentIDs); + const toUnsubscribe = difference(subscribedIDs, leaveSubscribed); + const toSubscribe = difference(currentIDs, leaveSubscribed); + try { + for (const contractID of toUnsubscribe) { + client.unsub(contractID); + } + for (const contractID of toSubscribe) { + client.sub(contractID); + } + } catch (e2) { + console.error(`[chelonia] pubsub/update: error ${e2.name}: ${e2.message}`, { toUnsubscribe, toSubscribe }, e2); + this.config.hooks.pubsubError?.(e2, client); + } + }, + // resolves when all pending actions for these contractID(s) finish + "chelonia/contract/wait": function(contractIDs) { + const listOfIds = contractIDs ? typeof contractIDs === "string" ? [contractIDs] : contractIDs : Object.keys(esm_default(this.config.stateSelector).contracts); + return Promise.all(listOfIds.flatMap((cID) => { + return esm_default("chelonia/queueInvocation", cID, ["chelonia/private/noop"]); + })); + }, + // resolves when all pending *writes* for these contractID(s) finish + "chelonia/contract/waitPublish": function(contractIDs) { + const listOfIds = contractIDs ? typeof contractIDs === "string" ? [contractIDs] : contractIDs : Object.keys(esm_default(this.config.stateSelector).contracts); + return Promise.all(listOfIds.flatMap((cID) => { + return esm_default("chelonia/private/queueEvent", `publish:${cID}`, ["chelonia/private/noop"]); + })); + }, + // 'chelonia/contract' - selectors related to injecting remote data and monitoring contracts + // TODO: add an optional parameter to "retain" the contract (see #828) + // eslint-disable-next-line require-await + "chelonia/contract/sync": async function(contractIDs, params) { + const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; + listOfIds.forEach((id) => { + if (checkCanBeGarbageCollected.call(this, id)) { + if (process.env.CI) { + Promise.reject(new Error("[chelonia] Missing reference count for contract " + id)); } - counts() { - return this._states.statusCounts(); + console.error("[chelonia] Missing reference count for contract " + id); + throw new Error("Missing reference count for contract"); + } + }); + return esm_default("chelonia/private/out/sync", listOfIds, { ...params, force: true }); + }, + "chelonia/contract/isSyncing": function(contractID, { firstSync = false } = {}) { + const isSyncing = !!this.currentSyncs[contractID]; + return firstSync ? isSyncing && this.currentSyncs[contractID].firstSync : isSyncing; + }, + "chelonia/contract/currentSyncs": function() { + return Object.keys(this.currentSyncs); + }, + // Because `/remove` is done asynchronously and a contract might be removed + // much later than when the call to remove was made, an optional callback + // can be passed to verify whether to proceed with removal. This is used as + // part of the `/release` mechanism to prevent removing contracts that have + // acquired new references since the call to `/remove`. + "chelonia/contract/remove": function(contractIDs, { confirmRemovalCallback, permanent } = {}) { + const rootState = esm_default(this.config.stateSelector); + const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; + return Promise.all(listOfIds.map((contractID) => { + if (!rootState?.contracts?.[contractID]) { + return void 0; + } + return esm_default("chelonia/private/queueEvent", contractID, () => { + if (confirmRemovalCallback && !confirmRemovalCallback(contractID)) { + return; } - _randomIndex() { - return Math.random().toString(36).slice(2); + const rootState2 = esm_default(this.config.stateSelector); + const fkContractIDs = Array.from(new Set(Object.values(rootState2[contractID]?._vm?.authorizedKeys ?? {}).filter((k) => { + return !!k.foreignKey; + }).map((k) => { + try { + const fkUrl = new URL(k.foreignKey); + return fkUrl.pathname; + } catch { + return void 0; + } + }).filter(Boolean))); + esm_default("chelonia/private/removeImmediately", contractID, { permanent }); + if (fkContractIDs.length) { + esm_default("chelonia/contract/release", fkContractIDs, { try: true }).catch((e2) => { + console.error("[chelonia] Error attempting to release foreign key contracts", e2); + }); } - check(weight = 1) { - return this._store.__check__(weight); + }); + })); + }, + "chelonia/contract/retain": async function(contractIDs, params) { + const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; + const rootState = esm_default(this.config.stateSelector); + if (listOfIds.length === 0) + return Promise.resolve(); + const checkIfDeleted = (id) => { + if (rootState.contracts[id] === null) { + console.error("[chelonia/contract/retain] Called /retain on permanently deleted contract.", id); + throw new ChelErrorResourceGone("Unable to retain permanently deleted contract " + id); + } + }; + if (!params?.ephemeral) { + listOfIds.forEach((id) => { + checkIfDeleted(id); + if (!has(rootState.contracts, id)) { + this.config.reactiveSet(rootState.contracts, id, /* @__PURE__ */ Object.create(null)); + } + this.config.reactiveSet(rootState.contracts[id], "references", (rootState.contracts[id].references ?? 0) + 1); + }); + } else { + listOfIds.forEach((id) => { + checkIfDeleted(id); + if (!has(this.ephemeralReferenceCount, id)) { + this.ephemeralReferenceCount[id] = 1; + } else { + this.ephemeralReferenceCount[id] = this.ephemeralReferenceCount[id] + 1; } - _clearGlobalState(index) { - if (this._scheduled[index] != null) { - clearTimeout(this._scheduled[index].expiration); - delete this._scheduled[index]; - return true; - } else { - return false; + }); + } + return await esm_default("chelonia/private/out/sync", listOfIds); + }, + // the `try` parameter does not affect (ephemeral or persistent) reference + // counts, but rather removes a contract if the reference count is zero + // and the contract isn't being monitored for foreign keys. This parameter + // is meant mostly for internal chelonia use, so that removing or releasing + // a contract can also remove other contracts that this first contract + // was monitoring. + "chelonia/contract/release": async function(contractIDs, params) { + const listOfIds = typeof contractIDs === "string" ? [contractIDs] : contractIDs; + const rootState = esm_default(this.config.stateSelector); + if (!params?.try) { + if (!params?.ephemeral) { + listOfIds.forEach((id) => { + if (rootState.contracts[id] === null) { + console.warn("[chelonia/contract/release] Called /release on permanently deleted contract. This has no effect.", id); + return; } - } - _free(index, job, options2, eventInfo) { - var _this = this; - return _asyncToGenerator2(function* () { - var e2, running; - try { - var _ref = yield _this._store.__free__(index, options2.weight); - running = _ref.running; - _this.Events.trigger("debug", `Freed ${options2.id}`, eventInfo); - if (running === 0 && _this.empty()) { - return _this.Events.trigger("idle"); + if (has(rootState.contracts, id) && has(rootState.contracts[id], "references")) { + const current = rootState.contracts[id].references; + if (current === 0) { + console.error("[chelonia/contract/release] Invalid negative reference count for", id); + if (process.env.CI) { + Promise.reject(new Error("Invalid negative reference count: " + id)); } - } catch (error1) { - e2 = error1; - return _this.Events.trigger("error", e2); + throw new Error("Invalid negative reference count"); } - })(); - } - _run(index, job, wait) { - var clearGlobalState, free, run2; - job.doRun(); - clearGlobalState = this._clearGlobalState.bind(this, index); - run2 = this._run.bind(this, index, job); - free = this._free.bind(this, index, job); - return this._scheduled[index] = { - timeout: setTimeout(() => { - return job.doExecute(this._limiter, clearGlobalState, run2, free); - }, wait), - expiration: job.options.expiration != null ? setTimeout(function() { - return job.doExpire(clearGlobalState, run2, free); - }, wait + job.options.expiration) : void 0, - job - }; - } - _drainOne(capacity) { - return this._registerLock.schedule(() => { - var args, index, next, options2, queue; - if (this.queued() === 0) { - return this.Promise.resolve(null); + if (current <= 1) { + this.config.reactiveDel(rootState.contracts[id], "references"); + } else { + this.config.reactiveSet(rootState.contracts[id], "references", current - 1); } - queue = this._queues.getFirst(); - var _next2 = next = queue.first(); - options2 = _next2.options; - args = _next2.args; - if (capacity != null && options2.weight > capacity) { - return this.Promise.resolve(null); + } else { + console.error("[chelonia/contract/release] Invalid negative reference count for", id); + if (process.env.CI) { + Promise.reject(new Error("Invalid negative reference count: " + id)); } - this.Events.trigger("debug", `Draining ${options2.id}`, { - args, - options: options2 - }); - index = this._randomIndex(); - return this._store.__register__(index, options2.weight, options2.expiration).then(({ - success, - wait, - reservoir - }) => { - var empty2; - this.Events.trigger("debug", `Drained ${options2.id}`, { - success, - args, - options: options2 - }); - if (success) { - queue.shift(); - empty2 = this.empty(); - if (empty2) { - this.Events.trigger("empty"); - } - if (reservoir === 0) { - this.Events.trigger("depleted", empty2); - } - this._run(index, next, wait); - return this.Promise.resolve(options2.weight); - } else { - return this.Promise.resolve(null); - } - }); - }); - } - _drainAll(capacity, total = 0) { - return this._drainOne(capacity).then((drained) => { - var newCapacity; - if (drained != null) { - newCapacity = capacity != null ? capacity - drained : capacity; - return this._drainAll(newCapacity, total + drained); + throw new Error("Invalid negative reference count"); + } + }); + } else { + listOfIds.forEach((id) => { + if (rootState.contracts[id] === null) { + console.warn("[chelonia/contract/release] Called /release on permanently deleted contract. This has no effect.", id); + return; + } + if (has(this.ephemeralReferenceCount, id)) { + const current = this.ephemeralReferenceCount[id] ?? 0; + if (current <= 1) { + delete this.ephemeralReferenceCount[id]; } else { - return this.Promise.resolve(total); + this.ephemeralReferenceCount[id] = current - 1; } - }).catch((e2) => { - return this.Events.trigger("error", e2); - }); + } else { + console.error("[chelonia/contract/release] Invalid negative ephemeral reference count for", id); + if (process.env.CI) { + Promise.reject(new Error("Invalid negative ephemeral reference count: " + id)); + } + throw new Error("Invalid negative ephemeral reference count"); + } + }); + } + } + const boundCheckCanBeGarbageCollected = checkCanBeGarbageCollected.bind(this); + const idsToRemove = listOfIds.filter(boundCheckCanBeGarbageCollected); + return idsToRemove.length ? await esm_default("chelonia/contract/remove", idsToRemove, { + confirmRemovalCallback: boundCheckCanBeGarbageCollected + }) : void 0; + }, + "chelonia/contract/disconnect": async function(contractID, contractIDToDisconnect) { + const state = esm_default(this.config.stateSelector); + const contractState = state[contractID]; + const keyIds = Object.values(contractState._vm.authorizedKeys).filter((k) => { + return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractIDToDisconnect; + }).map((k) => k.id); + if (!keyIds.length) + return; + return await esm_default("chelonia/out/keyDel", { + contractID, + contractName: contractState._vm.type, + data: keyIds, + signingKeyId: findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_DEL], ["sig"]) + }); + }, + "chelonia/in/processMessage": function(messageOrRawMessage, state) { + const stateCopy = cloneDeep(state); + const message = typeof messageOrRawMessage === "string" ? SPMessage.deserialize(messageOrRawMessage, this.transientSecretKeys, stateCopy, this.config.unwrapMaybeEncryptedData) : messageOrRawMessage; + return esm_default("chelonia/private/in/processMessage", message, stateCopy).then(() => stateCopy).catch((e2) => { + console.warn(`chelonia/in/processMessage: reverting mutation ${message.description()}: ${message.serialize()}`, e2); + return state; + }); + }, + "chelonia/out/fetchResource": async function(cid, { code: code2 } = {}) { + const parsedCID = parseCID(cid); + if (code2 != null) { + if (parsedCID.code !== code2) { + throw new Error(`Invalid CID content type. Expected ${code2}, got ${parsedCID.code}`); + } + } + const local = await esm_default("chelonia.db/get", cid); + if (local != null) + return local; + const url2 = `${this.config.connectionURL}/file/${cid}`; + const data = await this.config.fetch(url2, { signal: this.abortController.signal }).then(handleFetchResult("text")); + const ourHash = createCID(data, parsedCID.code); + if (ourHash !== cid) { + throw new Error(`expected hash ${cid}. Got: ${ourHash}`); + } + await esm_default("chelonia.db/set", cid, data); + return data; + }, + "chelonia/out/latestHEADInfo": function(contractID) { + return this.config.fetch(`${this.config.connectionURL}/latestHEADinfo/${contractID}`, { + cache: "no-store", + signal: this.abortController.signal + }).then(handleFetchResult("json")); + }, + "chelonia/out/deserializedHEAD": async function(hash3, { contractID } = {}) { + const message = await esm_default("chelonia/out/fetchResource", hash3, { + code: multicodes.SHELTER_CONTRACT_DATA + }); + const deserializedHEAD = SPMessage.deserializeHEAD(message); + if (contractID && deserializedHEAD.contractID !== contractID) { + throw new Error("chelonia/out/deserializedHEAD: Mismatched contract ID"); + } + return deserializedHEAD; + }, + "chelonia/out/eventsAfter": eventsAfter, + "chelonia/out/eventsBefore": function(contractID, { beforeHeight, limit, stream }) { + if (limit <= 0) { + console.error('[chelonia] invalid params error: "limit" needs to be positive integer'); + } + const offset = Math.max(0, beforeHeight - limit + 1); + const eventsAfterLimit = Math.min(beforeHeight + 1, limit); + return esm_default("chelonia/out/eventsAfter", contractID, { + sinceHeight: offset, + limit: eventsAfterLimit, + stream + }); + }, + "chelonia/out/eventsBetween": function(contractID, { startHash, endHeight = Number.POSITIVE_INFINITY, offset = 0, limit = 0, stream = true }) { + if (offset < 0) { + console.error('[chelonia] invalid params error: "offset" needs to be positive integer or zero'); + return; + } + let reader; + const s = new ReadableStream({ + start: async (controller) => { + const deserializedHEAD = await esm_default("chelonia/out/deserializedHEAD", startHash, { contractID }); + const startOffset = Math.max(0, deserializedHEAD.head.height - offset); + const ourLimit = limit ? Math.min(endHeight - startOffset + 1, limit) : endHeight - startOffset + 1; + if (ourLimit < 1) { + controller.close(); + return; } - _dropAllQueued(message) { - return this._queues.shiftAll(function(job) { - return job.doDrop({ - message - }); - }); + reader = esm_default("chelonia/out/eventsAfter", contractID, { + sinceHeight: startOffset, + limit: ourLimit + }).getReader(); + }, + async pull(controller) { + const { done, value } = await reader.read(); + if (done) { + controller.close(); + } else { + controller.enqueue(value); } - stop(options2 = {}) { - var done, waitForExecuting; - options2 = parser3.load(options2, this.stopDefaults); - waitForExecuting = (at) => { - var finished; - finished = () => { - var counts; - counts = this._states.counts; - return counts[0] + counts[1] + counts[2] + counts[3] === at; - }; - return new this.Promise((resolve82, reject) => { - if (finished()) { - return resolve82(); - } else { - return this.on("done", () => { - if (finished()) { - this.removeAllListeners("done"); - return resolve82(); - } - }); - } - }); - }; - done = options2.dropWaitingJobs ? (this._run = function(index, next) { - return next.doDrop({ - message: options2.dropErrorMessage - }); - }, this._drainOne = () => { - return this.Promise.resolve(null); - }, this._registerLock.schedule(() => { - return this._submitLock.schedule(() => { - var k, ref, v2; - ref = this._scheduled; - for (k in ref) { - v2 = ref[k]; - if (this.jobStatus(v2.job.options.id) === "RUNNING") { - clearTimeout(v2.timeout); - clearTimeout(v2.expiration); - v2.job.doDrop({ - message: options2.dropErrorMessage - }); - } - } - this._dropAllQueued(options2.dropErrorMessage); - return waitForExecuting(0); - }); - })) : this.schedule({ - priority: NUM_PRIORITIES - 1, - weight: 0 - }, () => { - return waitForExecuting(1); - }); - this._receive = function(job) { - return job._reject(new Bottleneck3.prototype.BottleneckError(options2.enqueueErrorMessage)); - }; - this.stop = () => { - return this.Promise.reject(new Bottleneck3.prototype.BottleneckError("stop() has already been called")); - }; - return done; + } + }); + if (stream) + return s; + return collectEventStream(s); + }, + "chelonia/rootState": function() { + return esm_default(this.config.stateSelector); + }, + "chelonia/latestContractState": async function(contractID, options2 = { forceSync: false }) { + const rootState = esm_default(this.config.stateSelector); + if (rootState.contracts[contractID] === null) { + throw new ChelErrorResourceGone("Permanently deleted contract " + contractID); + } + if (!options2.forceSync && rootState[contractID] && Object.keys(rootState[contractID]).some((x3) => x3 !== "_volatile")) { + return cloneDeep(rootState[contractID]); + } + let state = /* @__PURE__ */ Object.create(null); + let contractName = rootState.contracts[contractID]?.type; + const eventsStream = esm_default("chelonia/out/eventsAfter", contractID, { + sinceHeight: 0, + sinceHash: contractID + }); + const eventsStreamReader = eventsStream.getReader(); + if (rootState[contractID]) + state._volatile = rootState[contractID]._volatile; + for (; ; ) { + const { value: event, done } = await eventsStreamReader.read(); + if (done) + return state; + const stateCopy = cloneDeep(state); + try { + await esm_default("chelonia/private/in/processMessage", SPMessage.deserialize(event, this.transientSecretKeys, state, this.config.unwrapMaybeEncryptedData), state, void 0, contractName); + if (!contractName && state._vm) { + contractName = state._vm.type; } - _addToQueue(job) { - var _this2 = this; - return _asyncToGenerator2(function* () { - var args, blocked, error2, options2, reachedHWM, shifted, strategy; - args = job.args; - options2 = job.options; - try { - var _ref2 = yield _this2._store.__submit__(_this2.queued(), options2.weight); - reachedHWM = _ref2.reachedHWM; - blocked = _ref2.blocked; - strategy = _ref2.strategy; - } catch (error1) { - error2 = error1; - _this2.Events.trigger("debug", `Could not queue ${options2.id}`, { - args, - options: options2, - error: error2 - }); - job.doDrop({ - error: error2 - }); - return false; - } - if (blocked) { - job.doDrop(); - return true; - } else if (reachedHWM) { - shifted = strategy === Bottleneck3.prototype.strategy.LEAK ? _this2._queues.shiftLastFrom(options2.priority) : strategy === Bottleneck3.prototype.strategy.OVERFLOW_PRIORITY ? _this2._queues.shiftLastFrom(options2.priority + 1) : strategy === Bottleneck3.prototype.strategy.OVERFLOW ? job : void 0; - if (shifted != null) { - shifted.doDrop(); - } - if (shifted == null || strategy === Bottleneck3.prototype.strategy.OVERFLOW) { - if (shifted == null) { - job.doDrop(); - } - return reachedHWM; - } - } - job.doQueue(reachedHWM, blocked); - _this2._queues.push(job); - yield _this2._drainAll(); - return reachedHWM; - })(); + } catch (e2) { + console.warn(`[chelonia] latestContractState: '${e2.name}': ${e2.message} processing:`, event, e2.stack); + if (e2 instanceof ChelErrorUnrecoverable) + throw e2; + state = stateCopy; + } + } + }, + "chelonia/contract/state": function(contractID, height) { + const state = esm_default(this.config.stateSelector)[contractID]; + const stateCopy = state && cloneDeep(state); + if (stateCopy?._vm && height != null) { + Object.keys(stateCopy._vm.authorizedKeys).forEach((keyId2) => { + if (stateCopy._vm.authorizedKeys[keyId2]._notBeforeHeight > height) { + delete stateCopy._vm.authorizedKeys[keyId2]; } - _receive(job) { - if (this._states.jobStatus(job.options.id) != null) { - job._reject(new Bottleneck3.prototype.BottleneckError(`A job with the same id already exists (id=${job.options.id})`)); - return false; - } else { - job.doReceive(); - return this._submitLock.schedule(this._addToQueue, job); + }); + } + return stateCopy; + }, + "chelonia/contract/fullState": function(contractID) { + const rootState = esm_default(this.config.stateSelector); + if (Array.isArray(contractID)) { + return Object.fromEntries(contractID.map((contractID2) => { + return [ + contractID2, + { + contractState: rootState[contractID2], + cheloniaState: rootState.contracts[contractID2] } + ]; + })); + } + return { + contractState: rootState[contractID], + cheloniaState: rootState.contracts[contractID] + }; + }, + // 'chelonia/out' - selectors that send data out to the server + "chelonia/out/registerContract": async function(params) { + const { contractName, keys, hooks, publishOptions, signingKeyId, actionSigningKeyId, actionEncryptionKeyId } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contractInfo = this.manifestToContract[manifestHash]; + if (!contractInfo) + throw new Error(`contract not defined: ${contractName}`); + const signingKey = this.transientSecretKeys[signingKeyId]; + if (!signingKey) + throw new Error(`Signing key ${signingKeyId} is not defined`); + const payload = { + type: contractName, + keys + }; + const contractMsg = SPMessage.createV1_0({ + contractID: null, + height: 0, + op: [ + SPMessage.OP_CONTRACT, + signedOutgoingDataWithRawKey(signingKey, payload) + ], + manifest: manifestHash + }); + const contractID = contractMsg.hash(); + await esm_default("chelonia/private/out/publishEvent", contractMsg, params.namespaceRegistration ? { + ...publishOptions, + headers: { + ...publishOptions?.headers, + "shelter-namespace-registration": params.namespaceRegistration + } + } : publishOptions, hooks && { + prepublish: hooks.prepublishContract, + postpublish: hooks.postpublishContract + }); + await esm_default("chelonia/private/out/sync", contractID); + const msg = await esm_default(actionEncryptionKeyId ? "chelonia/out/actionEncrypted" : "chelonia/out/actionUnencrypted", { + action: contractName, + contractID, + data: params.data, + signingKeyId: actionSigningKeyId ?? signingKeyId, + encryptionKeyId: actionEncryptionKeyId, + hooks, + publishOptions + }); + return msg; + }, + "chelonia/out/ownResources": async function(contractID) { + if (!contractID) { + throw new TypeError("A contract ID must be provided"); + } + const response = await this.config.fetch(`${this.config.connectionURL}/ownResources`, { + method: "GET", + signal: this.abortController.signal, + headers: new Headers([ + ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] + ]) + }); + if (!response.ok) { + console.error("Unable to fetch own resources", contractID, response.status); + throw new Error(`Unable to fetch own resources for ${contractID}: ${response.status}`); + } + return response.json(); + }, + "chelonia/out/deleteContract": async function(contractID, credentials = {}) { + if (!contractID) { + throw new TypeError("A contract ID must be provided"); + } + if (!Array.isArray(contractID)) + contractID = [contractID]; + return await Promise.allSettled(contractID.map(async (cid) => { + const hasCredential = has(credentials, cid); + const hasToken = has(credentials[cid], "token") && credentials[cid].token; + const hasBillableContractID = has(credentials[cid], "billableContractID") && credentials[cid].billableContractID; + if (!hasCredential || hasToken === hasBillableContractID) { + throw new TypeError(`Either a token or a billable contract ID must be provided for ${cid}`); + } + const response = await this.config.fetch(`${this.config.connectionURL}/deleteContract/${cid}`, { + method: "POST", + signal: this.abortController.signal, + headers: new Headers([ + [ + "authorization", + hasToken ? `bearer ${credentials[cid].token.valueOf()}` : buildShelterAuthorizationHeader.call(this, credentials[cid].billableContractID) + ] + ]) + }); + if (!response.ok) { + if (response.status === 404 || response.status === 410) { + console.warn("Contract appears to have been deleted already", cid, response.status); + return; } - submit(...args) { - var cb, fn, job, options2, ref, ref1, task; - if (typeof args[0] === "function") { - var _ref3, _ref4, _splice$call, _splice$call2; - ref = args, _ref3 = ref, _ref4 = _toArray(_ref3), fn = _ref4[0], args = _ref4.slice(1), _ref3, _splice$call = splice.call(args, -1), _splice$call2 = _slicedToArray2(_splice$call, 1), cb = _splice$call2[0], _splice$call; - options2 = parser3.load({}, this.jobDefaults); - } else { - var _ref5, _ref6, _splice$call3, _splice$call4; - ref1 = args, _ref5 = ref1, _ref6 = _toArray(_ref5), options2 = _ref6[0], fn = _ref6[1], args = _ref6.slice(2), _ref5, _splice$call3 = splice.call(args, -1), _splice$call4 = _slicedToArray2(_splice$call3, 1), cb = _splice$call4[0], _splice$call3; - options2 = parser3.load(options2, this.jobDefaults); - } - task = (...args2) => { - return new this.Promise(function(resolve82, reject) { - return fn(...args2, function(...args3) { - return (args3[0] != null ? reject : resolve82)(args3); - }); - }); - }; - job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); - job.promise.then(function(args2) { - return typeof cb === "function" ? cb(...args2) : void 0; - }).catch(function(args2) { - if (Array.isArray(args2)) { - return typeof cb === "function" ? cb(...args2) : void 0; - } else { - return typeof cb === "function" ? cb(args2) : void 0; - } - }); - return this._receive(job); + console.error("Unable to delete contract", cid, response.status); + throw new Error(`Unable to delete contract ${cid}: ${response.status}`); + } + })); + }, + // all of these functions will do both the creation of the SPMessage + // and the sending of it via 'chelonia/private/out/publishEvent' + "chelonia/out/actionEncrypted": function(params) { + return outEncryptedOrUnencryptedAction.call(this, SPMessage.OP_ACTION_ENCRYPTED, params); + }, + "chelonia/out/actionUnencrypted": function(params) { + return outEncryptedOrUnencryptedAction.call(this, SPMessage.OP_ACTION_UNENCRYPTED, params); + }, + "chelonia/out/keyShare": async function(params) { + const { atomic, originatingContractName, originatingContractID, contractName, contractID, data, hooks, publishOptions } = params; + const originatingManifestHash = this.config.contracts.manifests[originatingContractName]; + const destinationManifestHash = this.config.contracts.manifests[contractName]; + const originatingContract = originatingContractID ? this.manifestToContract[originatingManifestHash]?.contract : void 0; + const destinationContract = this.manifestToContract[destinationManifestHash]?.contract; + if (originatingContractID && !originatingContract || !destinationContract) { + throw new Error("Contract name not found"); + } + const payload = data; + if (!params.signingKeyId && !params.signingKey) { + throw new TypeError("Either signingKeyId or signingKey must be specified"); + } + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_SHARE, + params.signingKeyId ? signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) : signedOutgoingDataWithRawKey(params.signingKey, payload) + ], + manifest: destinationManifestHash + }); + if (!atomic) { + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); + } + return msg; + }, + "chelonia/out/keyAdd": async function(params) { + const { atomic, contractID, contractName, data, hooks, publishOptions } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const state = contract.state(contractID); + const payload = params.skipExistingKeyCheck ? data : data.filter((wk) => { + const k = isEncryptedData(wk) ? wk.valueOf() : wk; + if (has(state._vm.authorizedKeys, k.id)) { + if (state._vm.authorizedKeys[k.id]._notAfterHeight == null) { + return false; } - schedule(...args) { - var job, options2, task; - if (typeof args[0] === "function") { - var _args = args; - var _args2 = _toArray(_args); - task = _args2[0]; - args = _args2.slice(1); - options2 = {}; - } else { - var _args3 = args; - var _args4 = _toArray(_args3); - options2 = _args4[0]; - task = _args4[1]; - args = _args4.slice(2); + } + return true; + }); + if (payload.length === 0) + return; + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_ADD, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + if (!atomic) { + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); + } + return msg; + }, + "chelonia/out/keyDel": async function(params) { + const { atomic, contractID, contractName, data, hooks, publishOptions } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const state = contract.state(contractID); + const payload = data.map((keyId2) => { + if (isEncryptedData(keyId2)) + return keyId2; + if (!has(state._vm.authorizedKeys, keyId2) || state._vm.authorizedKeys[keyId2]._notAfterHeight != null) { + return void 0; + } + if (state._vm.authorizedKeys[keyId2]._private) { + return encryptedOutgoingData(contractID, state._vm.authorizedKeys[keyId2]._private, keyId2); + } else { + return keyId2; + } + }).filter(Boolean); + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_DEL, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + if (!atomic) { + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); + } + return msg; + }, + "chelonia/out/keyUpdate": async function(params) { + const { atomic, contractID, contractName, data, hooks, publishOptions } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const state = contract.state(contractID); + const payload = data.map((key) => { + if (isEncryptedData(key)) + return key; + const { oldKeyId } = key; + if (state._vm.authorizedKeys[oldKeyId]._private) { + return encryptedOutgoingData(contractID, state._vm.authorizedKeys[oldKeyId]._private, key); + } else { + return key; + } + }); + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_UPDATE, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + if (!atomic) { + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); + } + return msg; + }, + "chelonia/out/keyRequest": async function(params) { + const { originatingContractID, originatingContractName, contractID, contractName, hooks, publishOptions, innerSigningKeyId, encryptionKeyId, innerEncryptionKeyId, encryptKeyRequestMetadata, reference } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const originatingManifestHash = this.config.contracts.manifests[originatingContractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + const originatingContract = this.manifestToContract[originatingManifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const rootState = esm_default(this.config.stateSelector); + try { + await esm_default("chelonia/contract/retain", contractID, { ephemeral: true }); + const state = contract.state(contractID); + const originatingState = originatingContract.state(originatingContractID); + const havePendingKeyRequest = Object.values(originatingState._vm.authorizedKeys).findIndex((k) => { + return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractID && state?._volatile?.pendingKeyRequests?.some((pkr) => pkr.name === k.name); + }) !== -1; + if (havePendingKeyRequest) { + return; + } + const keyRequestReplyKey = keygen(EDWARDS25519SHA512BATCH); + const keyRequestReplyKeyId = keyId(keyRequestReplyKey); + const keyRequestReplyKeyP = serializeKey(keyRequestReplyKey, false); + const keyRequestReplyKeyS = serializeKey(keyRequestReplyKey, true); + const signingKeyId = findSuitableSecretKeyId(originatingState, [SPMessage.OP_KEY_ADD], ["sig"]); + if (!signingKeyId) { + throw new ChelErrorUnexpected(`Unable to send key request. Originating contract is missing a key with OP_KEY_ADD permission. contractID=${contractID} originatingContractID=${originatingContractID}`); + } + const keyAddOp = () => esm_default("chelonia/out/keyAdd", { + contractID: originatingContractID, + contractName: originatingContractName, + data: [ + { + id: keyRequestReplyKeyId, + name: "#krrk-" + keyRequestReplyKeyId, + purpose: ["sig"], + ringLevel: Number.MAX_SAFE_INTEGER, + permissions: params.permissions === "*" ? "*" : Array.isArray(params.permissions) ? [...params.permissions, SPMessage.OP_KEY_SHARE] : [SPMessage.OP_KEY_SHARE], + allowedActions: params.allowedActions, + meta: { + private: { + content: encryptedOutgoingData(originatingContractID, encryptionKeyId, keyRequestReplyKeyS), + shareable: false + }, + keyRequest: { + ...reference && { + reference: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, reference) : reference + }, + contractID: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, contractID) : contractID + } + }, + data: keyRequestReplyKeyP } - job = new Job(task, args, options2, this.jobDefaults, this.rejectOnDrop, this.Events, this._states, this.Promise); - this._receive(job); - return job.promise; - } - wrap(fn) { - var schedule, wrapped; - schedule = this.schedule.bind(this); - wrapped = function wrapped2(...args) { - return schedule(fn.bind(this), ...args); - }; - wrapped.withOptions = function(options2, ...args) { - return schedule(options2, fn, ...args); - }; - return wrapped; + ], + signingKeyId + }).catch((e2) => { + console.error(`[chelonia] Error sending OP_KEY_ADD for ${originatingContractID} during key request to ${contractID}`, e2); + throw e2; + }); + const payload = { + contractID: originatingContractID, + height: rootState.contracts[originatingContractID].height, + replyWith: signedOutgoingData(originatingContractID, innerSigningKeyId, { + encryptionKeyId, + responseKey: encryptedOutgoingData(contractID, innerEncryptionKeyId, keyRequestReplyKeyS) + }, this.transientSecretKeys), + request: "*" + }; + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_REQUEST, + signedOutgoingData(contractID, params.signingKeyId, encryptKeyRequestMetadata ? encryptedOutgoingData(contractID, innerEncryptionKeyId, payload) : payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, { + ...hooks, + // We ensure that both messages are placed into the publish queue + prepublish: (...args) => { + return keyAddOp().then(() => hooks?.prepublish?.(...args)); } - updateSettings(options2 = {}) { - var _this3 = this; - return _asyncToGenerator2(function* () { - yield _this3._store.__updateSettings__(parser3.overwrite(options2, _this3.storeDefaults)); - parser3.overwrite(options2, _this3.instanceDefaults, _this3); - return _this3; - })(); + }); + return msg; + } finally { + await esm_default("chelonia/contract/release", contractID, { ephemeral: true }); + } + }, + "chelonia/out/keyRequestResponse": async function(params) { + const { atomic, contractID, contractName, data, hooks, publishOptions } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const payload = data; + let message = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_KEY_REQUEST_SEEN, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + if (!atomic) { + message = await esm_default("chelonia/private/out/publishEvent", message, publishOptions, hooks); + } + return message; + }, + "chelonia/out/atomic": async function(params) { + const { contractID, contractName, data, hooks, publishOptions } = params; + const manifestHash = this.config.contracts.manifests[contractName]; + const contract = this.manifestToContract[manifestHash]?.contract; + if (!contract) { + throw new Error("Contract name not found"); + } + const payload = (await Promise.all(data.map(([selector, opParams]) => { + if (![ + "chelonia/out/actionEncrypted", + "chelonia/out/actionUnencrypted", + "chelonia/out/keyAdd", + "chelonia/out/keyDel", + "chelonia/out/keyUpdate", + "chelonia/out/keyRequestResponse", + "chelonia/out/keyShare" + ].includes(selector)) { + throw new Error("Selector not allowed in OP_ATOMIC: " + selector); + } + return esm_default(selector, { + ...opParams, + ...params, + data: opParams.data, + atomic: true + }); + }))).flat().filter(Boolean).map((msg2) => { + return [msg2.opType(), msg2.opValue()]; + }); + let msg = SPMessage.createV1_0({ + contractID, + op: [ + SPMessage.OP_ATOMIC, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + msg = await esm_default("chelonia/private/out/publishEvent", msg, publishOptions, hooks); + return msg; + }, + "chelonia/out/protocolUpgrade": async function() { + }, + "chelonia/out/propSet": async function() { + }, + "chelonia/out/propDel": async function() { + }, + "chelonia/out/encryptedOrUnencryptedPubMessage": function({ contractID, innerSigningKeyId, encryptionKeyId, signingKeyId, data }) { + const serializedData = outputEncryptedOrUnencryptedMessage.call(this, { + contractID, + innerSigningKeyId, + encryptionKeyId, + signingKeyId, + data + }); + this.pubsub.pub(contractID, serializedData); + }, + // Note: This is a bare-bones function designed for precise control. In many + // situations, the `chelonia/kv/queuedSet` selector (in chelonia-utils.js) + // will be simpler and more appropriate to use. + // In most situations, you want to use some queuing strategy (which this + // selector doesn't provide) alongside writing to the KV store. Therefore, as + // a general rule, you shouldn't be calling this selector directly unless + // you're building a utility library or if you have very specific needs. In + // this case, see if `chelonia/kv/queuedSet` covers your needs. + // `data` is allowed to be falsy, in which case a fetch will occur first and + // the `onconflict` handler will be called. + "chelonia/kv/set": async function(contractID, key, data, { ifMatch, innerSigningKeyId, encryptionKeyId, signingKeyId, maxAttempts, onconflict }) { + maxAttempts = maxAttempts ?? 3; + const url2 = `${this.config.connectionURL}/kv/${encodeURIComponent(contractID)}/${encodeURIComponent(key)}`; + const hasOnconflict = typeof onconflict === "function"; + let response; + const resolveData = async () => { + let currentValue; + if (response.ok || response.status === 409 || response.status === 412) { + const serializedDataText = await response.text(); + currentValue = serializedDataText ? parseEncryptedOrUnencryptedMessage(this, { + contractID, + serializedData: JSON.parse(serializedDataText), + meta: key + }) : void 0; + } else if (response.status !== 404 && response.status !== 410) { + throw new ChelErrorUnexpectedHttpResponseCode("[kv/set] Invalid response code: " + response.status); + } + const result = await onconflict({ + contractID, + key, + failedData: data, + status: response.status, + // If no x-cid or etag header was returned, `ifMatch` would likely be + // returned as undefined, which will then use the `''` fallback value + // when writing. This allows 404 / 410 responses to work even if no + // etag is explicitly given + etag: response.headers.get("x-cid") || response.headers.get("etag"), + get currentData() { + return currentValue?.data; + }, + currentValue + }); + if (!result) + return false; + data = result[0]; + ifMatch = result[1]; + return true; + }; + for (; ; ) { + if (data !== void 0) { + const serializedData = outputEncryptedOrUnencryptedMessage.call(this, { + contractID, + innerSigningKeyId, + encryptionKeyId, + signingKeyId, + data, + meta: key + }); + response = await this.config.fetch(url2, { + headers: new Headers([ + ["authorization", buildShelterAuthorizationHeader.call(this, contractID)], + ["if-match", ifMatch || '""'] + ]), + method: "POST", + body: JSON.stringify(serializedData), + signal: this.abortController.signal + }); + } else { + if (!hasOnconflict) { + throw TypeError("onconflict required with empty data"); } - currentReservoir() { - return this._store.__currentReservoir__(); + response = await this.config.fetch(url2, { + headers: new Headers([ + ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] + ]), + signal: this.abortController.signal + }); + if (await resolveData()) { + continue; + } else { + break; } - incrementReservoir(incr = 0) { - return this._store.__incrementReservoir__(incr); + } + if (!response.ok) { + if (response.status === 409 || response.status === 412) { + if (--maxAttempts <= 0) { + throw new Error("kv/set conflict setting KV value"); + } + await delay(randomIntFromRange(0, 1500)); + if (hasOnconflict) { + if (await resolveData()) { + continue; + } else { + break; + } + } else { + throw new Error(`kv/set failed with status ${response.status} and no onconflict handler was provided`); + } } + throw new ChelErrorUnexpectedHttpResponseCode("kv/set invalid response status: " + response.status); } - ; - Bottleneck3.default = Bottleneck3; - Bottleneck3.Events = Events2; - Bottleneck3.version = Bottleneck3.prototype.version = require_version().version; - Bottleneck3.strategy = Bottleneck3.prototype.strategy = { - LEAK: 1, - OVERFLOW: 2, - OVERFLOW_PRIORITY: 4, - BLOCK: 3 - }; - Bottleneck3.BottleneckError = Bottleneck3.prototype.BottleneckError = require_BottleneckError(); - Bottleneck3.Group = Bottleneck3.prototype.Group = require_Group(); - Bottleneck3.RedisConnection = Bottleneck3.prototype.RedisConnection = require_RedisConnection(); - Bottleneck3.IORedisConnection = Bottleneck3.prototype.IORedisConnection = require_IORedisConnection(); - Bottleneck3.Batcher = Bottleneck3.prototype.Batcher = require_Batcher(); - Bottleneck3.prototype.jobDefaults = { - priority: DEFAULT_PRIORITY, - weight: 1, - expiration: null, - id: "" - }; - Bottleneck3.prototype.storeDefaults = { - maxConcurrent: null, - minTime: 0, - highWater: null, - strategy: Bottleneck3.prototype.strategy.LEAK, - penalty: null, - reservoir: null, - reservoirRefreshInterval: null, - reservoirRefreshAmount: null, - reservoirIncreaseInterval: null, - reservoirIncreaseAmount: null, - reservoirIncreaseMaximum: null - }; - Bottleneck3.prototype.localStoreDefaults = { - Promise, - timeout: null, - heartbeatInterval: 250 - }; - Bottleneck3.prototype.redisStoreDefaults = { - Promise, - timeout: null, - heartbeatInterval: 5e3, - clientTimeout: 1e4, - Redis: null, - clientOptions: {}, - clusterNodes: null, - clearDatastore: false, - connection: null - }; - Bottleneck3.prototype.instanceDefaults = { - datastore: "local", - connection: null, - id: "", - rejectOnDrop: true, - trackDoneStatus: false, - Promise - }; - Bottleneck3.prototype.stopDefaults = { - enqueueErrorMessage: "This limiter has been stopped and cannot accept new jobs.", - dropWaitingJobs: true, - dropErrorMessage: "This limiter has been stopped." - }; - return Bottleneck3; - }.call(void 0); - module14.exports = Bottleneck2; + break; + } + }, + "chelonia/kv/get": async function(contractID, key) { + const response = await this.config.fetch(`${this.config.connectionURL}/kv/${encodeURIComponent(contractID)}/${encodeURIComponent(key)}`, { + headers: new Headers([ + ["authorization", buildShelterAuthorizationHeader.call(this, contractID)] + ]), + signal: this.abortController.signal + }); + if (response.status === 404) { + return null; + } + if (!response.ok) { + throw new Error("Invalid response status: " + response.status); + } + const data = await response.json(); + return parseEncryptedOrUnencryptedMessage(this, { + contractID, + serializedData: data, + meta: key + }); + }, + // To set filters for a contract, call with `filter` set to an array of KV + // keys to receive updates for over the WebSocket. An empty array means that + // no KV updates will be sent. + // Calling with a single argument (the contract ID) will remove filters, + // meaning that KV updates will be sent for _any_ KV key. + // The last call takes precedence, so, for example, calling with filter + // set to `['foo', 'bar']` and then with `['baz']` means that KV updates will + // be received for `baz` only, not for `foo`, `bar` or any other keys. + "chelonia/kv/setFilter": function(contractID, filter) { + this.pubsub.setKvFilter(contractID, filter); + }, + "chelonia/parseEncryptedOrUnencryptedDetachedMessage": function({ contractID, serializedData, meta }) { + return parseEncryptedOrUnencryptedMessage(this, { + contractID, + serializedData, + meta + }); } }); -var require_lib6 = __commonJS({ - "node_modules/.deno/bottleneck@2.19.5/node_modules/bottleneck/lib/index.js"(exports2, module14) { - "use strict"; - module14.exports = require_Bottleneck(); +function contractNameFromAction(action) { + const regexResult = ACTION_REGEX.exec(action); + const contractName = regexResult?.[2]; + if (!contractName) + throw new Error(`Poorly named action '${action}': missing contract name.`); + return contractName; +} +function outputEncryptedOrUnencryptedMessage({ contractID, innerSigningKeyId, encryptionKeyId, signingKeyId, data, meta }) { + const state = esm_default(this.config.stateSelector)[contractID]; + const signedMessage = innerSigningKeyId ? state._vm.authorizedKeys[innerSigningKeyId] && state._vm.authorizedKeys[innerSigningKeyId]?._notAfterHeight == null ? signedOutgoingData(contractID, innerSigningKeyId, data, this.transientSecretKeys) : signedOutgoingDataWithRawKey(this.transientSecretKeys[innerSigningKeyId], data) : data; + const payload = !encryptionKeyId ? signedMessage : encryptedOutgoingData(contractID, encryptionKeyId, signedMessage); + const message = signedOutgoingData(contractID, signingKeyId, payload, this.transientSecretKeys); + const rootState = esm_default(this.config.stateSelector); + const height = String(rootState.contracts[contractID].height); + const serializedData = { ...message.serialize((meta ?? "") + height), height }; + return serializedData; +} +function parseEncryptedOrUnencryptedMessage(ctx, { contractID, serializedData, meta }) { + if (!serializedData) { + throw new TypeError("[chelonia] parseEncryptedOrUnencryptedMessage: serializedData is required"); } -}); -var getConnInfo2; -var init_conninfo2 = __esm({ - "node_modules/.deno/@hono+node-server@1.19.14/node_modules/@hono/node-server/dist/conninfo.mjs"() { - getConnInfo2 = (c) => { - const bindings = c.env.server ? c.env.server : c.env; - const address = bindings.incoming.socket.remoteAddress; - const port = bindings.incoming.socket.remotePort; - const family = bindings.incoming.socket.remoteFamily; - return { - remote: { - address, - port, - addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0 + const state = esm_default(ctx.config.stateSelector)[contractID]; + const numericHeight = parseInt(serializedData.height); + const rootState = esm_default(ctx.config.stateSelector); + const currentHeight = rootState.contracts[contractID].height; + if (!(numericHeight >= 0) || !(numericHeight <= currentHeight)) { + throw new Error(`[chelonia] parseEncryptedOrUnencryptedMessage: Invalid height ${serializedData.height}; it must be between 0 and ${currentHeight}`); + } + const aad = (meta ?? "") + serializedData.height; + const v2 = signedIncomingData(contractID, state, serializedData, numericHeight, aad, (message) => { + return maybeEncryptedIncomingData(contractID, state, message, numericHeight, ctx.transientSecretKeys, aad, void 0); + }); + let encryptionKeyId; + let innerSigningKeyId; + const unwrap2 = /* @__PURE__ */ (() => { + let result2; + return () => { + if (!result2) { + try { + let unwrapped; + unwrapped = v2.valueOf(); + if (isEncryptedData(unwrapped)) { + encryptionKeyId = unwrapped.encryptionKeyId; + unwrapped = unwrapped.valueOf(); + if (isSignedData(unwrapped)) { + innerSigningKeyId = unwrapped.signingKeyId; + unwrapped = unwrapped.valueOf(); + } else { + innerSigningKeyId = null; + } + } else { + encryptionKeyId = null; + innerSigningKeyId = null; + } + result2 = [unwrapped]; + } catch (e2) { + result2 = [void 0, e2]; } - }; + } + if (result2.length === 2) { + throw result2[1]; + } + return result2[0]; }; + })(); + const result = { + get contractID() { + return contractID; + }, + get innerSigningKeyId() { + if (innerSigningKeyId === void 0) { + try { + unwrap2(); + } catch { + } + } + return innerSigningKeyId; + }, + get encryptionKeyId() { + if (encryptionKeyId === void 0) { + try { + unwrap2(); + } catch { + } + } + return encryptionKeyId; + }, + get signingKeyId() { + return v2.signingKeyId; + }, + get data() { + return unwrap2(); + }, + get signingContractID() { + return getContractIDfromKeyId(contractID, result.signingKeyId, state); + }, + get innerSigningContractID() { + return getContractIDfromKeyId(contractID, result.innerSigningKeyId, state); + } + }; + return result; +} +async function outEncryptedOrUnencryptedAction(opType, params) { + const { atomic, action, contractID, data, hooks, publishOptions } = params; + const contractName = contractNameFromAction(action); + const manifestHash = this.config.contracts.manifests[contractName]; + const { contract } = this.manifestToContract[manifestHash]; + const state = contract.state(contractID); + const meta = await contract.metadata.create(); + const unencMessage = { action, data, meta }; + const signedMessage = params.innerSigningKeyId ? state._vm.authorizedKeys[params.innerSigningKeyId] && state._vm.authorizedKeys[params.innerSigningKeyId]?._notAfterHeight == null ? signedOutgoingData(contractID, params.innerSigningKeyId, unencMessage, this.transientSecretKeys) : signedOutgoingDataWithRawKey(this.transientSecretKeys[params.innerSigningKeyId], unencMessage) : unencMessage; + if (opType === SPMessage.OP_ACTION_ENCRYPTED && !params.encryptionKeyId) { + throw new Error("OP_ACTION_ENCRYPTED requires an encryption key ID be given"); + } + if (params.encryptionKey) { + if (params.encryptionKeyId !== keyId(params.encryptionKey)) { + throw new Error("OP_ACTION_ENCRYPTED raw encryption key does not match encryptionKeyId"); + } + } + const payload = opType === SPMessage.OP_ACTION_UNENCRYPTED ? signedMessage : params.encryptionKey ? encryptedOutgoingDataWithRawKey(params.encryptionKey, signedMessage) : encryptedOutgoingData(contractID, params.encryptionKeyId, signedMessage); + let message = SPMessage.createV1_0({ + contractID, + op: [ + opType, + signedOutgoingData(contractID, params.signingKeyId, payload, this.transientSecretKeys) + ], + manifest: manifestHash + }); + if (!atomic) { + message = await esm_default("chelonia/private/out/publishEvent", message, publishOptions, hooks); + } + return message; +} +function gettersProxy(state, getters) { + const proxyGetters = new Proxy({}, { + get(_target, prop) { + return getters[prop](state, proxyGetters); + } + }); + return { getters: proxyGetters }; +} +esm_default("sbp/domains/lock", ["chelonia"]); +init_db(); +init_db(); +init_functions(); +init_esm(); +var import_npm_lru_cache = __toESM(require_lru_cache()); +init_errors3(); +var BackendErrorNotFound = ChelErrorGenerator("BackendErrorNotFound"); +var BackendErrorGone = ChelErrorGenerator("BackendErrorGone"); +var BackendErrorBadData = ChelErrorGenerator("BackendErrorBadData"); +var BackendErrorConflict = ChelErrorGenerator("BackendErrorConflict"); +init_esm(); +var import_npm_nconf = __toESM(require_nconf()); +var vapidPublicKey; +var vapidPrivateKey; +var vapid; +var initVapid = async () => { + const vapidEmail = import_npm_nconf.default.get("server:vapid:email"); + if (!vapidEmail) { + console.warn('Missing VAPID identification. Please set `server:vapid:email` to a value like "some@domain.example".'); + } + vapid = { VAPID_EMAIL: vapidEmail?.replace(/^mailto:/i, "") || "test@example.com" }; + const vapidKeyPair = await esm_default("chelonia.db/get", "_private_immutable_vapid_key").then(async (vapidKeyPair2) => { + if (!vapidKeyPair2) { + console.info("Generating new VAPID keypair..."); + const keyPair = await crypto.subtle.generateKey( + { + name: "ECDSA", + namedCurve: "P-256" + // Use P-256 curve + }, + true, + // Whether the key is extractable + ["sign", "verify"] + // Usages + ); + const serializedKeyPair2 = await Promise.all([ + crypto.subtle.exportKey("jwk", keyPair.privateKey), + crypto.subtle.exportKey("raw", keyPair.publicKey).then( + (key) => Buffer7.from(key).toString("base64url") + ) + ]); + return esm_default("chelonia.db/set", "_private_immutable_vapid_key", JSON.stringify(serializedKeyPair2)).then(() => { + console.info("Successfully saved newly generated VAPID keys"); + return [keyPair.privateKey, serializedKeyPair2[1]]; + }); + } + const serializedKeyPair = JSON.parse(vapidKeyPair2); + return [ + await crypto.subtle.importKey( + "jwk", + serializedKeyPair[0], + { name: "ECDSA", namedCurve: "P-256" }, + false, + ["sign"] + ), + serializedKeyPair[1] + ]; + }); + vapidPrivateKey = vapidKeyPair[0]; + vapidPublicKey = vapidKeyPair[1]; +}; +var generateJwt = async (endpoint) => { + const now = Date.now() / 1e3 | 0; + const audience = endpoint.origin; + const header = Buffer7.from(JSON.stringify( + Object.fromEntries([["typ", "JWT"], ["alg", "ES256"]]) + )).toString("base64url"); + const body = Buffer7.from(JSON.stringify( + // We're expecting to use the JWT immediately. We set a 10-minute window + // for using the JWT (5 minutes into the past, 5 minutes into the future) + // to account for potential network delays and clock drift. + Object.fromEntries([ + // token audience + ["aud", audience], + // 'expiry' / 'not after' value for the token + ["exp", now + 300], + // (optional) issuance time for the token + ["iat", now], + // 'not before' value for the JWT + ["nbf", now - 300], + // URI used for identifying ourselves. This can be used by the push + // provider to get in touch in case of issues. + ["sub", `mailto:${vapid.VAPID_EMAIL}`] + ]) + )).toString("base64url"); + const signature = Buffer7.from( + await crypto.subtle.sign( + { name: "ECDSA", hash: "SHA-256" }, + vapidPrivateKey, + Buffer7.from([header, body].join(".")) + ) + ).toString("base64url"); + return [header, body, signature].join("."); +}; +var getVapidPublicKey = () => vapidPublicKey; +var vapidAuthorization = async (endpoint) => { + const jwt = await generateJwt(endpoint); + return `vapid t=${jwt}, k=${vapidPublicKey}`; +}; +var import_scrypt_async2 = __toESM(require_scrypt_async(), 1); +var import_tweetnacl2 = __toESM(require_nacl_fast(), 1); +var AUTHSALT = "AUTHSALT"; +var CONTRACTSALT = "CONTRACTSALT"; +var CS = "CS"; +var SU = "SU"; +var SALT_LENGTH_IN_OCTETS = 24; +var base64ToBase64url = (s) => s.replace(/\//g, "_").replace(/\+/g, "-").replace(/=*$/, ""); +var base64urlToBase64 = (s) => s.replace(/_/g, "/").replace(/-/g, "+") + "=".repeat((4 - s.length % 4) % 4); +var hashStringArray = (...args) => { + return import_tweetnacl2.default.hash(Buffer8.concat(args.map((s) => import_tweetnacl2.default.hash(Buffer8.from(s))))); +}; +var hashRawStringArray = (...args) => { + return import_tweetnacl2.default.hash(Buffer8.concat(args.map((s) => Buffer8.from(s)))); +}; +var randomNonce = () => { + return base64ToBase64url(Buffer8.from(import_tweetnacl2.default.randomBytes(12)).toString("base64")); +}; +var hash2 = (v2) => { + return base64ToBase64url(Buffer8.from(import_tweetnacl2.default.hash(Buffer8.from(v2))).toString("base64")); +}; +var computeCAndHc = (r, s, h2) => { + const \u0127 = hashStringArray(r, s); + const c = hashStringArray(h2, \u0127); + const hc = import_tweetnacl2.default.hash(c); + return [c, hc]; +}; +var encryptContractSalt = (c, contractSalt) => { + const encryptionKey = hashRawStringArray(CS, c).slice(0, import_tweetnacl2.default.secretbox.keyLength); + const nonce = import_tweetnacl2.default.randomBytes(import_tweetnacl2.default.secretbox.nonceLength); + const encryptedContractSalt = import_tweetnacl2.default.secretbox(Buffer8.from(contractSalt), nonce, encryptionKey); + return base64ToBase64url(Buffer8.concat([nonce, encryptedContractSalt]).toString("base64")); +}; +var encryptSaltUpdate = (secret, recordId, record2) => { + const nonce = import_tweetnacl2.default.randomBytes(import_tweetnacl2.default.secretbox.nonceLength); + const encryptionKey = hashRawStringArray(SU, secret, nonce, recordId).slice(0, import_tweetnacl2.default.secretbox.keyLength); + const encryptedRecord = import_tweetnacl2.default.secretbox(Buffer8.from(record2), nonce, encryptionKey); + return base64ToBase64url(Buffer8.concat([nonce, encryptedRecord]).toString("base64")); +}; +var decryptSaltUpdate = (secret, recordId, encryptedRecordBox) => { + const encryptedRecordBoxBuf = Buffer8.from(base64urlToBase64(encryptedRecordBox), "base64"); + const nonce = encryptedRecordBoxBuf.subarray(0, import_tweetnacl2.default.secretbox.nonceLength); + const encryptionKey = hashRawStringArray(SU, secret, nonce, recordId).slice(0, import_tweetnacl2.default.secretbox.keyLength); + const encryptedRecord = encryptedRecordBoxBuf.subarray(import_tweetnacl2.default.secretbox.nonceLength); + const decrypted = import_tweetnacl2.default.secretbox.open(encryptedRecord, nonce, encryptionKey); + if (!decrypted) + throw new Error("Failed to decrypt salt update"); + return Buffer8.from(decrypted).toString(); +}; +var boxKeyPair = () => { + return import_tweetnacl2.default.box.keyPair(); +}; +var saltAgreement = (publicKey, secretKey) => { + const publicKeyBuf = Buffer8.from(base64urlToBase64(publicKey), "base64"); + const dhKey = import_tweetnacl2.default.box.before(publicKeyBuf, secretKey); + if (!publicKeyBuf || publicKeyBuf.byteLength !== import_tweetnacl2.default.box.publicKeyLength) { + return false; + } + const authSalt = Buffer8.from(hashStringArray(AUTHSALT, dhKey)).subarray(0, SALT_LENGTH_IN_OCTETS).toString("base64"); + const contractSalt = Buffer8.from(hashStringArray(CONTRACTSALT, dhKey)).subarray(0, SALT_LENGTH_IN_OCTETS).toString("base64"); + return [authSalt, contractSalt]; +}; +var parseRegisterSalt = (publicKey, secretKey, encryptedHashedPassword) => { + const saltAgreementRes = saltAgreement(publicKey, secretKey); + if (!saltAgreementRes) { + return false; + } + const [authSalt, contractSalt] = saltAgreementRes; + const encryptionKey = import_tweetnacl2.default.hash(Buffer8.from(authSalt + contractSalt)).slice(0, import_tweetnacl2.default.secretbox.keyLength); + const encryptedHashedPasswordBuf = Buffer8.from(base64urlToBase64(encryptedHashedPassword), "base64"); + const hashedPasswordBuf = import_tweetnacl2.default.secretbox.open(encryptedHashedPasswordBuf.subarray(import_tweetnacl2.default.box.nonceLength), encryptedHashedPasswordBuf.subarray(0, import_tweetnacl2.default.box.nonceLength), encryptionKey); + if (!hashedPasswordBuf) { + return false; + } + return [authSalt, contractSalt, hashedPasswordBuf, encryptionKey]; +}; +init_esm(); +var import_npm_tweetnacl = __toESM(require_nacl_fast()); +var nacl3 = import_npm_tweetnacl.default; +var recordSecret; +var challengeSecret; +var registrationSecret; +var hashUpdateSecret; +var initZkpp = async () => { + const IKM = await esm_default("chelonia.db/get", "_private_immutable_zkpp_ikm").then((IKM2) => { + if (!IKM2) { + const secret = randomBytes2(33).toString("base64"); + return esm_default("chelonia.db/set", "_private_immutable_zkpp_ikm", secret).then(() => { + return secret; + }); + } + return IKM2; + }); + recordSecret = Buffer9.from(hashStringArray("private/recordSecret", IKM)).toString("base64"); + challengeSecret = Buffer9.from(hashStringArray("private/challengeSecret", IKM)).toString("base64"); + registrationSecret = Buffer9.from(hashStringArray("private/registrationSecret", IKM)).toString("base64"); + hashUpdateSecret = Buffer9.from(hashStringArray("private/hashUpdateSecret", IKM)).toString("base64"); +}; +var maxAge = 30; +var computeZkppSaltRecordId = async (contractID) => { + const recordId = `_private_rid_${contractID}`; + const record2 = await esm_default("chelonia.db/get", recordId); + if (!record2) { + return null; + } + const recordBuf = Buffer9.concat([Buffer9.from(contractID), Buffer9.from(record2)]); + return hash2(recordBuf); +}; +var getZkppSaltRecord = async (contractID) => { + const recordId = `_private_rid_${contractID}`; + const record2 = await esm_default("chelonia.db/get", recordId); + if (record2) { + const encryptionKey = hashStringArray("REK", contractID, recordSecret).slice(0, nacl3.secretbox.keyLength); + const recordBuf = Buffer9.from(base64urlToBase64(record2), "base64"); + const nonce = recordBuf.slice(0, nacl3.secretbox.nonceLength); + const recordCiphertext = recordBuf.slice(nacl3.secretbox.nonceLength); + const recordPlaintext = nacl3.secretbox.open(recordCiphertext, nonce, encryptionKey); + if (!recordPlaintext) { + return null; + } + const recordString = Buffer9.from(recordPlaintext).toString("utf-8"); + try { + const recordObj = JSON.parse(recordString); + if (!Array.isArray(recordObj) || recordObj.length !== 3 && recordObj.length !== 4 || recordObj.slice(0, 3).some((r) => !r || typeof r !== "string") || recordObj[3] != null && typeof recordObj[3] !== "string") { + console.error("Error validating encrypted JSON object " + recordId); + return null; + } + const [hashedPassword, authSalt, contractSalt, cid] = recordObj; + return { + hashedPassword, + authSalt, + contractSalt, + cid + }; + } catch { + console.error("Error parsing encrypted JSON object " + recordId); + } + } + return null; +}; +var setZkppSaltRecord = async (contractID, hashedPassword, authSalt, contractSalt, cid) => { + const recordId = `_private_rid_${contractID}`; + const encryptionKey = hashStringArray("REK", contractID, recordSecret).slice(0, nacl3.secretbox.keyLength); + const nonce = nacl3.randomBytes(nacl3.secretbox.nonceLength); + const recordPlaintext = JSON.stringify([hashedPassword, authSalt, contractSalt, cid]); + const recordCiphertext = nacl3.secretbox(Buffer9.from(recordPlaintext), nonce, encryptionKey); + const recordBuf = Buffer9.concat([nonce, recordCiphertext]); + const record2 = base64ToBase64url(recordBuf.toString("base64")); + await esm_default("chelonia.db/set", recordId, record2); +}; +var getChallenge = async (contract, b) => { + const record2 = await getZkppSaltRecord(contract); + if (!record2) { + console.debug("getChallenge: Error obtaining ZKPP salt record for contract ID " + contract); + return false; + } + const { authSalt } = record2; + const s = randomNonce(); + const now = (Date.now() / 1e3 | 0).toString(16); + const sig = [now, base64ToBase64url(Buffer9.from(hashStringArray(contract, b, s, now, challengeSecret)).toString("base64"))].join(","); + return { + authSalt, + s, + sig + }; +}; +var verifyChallenge = (contractID, r, s, userSig) => { + if (!/^[a-fA-F0-9]{1,11},[a-zA-Z0-9_-]{86}(?:==)?$/.test(userSig)) { + console.info(`wrong signature format for challenge for contract: ${contractID}`); + return false; + } + const [then, mac] = userSig.split(","); + const now = Date.now() / 1e3 | 0; + const iThen = Number.parseInt(then, 16); + if (!(iThen <= now) || !(iThen >= now - maxAge)) { + return false; + } + const b = hash2(r); + const sig = hashStringArray(contractID, b, s, then, challengeSecret); + const macBuf = Buffer9.from(base64urlToBase64(mac), "base64"); + return sig.byteLength === macBuf.byteLength && timingSafeEqual(sig, macBuf); +}; +var registrationKey = (provisionalId, b) => { + const encryptionKey = hashStringArray("REG", provisionalId, registrationSecret).slice(0, nacl3.secretbox.keyLength); + const nonce = nacl3.randomBytes(nacl3.secretbox.nonceLength); + const keyPair = boxKeyPair(); + const s = base64ToBase64url(Buffer9.concat([nonce, nacl3.secretbox(keyPair.secretKey, nonce, encryptionKey)]).toString("base64")); + const now = (Date.now() / 1e3 | 0).toString(16); + const sig = [now, base64ToBase64url(Buffer9.from(hashStringArray(provisionalId, b, s, now, challengeSecret)).toString("base64"))].join(","); + return { + s, + p: base64ToBase64url(Buffer9.from(keyPair.publicKey).toString("base64")), + sig + }; +}; +var register = (provisionalId, clientPublicKey, encryptedSecretKey, userSig, encryptedHashedPassword) => { + if (!verifyChallenge(provisionalId, clientPublicKey, encryptedSecretKey, userSig)) { + console.warn("register: Error validating challenge: " + JSON.stringify({ contract: provisionalId, clientPublicKey, userSig })); + throw new Error("register: Invalid challenge"); + } + const encryptedSecretKeyBuf = Buffer9.from(base64urlToBase64(encryptedSecretKey), "base64"); + const encryptionKey = hashStringArray("REG", provisionalId, registrationSecret).slice(0, nacl3.secretbox.keyLength); + const secretKeyBuf = nacl3.secretbox.open(encryptedSecretKeyBuf.slice(nacl3.secretbox.nonceLength), encryptedSecretKeyBuf.slice(0, nacl3.secretbox.nonceLength), encryptionKey); + if (!secretKeyBuf) { + console.warn(`register: Error decrypting arguments for contract ID ${provisionalId} (${JSON.stringify({ clientPublicKey, userSig })})`); + return false; + } + const parseRegisterSaltRes = parseRegisterSalt(clientPublicKey, secretKeyBuf, encryptedHashedPassword); + if (!parseRegisterSaltRes) { + console.warn(`register: Error parsing registration salt for contract ID ${provisionalId} (${JSON.stringify({ clientPublicKey, userSig })})`); + return false; + } + const [authSalt, contractSalt, hashedPasswordBuf, sharedEncryptionKey] = parseRegisterSaltRes; + const token = encryptSaltUpdate( + hashUpdateSecret, + provisionalId, + JSON.stringify([Date.now(), Buffer9.from(hashedPasswordBuf).toString(), authSalt, contractSalt]) + ); + return encryptContractSalt(sharedEncryptionKey, token); +}; +var contractSaltVerifyC = (h2, r, s, userHc) => { + const [c, hc] = computeCAndHc(r, s, h2); + const userHcBuf = Buffer9.from(base64urlToBase64(userHc), "base64"); + if (hc.byteLength === userHcBuf.byteLength && timingSafeEqual(hc, userHcBuf)) { + return c; + } + return false; +}; +var getContractSalt = async (contract, r, s, sig, hc) => { + if (!verifyChallenge(contract, r, s, sig)) { + console.debug("getContractSalt: Error validating challenge: " + JSON.stringify({ contract, r, s, sig })); + throw new Error("getContractSalt: Bad challenge"); + } + const record2 = await getZkppSaltRecord(contract); + if (!record2) { + console.error("getContractSalt: Error obtaining ZKPP salt record for contract ID " + contract); + return false; + } + const { hashedPassword, contractSalt, cid } = record2; + const c = contractSaltVerifyC(hashedPassword, r, s, hc); + if (!c) { + console.error(`getContractSalt: Error verifying challenge for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); + throw new Error("getContractSalt: Bad challenge"); + } + return encryptContractSalt(c, JSON.stringify([contractSalt, cid])); +}; +var updateContractSalt = async (contract, r, s, sig, hc, encryptedArgs) => { + if (!verifyChallenge(contract, r, s, sig)) { + console.warn("update: Error validating challenge: " + JSON.stringify({ contract, r, s, sig })); + throw new Error("update: Bad challenge"); + } + const record2 = await getZkppSaltRecord(contract); + if (!record2) { + console.error("update: Error obtaining ZKPP salt record for contract ID " + contract); + return false; + } + const { hashedPassword, contractSalt: oldContractSalt } = record2; + const c = contractSaltVerifyC(hashedPassword, r, s, hc); + if (!c) { + console.error(`update: Error verifying challenge for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); + throw new Error("update: Bad challenge"); + } + const encryptionKey = hashRawStringArray(SU, c).slice(0, nacl3.secretbox.keyLength); + const encryptedArgsBuf = Buffer9.from(base64urlToBase64(encryptedArgs), "base64"); + const nonce = encryptedArgsBuf.slice(0, nacl3.secretbox.nonceLength); + const encryptedArgsCiphertext = encryptedArgsBuf.slice(nacl3.secretbox.nonceLength); + const args = nacl3.secretbox.open(encryptedArgsCiphertext, nonce, encryptionKey); + if (!args) { + console.error(`update: Error decrypting arguments for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); + return false; + } + try { + const hashedPassword2 = Buffer9.from(args).toString(); + const recordId = await computeZkppSaltRecordId(contract); + if (!recordId) { + console.error(`update: Error obtaining record ID for contract ID ${contract}`); + return false; + } + const authSalt = Buffer9.from(hashStringArray(AUTHSALT, c)).slice(0, SALT_LENGTH_IN_OCTETS).toString("base64"); + const contractSalt = Buffer9.from(hashStringArray(CONTRACTSALT, c)).slice(0, SALT_LENGTH_IN_OCTETS).toString("base64"); + const token = encryptSaltUpdate( + hashUpdateSecret, + recordId, + JSON.stringify([Date.now(), hashedPassword2, authSalt, contractSalt]) + ); + return encryptContractSalt(c, JSON.stringify([oldContractSalt, token])); + } catch { + console.error(`update: Error parsing encrypted arguments for contract ID ${contract} (${JSON.stringify({ r, s, hc })})`); + } + return false; +}; +var redeemSaltRegistrationToken = async (provisoryRegistrationKey, contract, token) => { + const decryptedToken = decryptSaltUpdate( + hashUpdateSecret, + provisoryRegistrationKey, + token + ); + const [timestamp, hashedPassword, authSalt, contractSalt] = JSON.parse(decryptedToken); + if (timestamp < Date.now() - 18e4) { + throw new Error("ZKPP token expired"); + } + await setZkppSaltRecord(contract, hashedPassword, authSalt, contractSalt); +}; +var redeemSaltUpdateToken = async (contract, token) => { + const recordId = await computeZkppSaltRecordId(contract); + if (!recordId) { + throw new Error("Record ID not found"); + } + const decryptedToken = decryptSaltUpdate( + hashUpdateSecret, + recordId, + token + ); + const [timestamp, hashedPassword, authSalt, contractSalt] = JSON.parse(decryptedToken); + if (timestamp < Date.now() - 18e4) { + throw new Error("ZKPP token expired"); + } + return (cid) => { + return setZkppSaltRecord(contract, hashedPassword, authSalt, contractSalt, cid); + }; +}; +var import_npm_nconf2 = __toESM(require_nconf()); +init_esm(); +var KEYOP_SEGMENT_LENGTH = 1e4; +var updateSize = async (resourceID, sizeKey, size, skipIfDeleted) => { + if (!Number.isSafeInteger(size)) { + throw new TypeError(`Invalid given size ${size} for ${resourceID}`); + } + await esm_default("okTurtles.eventQueue/queueEvent", sizeKey, async () => { + const storedSize = await esm_default("chelonia.db/get", sizeKey, { bypassCache: true }); + if (skipIfDeleted && storedSize == null) return; + const existingSize = parseInt(storedSize ?? "0", 10); + if (!(existingSize >= 0)) { + throw new TypeError(`Invalid stored size ${existingSize} for ${resourceID}`); + } + const updatedSize = existingSize + size; + if (!(updatedSize >= 0)) { + throw new TypeError(`Invalid stored updated size ${updatedSize} for ${resourceID}`); + } + await esm_default("chelonia.db/set", sizeKey, updatedSize.toString(10)); + }); +}; +function namespaceKey(name) { + return "name=" + name; +} +var appendToIndexFactory = (key) => { + return (value) => { + return esm_default("okTurtles.eventQueue/queueEvent", key, async () => { + const currentIndex = await esm_default("chelonia.db/get", key, { bypassCache: true }); + if (currentIndex) { + if ( + // Check if the value is at the end + currentIndex.endsWith("\0" + value) || // Check if the value is at the start + currentIndex.startsWith(value + "\0") || // Check if the current index is exactly the value + currentIndex === value || // Check if the value is in the middle + currentIndex.includes("\0" + value + "\0") + ) { + return; + } + await esm_default("chelonia.db/set", key, `${currentIndex}\0${value}`); + return; + } + await esm_default("chelonia.db/set", key, value); + }); + }; +}; +var appendToNamesIndex = appendToIndexFactory("_private_names_index"); +var removeFromIndexFactory = (key) => { + return (values) => { + return esm_default("okTurtles.eventQueue/queueEvent", key, async () => { + let existingEntries = await esm_default("chelonia.db/get", key, { bypassCache: true }); + if (!existingEntries) return; + if (!Array.isArray(values)) { + values = [values]; + } + for (const value of values) { + if (existingEntries.endsWith("\0" + value)) { + existingEntries = existingEntries.slice(0, -value.length - 1); + continue; + } + if (existingEntries.startsWith(value + "\0")) { + existingEntries = existingEntries.slice(value.length + 1); + continue; + } + if (existingEntries === value) { + existingEntries = void 0; + break; + } + const entryIndex = existingEntries.indexOf("\0" + value + "\0"); + if (entryIndex === -1) continue; + existingEntries = existingEntries.slice(0, entryIndex) + existingEntries.slice(entryIndex + value.length + 1); + } + if (existingEntries) { + await esm_default("chelonia.db/set", key, existingEntries); + } else { + await esm_default("chelonia.db/delete", key); + } + }); + }; +}; +var lookupUltimateOwner = async (resourceID) => { + let ownerID = resourceID; + for (let depth = 128; depth >= 0; depth--) { + const newOwnerID = await esm_default("chelonia.db/get", `_private_owner_${ownerID}`, { bypassCache: true }); + if (!newOwnerID) break; + if (!depth) { + throw new Error("Exceeded max depth looking up owner for " + resourceID); + } + ownerID = newOwnerID; + } + return ownerID; +}; +var globImport_database_ts2 = __glob({ + "./database-fs.ts": () => Promise.resolve().then(() => (init_database_fs(), database_fs_exports)), + "./database-redis.ts": () => Promise.resolve().then(() => (init_database_redis(), database_redis_exports)), + "./database-router.test.ts": () => Promise.resolve().then(() => (init_database_router_test(), database_router_test_exports)), + "./database-router.ts": () => Promise.resolve().then(() => (init_database_router(), database_router_exports)), + "./database-sqlite.ts": () => Promise.resolve().then(() => (init_database_sqlite(), database_sqlite_exports)) +}); +var production = process2.env.NODE_ENV === "production"; +var currentBackend = null; +var currentCache = null; +var baseSelectorsInstalled = false; +function installBaseSelectorsOnce() { + if (baseSelectorsInstalled) return; + baseSelectorsInstalled = true; + esm_default("sbp/selectors/register", { + "backend/db/streamEntriesAfter": async function(contractID, height, requestedLimit, options2 = {}) { + const batchMaxSize = import_npm_nconf2.default.get("server:maxEventsBatchSize") ?? 500; + const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize); + const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); + if (latestHEADinfo === "") { + throw new BackendErrorGone(`contractID ${contractID} has been deleted!`); + } + if (!latestHEADinfo) { + throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`); + } + let counter = 0; + let currentHeight = height; + let currentHash, serverMeta; + let prefix = ""; + const nextKeyOp = /* @__PURE__ */ (() => { + let index; + return async () => { + if (!index) { + index = (await esm_default("chelonia.db/get", `_private_keyop_idx_${contractID}_${currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH}`))?.split("\0"); + } + const value = index?.find((h2, i2) => { + if (Number(h2) >= currentHeight) { + index = index.slice(i2 + 1); + return true; + } else { + return false; + } + }); + if (value != null) { + const newHeight = Number(value); + currentHeight = newHeight; + } else { + currentHeight = currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH + KEYOP_SEGMENT_LENGTH; + index = void 0; + if (currentHeight > latestHEADinfo.height) { + return false; + } else { + return null; + } + } + return true; + }; + })(); + const fetchMeta = async () => { + if (currentHeight > latestHEADinfo.height) { + return false; + } + const meta = await esm_default("chelonia/db/getEntryMeta", contractID, currentHeight); + if (!meta) { + return false; + } + const { hash: newCurrentHash, ...newServerMeta } = meta; + currentHash = newCurrentHash; + serverMeta = newServerMeta; + return true; + }; + const stream = Readable.from(async function* () { + yield "["; + await fetchMeta(); + while (serverMeta && counter < limit) { + try { + const entry = await esm_default("chelonia/db/getEntry", currentHash); + if (!entry) break; + const currentPrefix = prefix; + prefix = ","; + counter++; + yield `${currentPrefix}"${strToB64( + JSON.stringify({ serverMeta, message: entry.serialize() }) + )}"`; + currentHeight++; + currentHash = void 0; + serverMeta = void 0; + if (options2.keyOps) { + while (await nextKeyOp() === null) ; + } + await fetchMeta(); + } catch (e2) { + console.error(e2, "[backend] streamEntriesAfter: read()"); + break; + } + } + yield "]"; + }(), { encoding: "utf-8", objectMode: false }); + stream.headers = { + "shelter-headinfo-head": latestHEADinfo.HEAD, + "shelter-headinfo-height": latestHEADinfo.height + }; + return stream; + }, + // ======================= + // wrapper methods to add / lookup names + // ======================= + "backend/db/registerName": async function(name, value) { + const exists = await esm_default("backend/db/lookupName", name); + if (exists) { + throw new BackendErrorConflict("exists"); + } + await esm_default("chelonia.db/set", namespaceKey(name), value); + await esm_default("chelonia.db/set", `_private_cid2name_${value}`, name); + await appendToNamesIndex(name); + return { name, value }; + }, + "backend/db/lookupName": async function(name) { + const value = await esm_default("chelonia.db/get", namespaceKey(name)); + return value; + } + }); +} +var initedDB = false; +var initDB = async ({ skipDbPreloading } = {}) => { + installBaseSelectorsOnce(); + if (!initedDB) { + const backend = import_npm_nconf2.default.get("database:backend"); + const persistence = backend || (production ? "fs" : void 0); + const options2 = import_npm_nconf2.default.get("database:backendOptions"); + const ARCHIVE_MODE = import_npm_nconf2.default.get("server:archiveMode"); + if (persistence && persistence !== "mem") { + const Ctor = (await globImport_database_ts2(`./database-${persistence}.ts`)).default; + const instance = new Ctor(options2[persistence]); + await instance.init(); + currentBackend = instance; + currentCache = new import_npm_lru_cache.default({ + max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 + }); + const prefixes = Object.keys(prefixHandlers); + esm_default("sbp/selectors/overwrite", { + "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { + const cache2 = currentCache; + if (!bypassCache) { + const lookupValue = cache2.get(prefixableKey); + if (lookupValue !== void 0) { + return lookupValue; + } + } + const [prefix, key] = parsePrefixableKey(prefixableKey); + let value = await currentBackend.readData(key); + if (value === void 0) { + return; + } + value = prefixHandlers[prefix](value); + cache2.set(prefixableKey, value); + return value; + }, + "chelonia.db/set": async function(key, value) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + const existingValue = await currentBackend.readData(key); + if (existingValue !== void 0) { + throw new Error("Cannot set already set immutable key"); + } + } + await currentBackend.writeData(key, value); + const cache2 = currentCache; + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/delete": async function(key) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + throw new Error("Cannot delete immutable key"); + } + await currentBackend.deleteData(key); + const cache2 = currentCache; + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/iterKeys": () => { + return currentBackend.iterKeys(); + }, + "chelonia.db/keyCount": () => { + return currentBackend.keyCount(); + } + }); + } + initedDB = true; + } + if (skipDbPreloading || initedDB === "preloaded") return; + await Promise.all([initVapid(), initZkpp()]); + initedDB = "preloaded"; +}; +async function closeDB() { + if (currentBackend) { + try { + await currentBackend.close(); + } catch (e2) { + console.error(e2, "Error closing DB"); + } + currentBackend = null; + } + currentCache?.clear(); + currentCache = null; + initedDB = false; +} +init_functions(); +async function createEntryFromFile(filepath, multicode) { + const buffer = await Deno.readFile(filepath); + const key = createCID(buffer, multicode); + return [key, buffer]; +} +function exit(x3, internal = false) { + const msg = x3 instanceof Error ? x3.message : String(x3); + if (internal) throw new Error(msg); + console.error("[chel]", red("Error:"), msg); + Deno.exit(1); +} +function isValidKey(key) { + return !/[\x00-\x1f\x7f\t\\/]/.test(key); +} +async function readRemoteData(src2, key) { + const buffer = await fetch(`${src2}/file/${key}`).then(async (r) => r.ok ? await r.arrayBuffer() : await Promise.reject(new Error(`failed network request to ${src2}: ${r.status} - ${r.statusText}`))); + return new Uint8Array(buffer); +} +async function revokeNet() { + await Deno.permissions.revoke({ name: "net" }); +} +var readJsonFile = async (file) => { + const contents = await Deno.readTextFile(resolve8(String(file))); + return JSON.parse(contents); +}; +var findManifestFiles = async (path8) => { + const visited = /* @__PURE__ */ new Set(); + const internal = async (path9) => { + if (visited.has(path9)) { + return /* @__PURE__ */ new Set(); + } + visited.add(path9); + const entries = Deno.readDir(path9); + const manifests = /* @__PURE__ */ new Set(); + for await (const entry of entries) { + const realPath2 = await Deno.realPath(join32(path9, entry.name)); + const info = await Deno.lstat(realPath2); + if (info.isDirectory) { + const subitems = await internal(realPath2); + for (const item of subitems) { + manifests.add(item); + } + } else if (entry.name.toLowerCase().endsWith(".manifest.json")) { + manifests.add(join32(path9, entry.name)); + } + } + return manifests; + }; + const realPath = await Deno.realPath(path8); + return internal(realPath); +}; +async function upload(args, internal = false) { + const { url: url2, files } = args; + if (!url2) { + await initDB({ skipDbPreloading: true }); + } + const uploaded = []; + const uploaderFn = url2 ? uploadEntryToURL : uploadEntryToDB; + for (const filepath_ of files) { + let type = multicodes.RAW; + let filepath = filepath_; + if (internal) { + if (filepath_[1] !== "|") throw new Error("Invalid path format"); + switch (filepath_[0]) { + case "r": + break; + case "m": + type = multicodes.SHELTER_CONTRACT_MANIFEST; + break; + case "t": + type = multicodes.SHELTER_CONTRACT_TEXT; + break; + default: + throw new Error("Unknown file type: " + filepath_[0]); + } + filepath = filepath_.slice(2); + } + const entry = await createEntryFromFile(filepath, type); + const destination = await uploaderFn(entry, url2); + if (!internal) { + console.log(green("uploaded:"), destination); + } else { + console.log(green(`${relative7(".", filepath)}:`), destination); + } + uploaded.push([filepath, destination]); + } + return uploaded; +} +async function uploadEntryToURL([cid, buffer], url2) { + const form = new FormData(); + form.append("hash", cid); + form.append("data", new Blob([buffer])); + return await fetch(`${url2}/dev-file`, { method: "POST", body: form }).then(handleFetchResult2("text")).then((r) => { + if (r !== `/file/${cid}`) { + throw new Error(`server returned bad URL: ${r}`); + } + return `${url2}${r}`; + }); +} +function uploadEntryToDB([cid, buffer]) { + return esm_default("chelonia.db/set", cid, Buffer12.from(buffer)).then(() => cid); +} +function handleFetchResult2(type) { + return async function(r) { + if (!r.ok) throw new Error(`${r.status}: ${r.statusText}`); + return await r[type](); + }; +} +var module2 = { + builder: (yargs) => { + return yargs.option("url", { + describe: "URL of a remote server", + requiresArg: true, + string: true + }).positional("files", { + describe: "Files to upload", + demandOption: true, + array: true, + type: "string" + }); + }, + command: "upload ", + describe: "Requires read and write access to the destination.", + postHandler: (argv) => { + return void upload(argv); + } +}; +var CONTRACT_TEXT_PREFIX = "t|"; +var CONTRACT_MANIFEST_PREFIX = "m|"; +var ContractBodySchema = object({ + contract: object({ file: string2() }), + contractSlim: object({ file: string2() }).optional() +}); +async function deploy(args) { + const { manifests } = args; + const toUpload = []; + const manifestSet = /* @__PURE__ */ new Set(); + for (const manifestPath of manifests) { + try { + const realPath = await Deno.realPath(manifestPath); + const info = await Deno.lstat(realPath); + if (info.isDirectory) { + const items = await findManifestFiles(realPath); + for (const item of items) { + manifestSet.add(item); + } + } else { + manifestSet.add(realPath); + } + } catch { + console.warn(`Skipping invalid path: ${manifestPath}`); + continue; + } + } + for (const manifestPath of manifestSet) { + const manifestText = await Deno.readTextFile(manifestPath); + const json = JSON.parse(manifestText); + const body = ContractBodySchema.parse(JSON.parse(json.body)); + const dirname82 = dirname8(manifestPath); + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contract.file)); + if (body.contractSlim) { + toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contractSlim.file)); + } + toUpload.push(CONTRACT_MANIFEST_PREFIX + manifestPath); + } + await upload({ ...args, files: toUpload }, true); +} +var module3 = { + builder: (yargs) => { + return yargs.option("url", { + describe: "URL of a remote server", + requiresArg: true, + string: true + }).positional("manifests", { + describe: "Manifest files to deploy (if a directory is passed in, all manifests in that directory, and sub-directories, will be added)", + demandOption: true, + array: true, + type: "string" + }); + }, + command: "deploy ", + describe: "", + postHandler: (argv) => { + return deploy(argv); + } +}; +init_esm(); +async function eventsAfter2({ limit, url: url2, contractID, height }) { + try { + let messages; + if (url2) { + messages = await getRemoteMessagesSince(url2, contractID, height, limit); + } else { + await initDB({ skipDbPreloading: true }); + messages = await getMessagesSince(contractID, height, limit); + } + console.log(JSON.stringify(messages, null, 2)); + } catch (error2) { + exit(error2); + } +} +async function getMessagesSince(contractID, sinceHeight, limit) { + const readable = await esm_default("backend/db/streamEntriesAfter", contractID, sinceHeight, limit); + return new Promise((resolve82, reject) => { + const data = []; + readable.on("readable", () => { + let chunk; + while (null !== (chunk = readable.read())) { + data.push(chunk); + } + }); + readable.on("error", reject); + readable.on("end", () => { + const events = JSON.parse(data.join("")).map((s) => { + return JSON.parse(new TextDecoder().decode(decodeBase64(s))); + }); + resolve82(events); + }); + }); +} +async function getRemoteMessagesSince(src2, contractID, sinceHeight, limit) { + const response = await fetch(`${src2}/eventsAfter/${contractID}/${sinceHeight}`); + if (!response.ok) { + const bodyText = await response.text().catch(() => "") || ""; + throw new Error(`failed network request to ${src2}: ${response.status} - ${response.statusText} - '${bodyText}'`); + } + const b64messages = await response.json(); + if (b64messages.length > limit) { + b64messages.length = limit; + } + return b64messages.map((b64str) => JSON.parse(new TextDecoder().decode(decodeBase64(b64str)))); +} +var module4 = { + builder: (yargs) => { + return yargs.option("limit", { + describe: "Limit", + default: 50, + number: true, + requiresArg: true, + coerce(v2) { + if (!Number.isSafeInteger(v2) || v2 < 0) { + throw new Error("--limit must be a valid non-negative integer"); + } + return v2; + } + }).option("url", { + describe: "URL of a remote server", + string: true + }).positional("contractID", { + describe: "Contract ID", + demandOption: true, + type: "string" + }).positional("height", { + describe: "Height", + demandOption: true, + type: "number" + }); + }, + command: "eventsAfter ", + describe: "Displays a JSON array of the first LIMIT events that happened in a given contract, since a given entry identified by its hash.\n\n- Older events are displayed first.\n- The output is parseable with tools such as 'jq'.\n- If --url is given, then its /eventsAfter REST endpoint will be called.\n", + postHandler: (argv) => { + return eventsAfter2(argv); + } +}; +init_esm(); +async function get({ key, url: url2 }) { + if (!url2) { + await initDB({ skipDbPreloading: true }); + } + try { + const data = url2 ? await readRemoteData(url2, key) : await esm_default("chelonia.db/get", key); + if (data === void 0) exit(`no entry found for ${key}`); + if (typeof data === "string") { + console.log(data); + } else { + await writeAll(Deno.stdout, data); + } + } catch (error2) { + exit(error2); + } +} +var module5 = { + builder: (yargs) => { + return yargs.option("url", { + describe: "URL of a remote server", + string: true + }).positional("key", { + describe: "Database key", + demandOption: true, + type: "string" + }); + }, + command: "get ", + describe: "Retrieves the entry associated with a given key, from a given database or server.\n\n- The output can be piped to a file, like this: chel get https://url.com mygreatlongkey > file.png", + postHandler: (argv) => { + return get(argv); + } +}; +init_functions(); +async function hash22({ filename }, multicode = multicodes.RAW, internal = false) { + const [cid] = await createEntryFromFile(filename, multicode); + if (!internal) { + console.log(`CID(${filename}):`, cid); + } + return cid; +} +var module6 = { + builder: (yargs) => { + return yargs.positional("filename", { + describe: "File name", + demandOption: true, + type: "string" + }); + }, + command: "hash ", + describe: "Computes and logs the content identifier (CID) for the given file.\n' + 'File contents will be interpreted as raw binary data, unless the file extension is '.json'.", + postHandler: (argv) => { + return void hash22(argv); + } +}; +init_esm6(); +var keygen2 = async (args) => { + await revokeNet(); + const key = keygen(EDWARDS25519SHA512BATCH); + const pubKeyData = { + version: "1.0.0", + pubkey: serializeKey(key, false) + }; + const keyData = { + ...pubKeyData, + privkey: serializeKey(key, true) + }; + const result = JSON.stringify(keyData); + const pubResult = JSON.stringify(pubKeyData); + const idx = keyId(key).slice(-12); + const outFile = args.out || `${EDWARDS25519SHA512BATCH}-${idx}.json`; + const pubOutFile = args.pubout || `${EDWARDS25519SHA512BATCH}-${idx}.pub.json`; + await Deno.writeTextFile(outFile, result); + console.log(green("wrote:"), outFile, blue("(secret)")); + await Deno.writeTextFile(pubOutFile, pubResult); + console.log(green("wrote:"), pubOutFile, blue("(public)")); +}; +var module7 = { + builder: (yargs) => { + return yargs.option("out", { + describe: "File name for the secret key", + requiresArg: true, + string: true + }).option("pubout", { + describe: "File name for the public key", + requiresArg: true, + string: true + }); + }, + command: "keygen", + describe: "", + postHandler: (argv) => { + return keygen2(argv); + } +}; +init_esm6(); +init_functions(); +function isSigningKeyDescriptor(obj) { + return obj !== null && typeof obj === "object" && typeof obj.privkey === "string"; +} +async function manifest(args) { + await revokeNet(); + const { signingKey: keyFileRaw, contractBundle: contractFileRaw } = args; + if (typeof keyFileRaw !== "string" || typeof contractFileRaw !== "string") { + exit("Missing or invalid key or contract file"); + } + const keyFile = keyFileRaw; + const contractFile = contractFileRaw; + const parsedFilepath = parse7(contractFile); + const { name: contractFileName, base: contractBasename, dir: contractDir } = parsedFilepath; + const name = args.name || contractFileName; + const version3 = args.contractVersion || "x"; + const slim = args.slim; + const outFile = args.out || join8(contractDir, `${contractFileName}.${version3}.manifest.json`); + if (!keyFile) exit("Missing signing key file"); + const signingKeyDescriptorRaw = await readJsonFile(keyFile); + if (!isSigningKeyDescriptor(signingKeyDescriptorRaw)) { + exit("Invalid signing key file: missing or invalid privkey", true); + } + const signingKeyDescriptor = signingKeyDescriptorRaw; + const signingKey = deserializeKey(signingKeyDescriptor.privkey); + const publicKeys = Array.from(new Set( + [serializeKey(signingKey, false)].concat(...await Promise.all(args.key?.map( + async (kf) => { + if (typeof kf !== "string" && typeof kf !== "number") { + exit(`Invalid key file reference: ${String(kf)}`); + } + const descriptor = await readJsonFile(String(kf)); + const key = deserializeKey(descriptor.pubkey); + if (key.type !== EDWARDS25519SHA512BATCH) { + exit(`Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.`); + } + return serializeKey(key, false); + } + ) || [])) + )); + const body = { + name, + version: version3, + contract: { + hash: await hash22({ ...args, filename: contractFile }, multicodes.SHELTER_CONTRACT_TEXT, true), + file: contractBasename + }, + signingKeys: publicKeys + }; + if (typeof slim === "string" && slim !== "") { + body.contractSlim = { + file: basename8(slim), + hash: await hash22({ ...args, filename: slim }, multicodes.SHELTER_CONTRACT_TEXT, true) + }; + } + const serializedBody = JSON.stringify(body); + const head = { manifestVersion: "1.0.0" }; + const serializedHead = JSON.stringify(head); + const manifest2 = JSON.stringify({ + head: serializedHead, + body: serializedBody, + signature: { + keyId: keyId(signingKey), + value: sign(signingKey, serializedBody + serializedHead) + } + }); + if (args.out === "-") { + console.log(manifest2); + } else { + Deno.writeTextFileSync(outFile, manifest2); + console.log(green("wrote:"), outFile); + } +} +var module8 = { + builder: (yargs) => { + return yargs.option("key", { + coerce: (v2) => Array.isArray(v2) ? v2 : [v2], + describe: "Additional public key", + requiresArg: true, + string: true + }).alias("k", "key").option("out", { + describe: "Manifest file name", + requiresArg: true, + string: true + }).option("name", { + describe: "Contract name", + requiresArg: true, + string: true + }).alias("n", "name").option("slim", { + describe: "Slim contract bundle", + requiresArg: true, + string: true + }).alias("s", "slim").option("contract-version", { + describe: "Contract version", + requiresArg: true, + string: true + }).alias("V", "contract-version").positional("signingKey", { + describe: "Signing key file", + demandOption: true, + type: "string" + }).positional("contractBundle", { + describe: "Contract bundle", + demandOption: true, + type: "string" + }); + }, + command: "manifest [-k|--key ] [-k|--key ...] [--out ] [-s|--slim ] [-V|--contract-version ] ", + describe: "Produce a signed manifest from a contract.\nIf unspecified, is set to 'x'.", + postHandler: (argv) => { + return manifest(argv); + } +}; +init_esm(); +var import_npm_nconf3 = __toESM(require_nconf()); +var globImport_serve_database_ts = __glob({ + "./serve/database-fs.ts": () => Promise.resolve().then(() => (init_database_fs(), database_fs_exports)), + "./serve/database-redis.ts": () => Promise.resolve().then(() => (init_database_redis(), database_redis_exports)), + "./serve/database-router.test.ts": () => Promise.resolve().then(() => (init_database_router_test(), database_router_test_exports)), + "./serve/database-router.ts": () => Promise.resolve().then(() => (init_database_router(), database_router_exports)), + "./serve/database-sqlite.ts": () => Promise.resolve().then(() => (init_database_sqlite(), database_sqlite_exports)) +}); +async function migrate(args) { + const { to } = args; + if (args.fromConfig) { + const fromConfig = parse8(await readFile2(args.fromConfig, { encoding: "utf-8", flag: "r" })); + const backend = import_npm_nconf3.default.get("database:backend"); + const fromBackend = fromConfig?.database?.backend; + if (fromBackend !== backend) { + console.warn(`--from-config has backend ${fromBackend} but --from is ${backend}`); + } + const fromConfigOpts = fromConfig?.database?.backendOptions?.[backend] || {}; + import_npm_nconf3.default.set(`database:backendOptions:${backend}`, fromConfigOpts); } -}); -function extractBearer(c) { - const authorization = c.req.header("authorization"); - if (!authorization) return null; - const prefix = "bearer "; - if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; - return { token: authorization.slice(prefix.length) }; -} -function extractShelter(c) { - const authorization = c.req.header("authorization"); - if (!authorization) return null; - const prefix = "shelter "; - if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; try { - const billableContractID = verifyShelterAuthorizationHeader(authorization); - return { billableContractID }; + await initDB({ skipDbPreloading: true }); } catch (e2) { - console.warn(e2, "Shelter authorization failed"); - return null; + console.error("Error setting up database"); + exit(e2); + throw e2; } -} -function authMiddleware(strategies, mode = "required") { - const strategyList = Array.isArray(strategies) ? strategies : [strategies]; - return async (c, next) => { - for (const strategy of strategyList) { - const extractor = extractors[strategy]; - if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`); - const credentials = extractor(c); - if (credentials) { - c.set("credentials", credentials); - c.set("authStrategy", strategy); - return next(); + let backendTo; + try { + let toConfigOpts; + if (args.toConfig) { + const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); + const toBackend = toConfig?.database?.backend; + if (toBackend !== to) { + console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); } + toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; + } else { + toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; } - if (mode === "optional") { - c.set("credentials", {}); - c.set("authStrategy", ""); - return next(); - } - throw new HTTPException(401, { message: "Unauthorized" }); + const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; + backendTo = new Ctor(toConfigOpts); + await backendTo.init(); + } catch (error2) { + exit(error2); + throw error2; + } + const numKeys2 = await esm_default("chelonia.db/keyCount"); + let numMigratedKeys = 0; + let numVisitedKeys = 0; + const reportStatus = () => { + console.log(`${green("Migrated:")} ${numMigratedKeys} entries`); }; -} -var extractors; -var init_auth = __esm({ - "src/serve/auth.ts"() { - "use strict"; - init_utils(); - init_http_exception(); - extractors = { - "chel-bearer": extractBearer, - "chel-shelter": extractShelter - }; - } -}); -var validCookieNameRegEx; -var validCookieValueRegEx; -var trimCookieWhitespace; -var parse42; -var init_cookie = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/cookie.js"() { - init_url(); - validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/; - validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/; - trimCookieWhitespace = (value) => { - let start = 0; - let end = value.length; - while (start < end) { - const charCode = value.charCodeAt(start); - if (charCode !== 32 && charCode !== 9) { - break; - } - start++; - } - while (end > start) { - const charCode = value.charCodeAt(end - 1); - if (charCode !== 32 && charCode !== 9) { - break; + const checkAndExit = (() => { + let interruptCount = 0; + let shouldExit = 0; + const handleSignal = (signal, code2) => { + process3.on(signal, () => { + shouldExit = 128 + code2; + if (++interruptCount < 3) { + console.error(`Received signal ${signal} (${code2}). Finishing current operation.`); + } else { + console.error(`Received signal ${signal} (${code2}). Force quitting.`); + reportStatus(); + exit(shouldExit); } - end--; - } - return start === 0 && end === value.length ? value : value.slice(start, end); + }); }; - parse42 = (cookie, name) => { - if (name && cookie.indexOf(name) === -1) { - return {}; - } - const pairs = cookie.split(";"); - const parsedCookie = {}; - for (const pairStr of pairs) { - const valueStartPos = pairStr.indexOf("="); - if (valueStartPos === -1) { - continue; - } - const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos)); - if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) { - continue; - } - let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1)); - if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) { - cookieValue = cookieValue.slice(1, -1); - } - if (validCookieValueRegEx.test(cookieValue)) { - parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue; - if (name) { - break; - } - } + const checkAndExit2 = async () => { + if (shouldExit) { + await backendTo.close(); + reportStatus(); + exit(shouldExit); } - return parsedCookie; }; + [ + ["SIGHUP", 1], + ["SIGINT", 2], + ["SIGQUIT", 3], + ["SIGTERM", 15], + ["SIGUSR1", 10], + ["SIGUSR2", 11] + ].forEach(([signal, code2]) => handleSignal(signal, code2)); + return checkAndExit2; + })(); + let lastReportedPercentage = 0; + for await (const key of esm_default("chelonia.db/iterKeys")) { + numVisitedKeys++; + if (!isValidKey(key)) { + console.debug("Skipping invalid key", key); + continue; + } + let value; + try { + value = await esm_default("chelonia.db/get", `any:${key}`); + } catch (e2) { + reportStatus(); + console.error(`Error reading from source database key '${key}'`, e2); + await backendTo.close(); + exit(1); + throw e2; + } + await checkAndExit(); + if (value === void 0) { + console.debug("Skipping empty key", key); + continue; + } + try { + await backendTo.writeData(key, value); + } catch (e2) { + reportStatus(); + console.error(`Error writing to target database key '${key}'`, e2); + await backendTo.close(); + exit(1); + throw e2; + } + await checkAndExit(); + ++numMigratedKeys; + const percentage = Math.floor(numVisitedKeys / numKeys2 * 100); + if (percentage - lastReportedPercentage >= 10) { + lastReportedPercentage = percentage; + console.log(`Migrating... ${percentage}% done`); + } } -}); -var getCookie; -var init_cookie2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/helper/cookie/index.js"() { - init_cookie(); - getCookie = (c, key, prefix) => { - const cookie = c.req.raw.headers.get("Cookie"); - if (typeof key === "string") { - if (!cookie) { - return void 0; - } - let finalKey = key; - if (prefix === "secure") { - finalKey = "__Secure-" + key; - } else if (prefix === "host") { - finalKey = "__Host-" + key; - } - const obj2 = parse42(cookie, finalKey); - return obj2[finalKey]; + reportStatus(); + await backendTo.close(); +} +var module9 = { + builder: (yargs) => { + return yargs.option("from", { + describe: "Source backend", + demandOption: true, + requiresArg: true, + string: true + }).alias("database:backend", "from").option("from-config", { + describe: "Source backend configuration", + requiresArg: true, + string: true + }).option("to", { + describe: "Destination backend", + demandOption: true, + requiresArg: true, + string: true + }).option("to-config", { + describe: "Destination backend configuration", + requiresArg: true, + string: true + }).strict(false).strictCommands(true); + }, + command: "migrate", + describe: "Reads all key-value pairs from a given database and creates or updates another database accordingly.\n\n- The output database will be created if necessary.\n- The source database won't be modified nor deleted.\n- Invalid key-value pairs entries will be skipped.\n- Requires read and write access to the source.\n", + postHandler: (argv) => { + return migrate(argv); + } +}; +var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; +var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; +var projectRoot; +var cheloniaConfig; +function sanitizeContractName(contractName) { + return contractName.replace(RESERVED_FILE_CHARS_REPLACE, "_").replace(/\.\./g, "__"); +} +async function pin(args) { + const version3 = args["manifest-version"]; + const manifestPath = args.manifest; + projectRoot = args["dir"] || process4.cwd(); + try { + if (!manifestPath) { + await loadCheloniaConfig(); + return; + } + console.log(cyan(`\u{1F4CC} Requesting pin to version: ${version3}`)); + console.log(gray(`Manifest: ${manifestPath}`)); + await loadCheloniaConfig(); + const fullManifestPath = join62(projectRoot, manifestPath); + if (!existsSync(fullManifestPath)) { + exit(`Manifest file not found: ${manifestPath}`); + } + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + if (RESERVED_FILE_CHARS.test(manifestVersion) || manifestVersion.startsWith(".") || manifestVersion.endsWith(".")) { + exit(`Invalid manifest version: ${manifestVersion}`); + } + console.log(blue(`Contract name: ${fullContractName}`)); + console.log(blue(`Manifest version: ${manifestVersion}`)); + if (version3) { + if (version3 !== manifestVersion) { + console.error(red(`\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})`)); + console.error(yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)); + exit("Version mismatch between CLI and manifest"); } - if (!cookie) { - return {}; + console.log(green(`\u2705 Version validation passed: ${version3}`)); + } + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; + if (currentPinnedVersion === manifestVersion) { + console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); + return; + } + if (currentPinnedVersion) { + console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + } else { + console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); + } + const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); + if (existsSync(contractVersionDir)) { + if (!args.overwrite) { + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); } - const obj = parse42(cookie); - return obj; - }; - } -}); -var init_crypto = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/crypto.js"() { - } -}); -var bufferToFormData; -var init_buffer = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/utils/buffer.js"() { - init_crypto(); - bufferToFormData = (arrayBuffer, contentType) => { - const response = new Response(arrayBuffer, { - headers: { - "Content-Type": contentType - } - }); - return response.formData(); - }; - } -}); -var jsonRegex; -var multipartRegex; -var urlencodedRegex; -var validator; -var init_validator = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/validator/validator.js"() { - init_cookie2(); - init_http_exception(); - init_buffer(); - jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; - multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/; - urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; - validator = (target, validationFunc) => { - return async (c, next) => { - let value = {}; - const contentType = c.req.header("Content-Type"); - switch (target) { - case "json": - if (!contentType || !jsonRegex.test(contentType)) { - break; - } - try { - value = await c.req.json(); - } catch { - const message = "Malformed JSON in request body"; - throw new HTTPException(400, { message }); - } - break; - case "form": { - if (!contentType || !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))) { - break; - } - let formData; - if (c.req.bodyCache.formData) { - formData = await c.req.bodyCache.formData; - } else { - try { - const arrayBuffer = await c.req.arrayBuffer(); - formData = await bufferToFormData(arrayBuffer, contentType); - c.req.bodyCache.formData = formData; - } catch (e2) { - let message = "Malformed FormData request."; - message += e2 instanceof Error ? ` ${e2.message}` : ` ${String(e2)}`; - throw new HTTPException(400, { message }); - } - } - const form = /* @__PURE__ */ Object.create(null); - formData.forEach((value2, key) => { - if (key.endsWith("[]")) { - ; - (form[key] ??= []).push(value2); - } else if (Array.isArray(form[key])) { - ; - form[key].push(value2); - } else if (Object.hasOwn(form, key)) { - form[key] = [form[key], value2]; - } else { - form[key] = value2; - } - }); - value = form; - break; - } - case "query": - value = Object.fromEntries( - Object.entries(c.req.queries()).map(([k, v2]) => { - return v2.length === 1 ? [k, v2[0]] : [k, v2]; - }) - ); - break; - case "param": - value = c.req.param(); - break; - case "header": - value = c.req.header(); - break; - case "cookie": - value = getCookie(c); - break; - } - const res = await validationFunc(value, c); - if (res instanceof Response) { - return res; - } - c.req.addValidatedData(target, res); - return await next(); - }; - }; + console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); + } else { + await createVersionDirectory(contractName, manifestVersion); + } + await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); + console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); + console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); + } catch (error2) { + exit(error2); } -}); -var init_validator2 = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/validator/index.js"() { - init_validator(); +} +async function parseManifest(manifestPath) { + const manifestContent = await readFile3(manifestPath, "utf8"); + const manifest2 = JSON.parse(manifestContent); + const body = JSON.parse(manifest2.body); + const fullContractName = body.name; + const manifestVersion = body.version; + const mainFile = body.contract.file; + const slimFile = body.contractSlim?.file; + if (!fullContractName || !mainFile || !manifestVersion) { + console.error(red("\u274C Invalid manifest: missing contract name, main file, or version")); + exit("Invalid manifest: missing contract name, main file, or version"); } -}); -function zValidatorFunction(target, schema, hook, options2) { - return validator(target, async (value, c) => { - let validatorValue = value; - if (target === "header" && "_def" in schema || target === "header" && "_zod" in schema) { - const schemaKeys = Object.keys("in" in schema ? schema.in.shape : schema.shape); - const caseInsensitiveKeymap = Object.fromEntries(schemaKeys.map((key) => [key.toLowerCase(), key])); - validatorValue = Object.fromEntries(Object.entries(value).map(([key, value$1]) => [caseInsensitiveKeymap[key] || key, value$1])); + const contractName = sanitizeContractName(fullContractName); + return { + contractName, + manifestVersion, + fullContractName, + contractFiles: { + main: mainFile, + slim: slimFile } - const result = options2 && options2.validationFunction ? await options2.validationFunction(schema, validatorValue) : await schema.safeParseAsync(validatorValue); - if (hook) { - const hookResult = await hook({ - data: validatorValue, - ...result, - target - }, c); - if (hookResult) { - if (hookResult instanceof Response) return hookResult; - if ("response" in hookResult) return hookResult.response; - } + }; +} +async function createVersionDirectory(contractName, version3) { + const versionDir = join62(projectRoot, "contracts", contractName, version3); + console.log(blue(`\u{1F4C1} Creating directory: contracts/${contractName}/${version3}/`)); + await mkdir3(versionDir, { recursive: true }); +} +async function copyContractFiles(contractFiles, manifestPath, contractName, version3, args) { + const sourceDir = dirname42(join62(projectRoot, manifestPath)); + const targetDir = join62(projectRoot, "contracts", contractName, version3); + console.log(gray(`\u{1F4CB} Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ""}, manifest`)); + const mainSource = join62(sourceDir, contractFiles.main); + const mainTarget = join62(targetDir, contractFiles.main); + await copyFileIfNeeded(mainSource, mainTarget, contractFiles.main, args); + if (contractFiles.slim) { + const slimSource = join62(sourceDir, contractFiles.slim); + const slimTarget = join62(targetDir, contractFiles.slim); + try { + await copyFileIfNeeded(slimSource, slimTarget, contractFiles.slim, args); + } catch (error2) { + const errorMessage = error2 instanceof Error ? error2.message : String(error2); + console.error(yellow(`\u26A0\uFE0F Could not copy slim file: ${errorMessage}`)); } - if (!result.success) return c.json(result, 400); - return result.data; - }); + } + const manifestSource = join62(projectRoot, manifestPath); + const manifestTarget = join62(targetDir, basename42(manifestPath)); + await copyFileIfNeeded(manifestSource, manifestTarget, basename42(manifestPath), args); } -var zValidator; -var init_dist3 = __esm({ - "node_modules/.deno/@hono+zod-validator@0.7.6/node_modules/@hono/zod-validator/dist/index.js"() { - init_validator2(); - zValidator = zValidatorFunction; - } -}); -var ERROR_MESSAGE; -var BodyLimitError; -var bodyLimit; -var init_body_limit = __esm({ - "node_modules/.deno/hono@4.12.12/node_modules/hono/dist/middleware/body-limit/index.js"() { - init_http_exception(); - ERROR_MESSAGE = "Payload Too Large"; - BodyLimitError = class extends Error { - constructor(message) { - super(message); - this.name = "BodyLimitError"; - } - }; - bodyLimit = (options2) => { - const onError = options2.onError || (() => { - const res = new Response(ERROR_MESSAGE, { - status: 413 - }); - throw new HTTPException(413, { res }); - }); - const maxSize = options2.maxSize; - return async function bodyLimit2(c, next) { - if (!c.req.raw.body) { - return next(); - } - const hasTransferEncoding = c.req.raw.headers.has("transfer-encoding"); - const hasContentLength = c.req.raw.headers.has("content-length"); - if (hasTransferEncoding && hasContentLength) { - } - if (hasContentLength && !hasTransferEncoding) { - const contentLength = parseInt(c.req.raw.headers.get("content-length") || "0", 10); - return contentLength > maxSize ? onError(c) : next(); - } - let size = 0; - const rawReader = c.req.raw.body.getReader(); - const reader = new ReadableStream({ - async start(controller) { - try { - for (; ; ) { - const { done, value } = await rawReader.read(); - if (done) { - break; - } - size += value.length; - if (size > maxSize) { - controller.error(new BodyLimitError(ERROR_MESSAGE)); - break; - } - controller.enqueue(value); - } - } finally { - controller.close(); - } - } - }); - const requestInit = { body: reader, duplex: "half" }; - c.req.raw = new Request(c.req.raw, requestInit); - await next(); - if (c.error instanceof BodyLimitError) { - c.res = await onError(c); - } - }; - }; +async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { + const targetExists = existsSync(targetPath); + if (!targetExists) { + console.log(blue(`\u{1F4C4} Copying: ${fileName} (new file)`)); + await copyFile(sourcePath, targetPath); + return; } -}); -var routes_exports = {}; -__export(routes_exports, { - staticServeConfig: () => staticServeConfig -}); -function getClientIP(c) { - const headerIP = c.req.header("x-real-ip"); - if (headerIP) return headerIP; - try { - const info = getConnInfo2(c); - return info.remote.address || "unknown"; - } catch { - return "unknown"; + if (targetExists && !args.overwrite) { + console.log(yellow(`\u23ED\uFE0F Skipping: ${fileName} (already exists, use --overwrite to replace)`)); + return; } + console.log(blue(`\u{1F4C4} Copying: ${fileName} (overwriting)`)); + await copyFile(sourcePath, targetPath); } -function notFoundNoCache(c) { - return c.body(null, 404, { "Cache-Control": "no-store" }); +async function loadCheloniaConfig() { + const configPath = join62(projectRoot, "chelonia.json"); + cheloniaConfig = { contracts: {} }; + if (existsSync(configPath)) { + try { + const configContent = await readFile3(configPath, "utf8"); + cheloniaConfig = JSON.parse(configContent); + console.log(blue("\u{1F4C4} Loaded existing chelonia.json")); + } catch (error2) { + console.warn(yellow(`Warning: Could not parse chelonia.json: ${error2}`)); + } + } else { + console.log(blue("\u{1F4C4} No existing chelonia.json found")); + } + if (!cheloniaConfig.contracts) { + cheloniaConfig.contracts = {}; + } } -var import_npm_bottleneck; -var import_npm_chalk2; -var import_npm_nconf5; -var MEGABYTE; -var SECOND; -var CID_REGEX; -var KV_KEY_REGEX; -var NAME_REGEX; -var POSITIVE_INTEGER_REGEX; -var cidSchema; -var nameSchema; -var kvKeySchema; -var positiveIntegerSchema; -var cidParamSchema; -var cidHashParamSchema; -var nameParamSchema; -var kvParamSchema; -var eventsAfterParamSchema; -var zkppContractParamSchema; -var zkppAuthHashQuerySchema; -var zkppContractHashQuerySchema; -var eventHeaderSchema; -var zkppRegisterBodySchema; -var zkppUpdatePasswordBodySchema; -var FILE_UPLOAD_MAX_BYTES; -var SIGNUP_LIMIT_MIN; -var SIGNUP_LIMIT_HOUR; -var SIGNUP_LIMIT_DAY; -var SIGNUP_LIMIT_DISABLED; -var ARCHIVE_MODE; -var limiterPerMinute; -var limiterPerHour; -var limiterPerDay; -var cidLookupTable; -var limiterKey; -var ctEq; -var isCheloniaDashboard; -var appDir; -var dashboardDir; -var staticServeConfig; -var errorMapper; -var app; -var init_routes = __esm({ - "src/serve/routes.ts"() { - "use strict"; - init_SPMessage(); - init_chelonia(); - init_functions(); - init_persistent_actions(); - init_esm(); - import_npm_bottleneck = __toESM(require_lib6()); - import_npm_chalk2 = __toESM(require_source()); - init_http_exception(); - init_conninfo2(); - init_database(); - init_instance_keys(); - init_logger(); - init_zkppSalt(); - import_npm_nconf5 = __toESM(require_nconf()); - init_auth(); - init_dist3(); - init_zod(); - init_body_limit(); - MEGABYTE = 1048576; - SECOND = 1e3; - CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; - KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; - NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? { + return yargs.option("overwrite", { + describe: "Overwrite existing files", + requiresArg: false, + boolean: true + }).alias("o", "overwrite").option("dir", { + default: false, + describe: "Output directory", + requiresArg: false, + string: true + }).alias("d", "dir").positional("manifest", { + describe: "Manifest file path", + demandOption: true, + type: "string" + }).positional("manifest-version", { + describe: "Manifest version", + demandOption: false, + type: "string" }); - cidLookupTable = { - [multicodes.SHELTER_CONTRACT_MANIFEST]: "application/vnd.shelter.contractmanifest+json", - [multicodes.SHELTER_CONTRACT_TEXT]: "application/vnd.shelter.contracttext", - [multicodes.SHELTER_CONTRACT_DATA]: "application/vnd.shelter.contractdata+json", - [multicodes.SHELTER_FILE_MANIFEST]: "application/vnd.shelter.filemanifest+json", - [multicodes.SHELTER_FILE_CHUNK]: "application/vnd.shelter.filechunk+octet-stream" - }; - limiterKey = (ip) => { - const ipVersion = isIP(ip); - if (ipVersion === 4) { - return ip; - } else if (ipVersion === 6) { - const [address, zoneIdx] = ip.split("%"); - const segments = address.split(":"); - let isCompressed = false; - for (let i2 = 0; i2 < segments.length - 1; i2++) { - if (!isCompressed && segments[i2] === "") { - const requiredSegments = 8 - (segments.length - 1); - if (requiredSegments < 0) { - throw new Error("Invalid IPv6 address: too many segments"); - } - if ((i2 === 0 || i2 === segments.length - 2) && segments[i2 + 1] === "") { - segments[i2 + 1] = "0"; - } - if (i2 === 0 && segments.length === 3 && segments[i2 + 2] === "") { - segments[i2 + 2] = "0"; - } - segments.splice(i2, 1, ...new Array(requiredSegments).fill("0")); - isCompressed = true; - continue; - } - segments[i2] = segments[i2].replace(/^0+/, "0"); - } - if (segments.length === 8 && isIP(segments[7]) === 4) { - return segments[7]; - } else if (segments.length === 8) { - if (zoneIdx) { - segments[7] = segments[7].replace(/^0+/, "0"); - return segments.join(":").toLowerCase() + "%" + zoneIdx; - } else { - return segments.slice(0, 4).join(":").toLowerCase() + "::"; - } - } else { - throw new Error("Invalid IPv6 address"); - } - } - throw new Error("Invalid address format"); - }; - ctEq = (expected, actual) => { - let r = actual.length ^ expected.length; - for (let i2 = 0; i2 < actual.length; i2++) { - r |= actual.codePointAt(i2) ^ expected.codePointAt(i2); - } - return r === 0; - }; - isCheloniaDashboard = process9.env.IS_CHELONIA_DASHBOARD_DEV; - appDir = import_npm_nconf5.default.get("server:appDir") || "."; - dashboardDir = import.meta.dirname || "./build/dist-dashboard"; - staticServeConfig = { - routePath: isCheloniaDashboard ? "/dashboard/{path*}" : "/app/{path*}", - distAssets: path6.resolve(path6.join(isCheloniaDashboard ? dashboardDir : appDir, "assets")), - distIndexHtml: path6.resolve(path6.join(isCheloniaDashboard ? dashboardDir : appDir, "index.html")), - redirect: isCheloniaDashboard ? "/dashboard/" : "/app/" - }; - errorMapper = (e2) => { - switch (e2?.name) { - case "BackendErrorNotFound": - throw new HTTPException(404); - case "BackendErrorGone": - throw new HTTPException(410); - case "BackendErrorBadData": - throw new HTTPException(422, { message: e2.message }); - default: - console.error(e2, "Unexpected backend error"); - throw new HTTPException(500, { message: e2.message ?? "internal error" }); - } - }; - app = esm_default("okTurtles.data/get", SERVER_INSTANCE); - app.post( - "/event", - bodyLimit({ maxSize: MEGABYTE }), - authMiddleware("chel-shelter", "optional"), - zValidator("header", eventHeaderSchema), - async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const ip = getClientIP(c); - try { - const payload = await c.req.text(); - if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); - const validatedHeaders = c.req.valid("header"); - const deserializedHEAD = SPMessage.deserializeHEAD(payload); - try { - const parsed = maybeParseCID(deserializedHEAD.head.manifest); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { - throw new HTTPException(422, { message: "Invalid manifest" }); - } - const credentials = c.get("credentials"); - if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { - const manifest2 = await esm_default("chelonia.db/get", deserializedHEAD.head.manifest); - const parsedManifest = JSON.parse(manifest2); - const { name } = JSON.parse(parsedManifest.body); - if (name !== "gi.contracts/identity") { - throw new HTTPException(401, { message: "This contract type requires ownership information" }); - } - if (import_npm_nconf5.default.get("server:signup:disabled")) { - throw new HTTPException(403, { message: "Registration disabled" }); - } - if (!SIGNUP_LIMIT_DISABLED) { - try { - const keyedIp = limiterKey(ip); - await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()); - await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()); - await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()); - } catch { - console.warn("rate limit hit for IP:", ip); - throw new HTTPException(429, { message: "Rate limit exceeded" }); - } - } - } - const saltUpdateToken = validatedHeaders["shelter-salt-update-token"]; - let updateSalts; - if (saltUpdateToken) { - updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken); - } - await esm_default("backend/server/handleEntry", deserializedHEAD, payload); - await updateSalts?.(deserializedHEAD.hash); - if (deserializedHEAD.isFirstMessage) { - if (credentials?.billableContractID) { - await esm_default("backend/server/saveOwner", credentials.billableContractID, deserializedHEAD.contractID); - } else { - await esm_default("backend/server/registerBillableEntity", deserializedHEAD.contractID); - } - const name = validatedHeaders["shelter-namespace-registration"]; - if (name) { - const cheloniaState = esm_default("chelonia/rootState"); - if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === "gi.contracts/identity") { - try { - await esm_default("backend/db/registerName", name, deserializedHEAD.contractID); - } catch (registerErr) { - if (registerErr.name === "BackendErrorConflict") { - throw new HTTPException(409, { message: "Name already exists" }); - } - throw registerErr; - } - const saltRegistrationToken = validatedHeaders["shelter-salt-registration-token"]; - console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`); - if (saltRegistrationToken) { - await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken); - } - } - } - const deletionTokenDgst = validatedHeaders["shelter-deletion-token-digest"]; - if (deletionTokenDgst) { - await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst); - } - } - await esm_default("backend/server/updateSize", deserializedHEAD.contractID, Buffer15.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : void 0); - } catch (err) { - if (err instanceof HTTPException) throw err; - console.error(err, import_npm_chalk2.default.bold.yellow(err.name)); - if (err.name === "ChelErrorDBBadPreviousHEAD" || err.name === "ChelErrorAlreadyProcessed") { - const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", deserializedHEAD.contractID) ?? { HEAD: null, height: 0 }; - return c.json({ message: err.message, data: { HEADinfo } }, 409, { - "shelter-headinfo-head": HEADinfo.HEAD, - "shelter-headinfo-height": String(HEADinfo.height) - }); - } else if (err.name === "ChelErrorSignatureError") { - throw new HTTPException(422, { message: "Invalid signature" }); - } else if (err.name === "ChelErrorSignatureKeyUnauthorized") { - throw new HTTPException(403, { message: "Unauthorized signing key" }); - } - throw err; - } - return c.text(deserializedHEAD.hash); - } catch (err) { - if (err instanceof HTTPException) throw err; - err.ip = ip; - logger_default.error(err, "POST /event", err.message); - throw err; + }, + command: "pin []", + describe: "Pin a manifest version", + postHandler: (argv) => { + return pin(argv); + } +}; +init_esm(); +init_esm4(); +init_esm3(); +init_esm(); +var isEventQueueSbpEvent2 = (e2) => { + return Object.prototype.hasOwnProperty.call(e2, "sbpInvocation"); +}; +var esm_default5 = esm_default("sbp/selectors/register", { + "okTurtles.eventQueue/_init": function() { + this.eventQueues = /* @__PURE__ */ Object.create(null); + }, + "okTurtles.eventQueue/isWaiting": function(name) { + var _a2; + return !!((_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.length); + }, + "okTurtles.eventQueue/queuedInvocations": function(name) { + var _a2, _b; + if (name == null) { + return Object.fromEntries(Object.entries(this.eventQueues).map(([name2, events]) => [name2, events.map((event) => { + if (isEventQueueSbpEvent2(event)) { + return event.sbpInvocation; + } else { + return event.fn; } + })])); + } + return (_b = (_a2 = this.eventQueues[name]) === null || _a2 === void 0 ? void 0 : _a2.map((event) => { + if (isEventQueueSbpEvent2(event)) { + return event.sbpInvocation; + } else { + return event.fn; } - ); - app.get( - "/eventsAfter/:contractID/:since/:limit?", - zValidator("param", eventsAfterParamSchema), - async function(c) { - const { contractID, since, limit } = c.req.valid("param"); - const keyOps2 = c.req.query("keyOps"); - const ip = getClientIP(c); + })) !== null && _b !== void 0 ? _b : []; + }, + "okTurtles.eventQueue/queueEvent": async function(name, invocation) { + if (!Object.prototype.hasOwnProperty.call(this.eventQueues, name)) { + this.eventQueues[name] = []; + } + const events = this.eventQueues[name]; + let accept; + const promise = new Promise((resolve82) => { + accept = resolve82; + }); + const thisEvent = typeof invocation === "function" ? { + fn: invocation, + promise + } : { + sbpInvocation: invocation, + promise + }; + events.push(thisEvent); + while (events.length > 0) { + const event = events[0]; + if (event === thisEvent) { try { - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400); - } - const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: keyOps2 === "true" }); - c.req.raw.signal.addEventListener("abort", () => stream.destroy()); - const streamHeaders = stream.headers || {}; - const webStream = Readable3.toWeb(stream); - return new Response(webStream, { - headers: { "content-type": "application/octet-stream", ...streamHeaders } - }); - } catch (err) { - if (err instanceof HTTPException) throw err; - err.ip = ip; - logger_default.error(err, `GET /eventsAfter/${contractID}/${since}`, err.message); - errorMapper(err); + if (typeof invocation === "function") { + return await invocation(); + } else { + return await esm_default(...invocation); + } + } finally { + accept(); + events.shift(); } + } else { + await event.promise; } - ); - app.get( - "/ownResources", - authMiddleware("chel-shelter", "required"), - async function(c) { - const billableContractID = c.get("credentials").billableContractID; - const resources = (await esm_default("chelonia.db/get", `_private_resources_${billableContractID}`))?.split("\0"); - return c.json(resources || []); - } - ); - if (process9.env.NODE_ENV === "development") { - const levelToColor = { - error: import_npm_chalk2.default.bold.red, - warn: import_npm_chalk2.default.yellow, - log: import_npm_chalk2.default.green, - info: import_npm_chalk2.default.green, - debug: import_npm_chalk2.default.blue - }; - app.post("/log", async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const body = await c.req.json(); - if (!body.level || !body.value) throw new HTTPException(400, { message: "level and value are required" }); - const ip = getClientIP(c); - const log2 = levelToColor[body.level]; - console.debug(import_npm_chalk2.default.bold.yellow(`REMOTE LOG (${ip}): `) + log2(`[${body.level}] ${body.value}`)); - return c.body(null, 200); - }); } - app.get("/name/:name", zValidator("param", nameParamSchema), async function(c) { - const { name } = c.req.valid("param"); - try { - const lookupResult = await esm_default("backend/db/lookupName", name); - return lookupResult ? c.text(lookupResult) : notFoundNoCache(c); - } catch (err) { - logger_default.error(err, `GET /name/${name}`, err.message); - throw err; - } - }); - app.get("/latestHEADinfo/:contractID", zValidator("param", cidParamSchema), async function(c) { - const { contractID } = c.req.valid("param"); + } +}); +init_esm(); +init_esm3(); +var listenKey2 = (evt) => `events/${evt}/listeners`; +var esm_default6 = esm_default("sbp/selectors/register", { + "okTurtles.events/_init": function() { + this.errorHandler = (event, e2) => { + console.error(`[okTurtles.events] Error at handler for ${event}`, e2); + }; + }, + "okTurtles.events/on": function(event, handler) { + esm_default("okTurtles.data/add", listenKey2(event), handler); + return () => esm_default("okTurtles.events/off", event, handler); + }, + "okTurtles.events/once": function(event, handler) { + const cbWithOff = (...args) => { + handler(...args); + esm_default("okTurtles.events/off", event, cbWithOff); + }; + return esm_default("okTurtles.events/on", event, cbWithOff); + }, + "okTurtles.events/emit": function(event, ...data) { + var _a2; + for (const listener of esm_default("okTurtles.data/get", listenKey2(event)) || []) { try { - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400); - const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); - if (HEADinfo === "") { - throw new HTTPException(410); - } - if (!HEADinfo) { - console.warn(`[backend] latestHEADinfo not found for ${contractID}`); - return notFoundNoCache(c); - } - return c.json(HEADinfo, 200, { "Cache-Control": "no-store" }); - } catch (err) { - if (err instanceof HTTPException) throw err; - logger_default.error(err, `GET /latestHEADinfo/${contractID}`, err.message); - throw err; + listener(...data); + } catch (e2) { + (_a2 = this.errorHandler) === null || _a2 === void 0 ? void 0 : _a2.call(this, event, e2); } + } + }, + // almost identical to Vue.prototype.$off, except we require `event` argument + "okTurtles.events/off": function(event, handler) { + if (handler) { + esm_default("okTurtles.data/remove", listenKey2(event), handler); + } else { + esm_default("okTurtles.data/delete", listenKey2(event)); + } + }, + "okTurtles.events/setErrorHandler": function(errorHandler2) { + this.errorHandler = errorHandler2; + } +}); +init_esm(); +var import_npm_chalk4 = __toESM(require_source()); +var SERVER_EXITING = "server-exiting"; +var SERVER_RUNNING = "server-running"; +var SERVER_INSTANCE = "@instance/server"; +var PUBSUB_INSTANCE = "@instance/pubsub"; +init_SPMessage(); +init_functions(); +init_esm(); +var timer = Symbol("timer"); +var coerceToError = (arg) => { + if (arg && arg instanceof Error) + return arg; + console.warn(tag, "Please use Error objects when throwing or rejecting"); + return new Error((typeof arg === "string" ? arg : JSON.stringify(arg)) ?? "undefined"); +}; +var defaultOptions2 = { + maxAttempts: Number.POSITIVE_INFINITY, + retrySeconds: 30 +}; +var tag = "[chelonia.persistentActions]"; +var PersistentAction = class { + id; + invocation; + options; + status; + [timer]; + constructor(invocation, options2 = {}) { + this.id = crypto.randomUUID(); + this.invocation = invocation; + this.options = { ...defaultOptions2, ...options2 }; + this.status = { + attempting: false, + failedAttemptsSoFar: 0, + lastError: "", + nextRetry: "", + resolved: false + }; + } + async attempt() { + if (this.status.attempting || this.status.resolved) + return; + if (await this.trySBP(this.options.skipCondition)) + this.cancel(); + if (this.status.resolved) + return; + try { + this.status.attempting = true; + const result = await esm_default(...this.invocation); + this.status.attempting = false; + this.handleSuccess(result); + } catch (error2) { + this.status.attempting = false; + await this.handleError(coerceToError(error2)); + } + } + cancel() { + if (this[timer]) + clearTimeout(this[timer]); + this.status.nextRetry = ""; + this.status.resolved = true; + } + async handleError(error2) { + const { id, options: options2, status } = this; + status.failedAttemptsSoFar++; + status.lastError = error2.message; + const anyAttemptLeft = options2.maxAttempts > status.failedAttemptsSoFar; + if (!anyAttemptLeft) + status.resolved = true; + status.nextRetry = anyAttemptLeft && !status.resolved ? new Date(Date.now() + options2.retrySeconds * 1e3).toISOString() : ""; + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_FAILURE, { error: error2, id }); + await this.trySBP(options2.errorInvocation); + if (!anyAttemptLeft) { + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_TOTAL_FAILURE, { error: error2, id }); + await this.trySBP(options2.totalFailureInvocation); + } + if (status.nextRetry) { + this[timer] = setTimeout(() => { + this.attempt().catch((e2) => { + console.error("Error attempting persistent action", id, e2); + }); + }, this.options.retrySeconds * 1e3); + } + } + handleSuccess(result) { + const { id, status } = this; + status.lastError = ""; + status.nextRetry = ""; + status.resolved = true; + esm_default("okTurtles.events/emit", PERSISTENT_ACTION_SUCCESS, { id, result }); + } + async trySBP(invocation) { + try { + return invocation ? await esm_default(...invocation) : void 0; + } catch (error2) { + console.error(tag, coerceToError(error2).message); + } + } +}; +var persistent_actions_default = esm_default("sbp/selectors/register", { + "chelonia.persistentActions/_init"() { + this.actionsByID = /* @__PURE__ */ Object.create(null); + this.checkDatabaseKey = () => { + if (!this.databaseKey) + throw new TypeError(`${tag} No database key configured`); + }; + esm_default("okTurtles.events/on", PERSISTENT_ACTION_SUCCESS, ({ id }) => { + esm_default("chelonia.persistentActions/cancel", id); }); - app.get("/time", function(c) { - return c.text((/* @__PURE__ */ new Date()).toISOString(), 200, { - "Cache-Control": "no-store" - }); + esm_default("okTurtles.events/on", PERSISTENT_ACTION_TOTAL_FAILURE, ({ id }) => { + esm_default("chelonia.persistentActions/cancel", id); }); - app.post("/streams-test", async function(c) { - const raw2 = await c.req.arrayBuffer(); - const buf2 = Buffer15.from(raw2); - if (buf2.byteLength === 2 && buf2.toString() === "ok") { - return c.body(null, 204); + }, + // Cancels a specific action by its ID. + // The action won't be retried again, but an async action cannot be aborted if its promise is stil attempting. + async "chelonia.persistentActions/cancel"(id) { + if (id in this.actionsByID) { + this.actionsByID[id].cancel(); + delete this.actionsByID[id]; + return await esm_default("chelonia.persistentActions/save"); + } + }, + // TODO: validation + "chelonia.persistentActions/configure"({ databaseKey, options: options2 = {} }) { + this.databaseKey = databaseKey; + for (const key in options2) { + if (key in defaultOptions2) { + defaultOptions2[key] = options2[key]; } else { - throw new HTTPException(400); + throw new TypeError(`${tag} Unknown option: ${key}`); } + } + }, + "chelonia.persistentActions/enqueue"(...args) { + const ids = []; + for (const arg of args) { + const action = Array.isArray(arg) ? new PersistentAction(arg) : new PersistentAction(arg.invocation, arg); + this.actionsByID[action.id] = action; + ids.push(action.id); + } + esm_default("chelonia.persistentActions/save").catch((e2) => { + console.error("Error saving persistent actions", e2); }); - if (process9.env.NODE_ENV === "development") { - app.post("/dev-file", bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - try { - console.log("FILE UPLOAD!"); - const formData = await c.req.parseBody({ all: true }); - const hash3 = formData["hash"]; - const data = formData["data"]; - if (!hash3) throw new HTTPException(400, { message: "missing hash" }); - if (!data) throw new HTTPException(400, { message: "missing data" }); - const parsed = maybeParseCID(hash3); - if (!parsed) throw new HTTPException(400, { message: "invalid hash" }); - const ourHash = createCID(data, parsed.code); - if (ourHash !== hash3) { - console.error(`hash(${hash3}) != ourHash(${ourHash})`); - throw new HTTPException(400, { message: "bad hash!" }); - } - await esm_default("chelonia.db/set", hash3, data); - return c.text("/file/" + hash3); - } catch (err) { - if (err instanceof HTTPException) throw err; - logger_default.error(err); - throw new HTTPException(500, { message: "File upload failed" }); - } + for (const id of ids) { + this.actionsByID[id].attempt().catch((e2) => { + console.error("Error attempting persistent action", id, e2); }); } - app.post( - "/file", - bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), - authMiddleware("chel-shelter", "required"), - async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + return ids; + }, + // Forces retrying a given persisted action immediately, rather than waiting for the scheduled retry. + // - 'status.failedAttemptsSoFar' will still be increased upon failure. + // - Does nothing if a retry is already running. + // - Does nothing if the action has already been resolved, rejected or cancelled. + "chelonia.persistentActions/forceRetry"(id) { + if (id in this.actionsByID) { + return this.actionsByID[id].attempt(); + } + }, + // Loads and tries every stored persistent action under the configured database key. + async "chelonia.persistentActions/load"() { + this.checkDatabaseKey(); + const storedActions = JSON.parse(await esm_default("chelonia.db/get", this.databaseKey) ?? "[]"); + for (const { id, invocation, options: options2 } of storedActions) { + this.actionsByID[id] = new PersistentAction(invocation, options2); + this.actionsByID[id].id = id; + } + return esm_default("chelonia.persistentActions/retryAll"); + }, + // Retry all existing persisted actions. + // TODO: add some delay between actions so as not to spam the server, + // or have a way to issue them all at once in a single network call. + "chelonia.persistentActions/retryAll"() { + return Promise.allSettled(Object.keys(this.actionsByID).map((id) => esm_default("chelonia.persistentActions/forceRetry", id))); + }, + // Updates the database version of the attempting action list. + "chelonia.persistentActions/save"() { + this.checkDatabaseKey(); + return esm_default("chelonia.db/set", this.databaseKey, JSON.stringify(Object.values(this.actionsByID))); + }, + "chelonia.persistentActions/status"() { + return Object.values(this.actionsByID).map((action) => ({ + id: action.id, + invocation: action.invocation, + ...action.status + })); + }, + // Pauses every currently loaded action, and removes them from memory. + // Note: persistent storage is not affected, so that these actions can be later loaded again and retried. + "chelonia.persistentActions/unload"() { + for (const id in this.actionsByID) { + if (this.actionsByID[id][timer]) { + clearTimeout(this.actionsByID[id][timer]); + } + delete this.actionsByID[id]; + } + } +}); +var SERVER = { + // We don't check the subscriptionSet in the server because we accpt new + // contract registrations, and are also not subcribed to contracts the same + // way clients are + acceptAllMessages: true, + // The server also doesn't process actions + skipActionProcessing: true, + // The previous setting implies this one, which we set to be on the safe side + skipSideEffects: true, + // Changes the behaviour of unwrapMaybeEncryptedData so that it never decrypts. + // Mostly useful for the server, to avoid filling up the logs and for faster + // execution. + skipDecryptionAttempts: true, + // If an error occurs during processing, the message is rejected rather than + // ignored + strictProcessing: true, + // The server expects events to be received in order (no past or future events) + strictOrdering: true +}; +init_esm(); +var import_npm_chalk3 = __toESM(require_source()); +var compose = (middleware, onError, onNotFound) => { + return (context, next) => { + let index = -1; + return dispatch(0); + async function dispatch(i2) { + if (i2 <= index) { + throw new Error("next() called multiple times"); + } + index = i2; + let res; + let isError = false; + let handler; + if (middleware[i2]) { + handler = middleware[i2][0][0]; + context.req.routeIndex = i2; + } else { + handler = i2 === middleware.length && next || void 0; + } + if (handler) { try { - console.info("FILE UPLOAD!"); - const credentials = c.get("credentials"); - if (!credentials?.billableContractID) { - throw new HTTPException(401, { message: "Uploading files requires ownership information" }); - } - const contentType = c.req.header("content-type") || ""; - if (!contentType.includes("multipart/form-data")) { - throw new HTTPException(400, { message: "Expected multipart/form-data" }); - } - const formData = await c.req.formData(); - const manifestFile = formData.get("manifest"); - if (!manifestFile) throw new HTTPException(400, { message: "missing manifest" }); - if (manifestFile.name !== "manifest.json") throw new HTTPException(400, { message: "wrong manifest filename" }); - const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()); - const manifest2 = (() => { - try { - return JSON.parse(Buffer15.from(manifestPayload).toString()); - } catch { - throw new HTTPException(422, { message: "Error parsing manifest" }); - } - })(); - if (typeof manifest2 !== "object") throw new HTTPException(422, { message: "manifest format is invalid" }); - if (manifest2.version !== "1.0.0") throw new HTTPException(422, { message: "unsupported manifest version" }); - if (manifest2.cipher !== "aes256gcm") throw new HTTPException(422, { message: "unsupported cipher" }); - if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new HTTPException(422, { message: "missing chunks" }); - const chunkFiles = []; - for (let i2 = 0; ; i2++) { - const chunkFile = formData.get(String(i2)); - if (!chunkFile) break; - chunkFiles.push(chunkFile); - } - let ourSize = 0; - const chunks = await Promise.all(manifest2.chunks.map(async (chunk, i2) => { - if (!Array.isArray(chunk) || chunk.length !== 2 || typeof chunk[0] !== "number" || typeof chunk[1] !== "string" || !Number.isSafeInteger(chunk[0]) || chunk[0] <= 0) { - throw new HTTPException(422, { message: "bad chunk description" }); - } - if (!chunkFiles[i2]) { - throw new HTTPException(400, { message: "chunk missing in submitted data" }); - } - const chunkPayload = new Uint8Array(await chunkFiles[i2].arrayBuffer()); - const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK); - if (chunkPayload.byteLength !== chunk[0]) { - throw new HTTPException(400, { message: "bad chunk size" }); - } - if (ourHash !== chunk[1]) { - throw new HTTPException(400, { message: "bad chunk hash" }); - } - ourSize += chunk[0]; - return [ourHash, chunkPayload]; - })); - if (ourSize !== manifest2.size) throw new HTTPException(400, { message: "Mismatched total size" }); - const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST); - if (await esm_default("chelonia.db/get", manifestHash)) { - throw new Error(`Manifest ${manifestHash} already exists`); - } - await Promise.all(chunks.map(async ([cid]) => { - const exists = !!await esm_default("chelonia.db/get", cid); - if (exists) { - throw new Error(`Chunk ${cid} already exists`); - } - })); - await Promise.all(chunks.map(([cid, data]) => esm_default("chelonia.db/set", cid, data))); - await esm_default("chelonia.db/set", manifestHash, manifestPayload); - await esm_default("backend/server/saveOwner", credentials.billableContractID, manifestHash); - const size = manifest2.size + manifestPayload.byteLength; - await esm_default("backend/server/updateSize", manifestHash, size); - await esm_default("backend/server/updateContractFilesTotalSize", credentials.billableContractID, size); - const deletionTokenDgst = c.req.header("shelter-deletion-token-digest"); - if (deletionTokenDgst) { - await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst); - } - return c.text(manifestHash); + res = await handler(context, () => dispatch(i2 + 1)); } catch (err) { - if (err instanceof HTTPException) throw err; - logger_default.error(err, "POST /file", err.message); - throw err; + if (err instanceof Error && onError) { + context.error = err; + res = await onError(err, context); + isError = true; + } else { + throw err; + } + } + } else { + if (context.finalized === false && onNotFound) { + res = await onNotFound(context); } } - ); - app.get("/file/:hash", zValidator("param", cidHashParamSchema), async function(c) { - const { hash: hash3 } = c.req.valid("param"); - const parsed = maybeParseCID(hash3); - if (!parsed) { - throw new HTTPException(400); - } - const blobOrString = await esm_default("chelonia.db/get", `any:${hash3}`); - if (blobOrString?.length === 0) { - throw new HTTPException(410); - } else if (!blobOrString) { - return notFoundNoCache(c); + if (res && (context.finalized === false || isError)) { + context.res = res; } - const type = cidLookupTable[parsed.code] || "application/octet-stream"; - return c.body(blobOrString, 200, { - "ETag": `"${hash3}"`, - "Cache-Control": "public,max-age=31536000,immutable", - // CSP to disable everything -- this only affects direct navigation to the - // `/file` URL. - // The CSP below prevents any sort of resource loading or script execution - // on direct navigation. The `nosniff` header instructs the browser to - // honour the provided content-type. - "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox", - "X-Content-Type-Options": "nosniff", - "Content-Type": type + return context; + } + }; +}; +var HTTPException = class extends Error { + res; + status; + /** + * Creates an instance of `HTTPException`. + * @param status - HTTP status code for the exception. Defaults to 500. + * @param options - Additional options for the exception. + */ + constructor(status = 500, options2) { + super(options2?.message, { cause: options2?.cause }); + this.res = options2?.res; + this.status = status; + } + /** + * Returns the response object associated with the exception. + * If a response object is not provided, a new response is created with the error message and status code. + * @returns The response object. + */ + getResponse() { + if (this.res) { + const newResponse = new Response(this.res.body, { + status: this.status, + headers: this.res.headers }); + return newResponse; + } + return new Response(this.message, { + status: this.status }); - app.post( - "/deleteFile/:hash", - authMiddleware(["chel-shelter", "chel-bearer"], "required"), - zValidator("param", cidHashParamSchema), - async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const { hash: hash3 } = c.req.valid("param"); - const strategy = c.get("authStrategy"); - const parsed = maybeParseCID(hash3); - if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { - throw new HTTPException(400); - } - const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); - if (!owner) { - throw new HTTPException(404); - } - const credentials = c.get("credentials"); - switch (strategy) { - case "chel-shelter": { - const ultimateOwner = await lookupUltimateOwner(owner); - if (!ctEq(credentials.billableContractID, ultimateOwner)) { - throw new HTTPException(401, { message: "Invalid shelter auth" }); - } - break; - } - case "chel-bearer": { - const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); - if (!expectedTokenDgst) { - throw new HTTPException(404); - } - const tokenDgst = blake32Hash(credentials.token); - if (!ctEq(expectedTokenDgst, tokenDgst)) { - throw new HTTPException(401, { message: "Invalid token" }); - } - break; - } - default: - throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); - } - try { - await esm_default("backend/deleteFile", hash3, null, true); - return c.body(null, 200); - } catch (e2) { - errorMapper(e2); - } - } - ); - app.post( - "/deleteContract/:hash", - authMiddleware(["chel-shelter", "chel-bearer"], "required"), - zValidator("param", cidHashParamSchema), - async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const { hash: hash3 } = c.req.valid("param"); - const strategy = c.get("authStrategy"); - const credentials = c.get("credentials"); - switch (strategy) { - case "chel-shelter": { - const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); - if (!owner) { - throw new HTTPException(404); - } - const ultimateOwner = await lookupUltimateOwner(owner); - if (!ctEq(credentials.billableContractID, ultimateOwner)) { - throw new HTTPException(401, { message: "Invalid shelter auth" }); - } - break; - } - case "chel-bearer": { - const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); - if (!expectedTokenDgst) { - throw new HTTPException(404); - } - const tokenDgst = blake32Hash(credentials.token); - if (!ctEq(expectedTokenDgst, tokenDgst)) { - throw new HTTPException(401, { message: "Invalid token" }); - } - break; - } - default: - throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); - } - const username = await esm_default("chelonia.db/get", `_private_cid2name_${hash3}`); - try { - const [id] = esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", hash3, null, true]); - if (username) { - const ip = getClientIP(c); - console.info({ contractID: hash3, username, ip, taskId: id }, "Scheduled deletion on named contract"); - } - return c.json({ id }, 202); - } catch (e2) { - errorMapper(e2); - } + } +}; +var GET_MATCH_RESULT = /* @__PURE__ */ Symbol(); +var parseBody = async (request, options2 = /* @__PURE__ */ Object.create(null)) => { + const { all = false, dot = false } = options2; + const headers = request instanceof HonoRequest ? request.raw.headers : request.headers; + const contentType = headers.get("Content-Type"); + if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) { + return parseFormData(request, { all, dot }); + } + return {}; +}; +async function parseFormData(request, options2) { + const formData = await request.formData(); + if (formData) { + return convertFormDataToBodyData(formData, options2); + } + return {}; +} +function convertFormDataToBodyData(formData, options2) { + const form = /* @__PURE__ */ Object.create(null); + formData.forEach((value, key) => { + const shouldParseAllValues = options2.all || key.endsWith("[]"); + if (!shouldParseAllValues) { + form[key] = value; + } else { + handleParsingAllValues(form, key, value); + } + }); + if (options2.dot) { + Object.entries(form).forEach(([key, value]) => { + const shouldParseDotValues = key.includes("."); + if (shouldParseDotValues) { + handleParsingNestedValues(form, key, value); + delete form[key]; } - ); - app.post( - "/kv/:contractID/:key", - bodyLimit({ maxSize: 6 * MEGABYTE }), - authMiddleware("chel-shelter", "required"), - zValidator("param", kvParamSchema), - async function(c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const { contractID, key } = c.req.valid("param"); - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400); - } - const credentials = c.get("credentials"); - if (!ctEq(credentials.billableContractID, contractID)) { - throw new HTTPException(401); - } - const payloadBuffer = Buffer15.from(await c.req.arrayBuffer()); - return esm_default("chelonia/queueInvocation", contractID, async () => { - const existing = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); - const expectedEtag = c.req.header("if-match"); - if (!expectedEtag) { - throw new HTTPException(400, { message: "if-match is required" }); - } - const cid = existing ? createCID(existing, multicodes.RAW) : ""; - if (expectedEtag === "*") { - } else { - if (!expectedEtag.split(",").map((v2) => v2.trim()).includes(`"${cid}"`)) { - return new Response(existing || "", { - status: 412, - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"` - } - }); - } - } - try { - const serializedData = JSON.parse(payloadBuffer.toString()); - const { contracts } = esm_default("chelonia/rootState"); - if (contracts[contractID].height !== Number(serializedData.height)) { - return new Response(existing || "", { - status: 409, - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"` - } - }); - } - esm_default("chelonia/parseEncryptedOrUnencryptedDetachedMessage", { - contractID, - serializedData, - meta: key - }); - } catch (parseErr) { - if (parseErr instanceof Response) throw parseErr; - throw new HTTPException(422); - } - const existingSize = existing ? Buffer15.from(existing).byteLength : 0; - await esm_default("chelonia.db/set", `_private_kv_${contractID}_${key}`, payloadBuffer); - await esm_default("backend/server/updateSize", contractID, payloadBuffer.byteLength - existingSize); - await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key); - esm_default("backend/server/broadcastKV", contractID, key, payloadBuffer.toString()).catch((e2) => console.error(e2, "Error broadcasting KV update", contractID, key)); - return c.body(null, 204); - }); + }); + } + return form; +} +var handleParsingAllValues = (form, key, value) => { + if (form[key] !== void 0) { + if (Array.isArray(form[key])) { + ; + form[key].push(value); + } else { + form[key] = [form[key], value]; + } + } else { + if (!key.endsWith("[]")) { + form[key] = value; + } else { + form[key] = [value]; + } + } +}; +var handleParsingNestedValues = (form, key, value) => { + if (/(?:^|\.)__proto__\./.test(key)) { + return; + } + let nestedForm = form; + const keys = key.split("."); + keys.forEach((key2, index) => { + if (index === keys.length - 1) { + nestedForm[key2] = value; + } else { + if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) { + nestedForm[key2] = /* @__PURE__ */ Object.create(null); } - ); - app.get( - "/kv/:contractID/:key", - authMiddleware("chel-shelter", "required"), - zValidator("param", kvParamSchema), - async function(c) { - const { contractID, key } = c.req.valid("param"); - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400); - } - const credentials = c.get("credentials"); - if (!ctEq(credentials.billableContractID, contractID)) { - throw new HTTPException(401); - } - const result = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); - if (!result) { - return notFoundNoCache(c); - } - const cid = createCID(result, multicodes.RAW); - return new Response(result, { - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"`, - "Cache-Control": "no-store" - } - }); + nestedForm = nestedForm[key2]; + } + }); +}; +var splitPath = (path8) => { + const paths = path8.split("/"); + if (paths[0] === "") { + paths.shift(); + } + return paths; +}; +var splitRoutingPath = (routePath) => { + const { groups, path: path8 } = extractGroupsFromPath(routePath); + const paths = splitPath(path8); + return replaceGroupMarks(paths, groups); +}; +var extractGroupsFromPath = (path8) => { + const groups = []; + path8 = path8.replace(/\{[^}]+\}/g, (match2, index) => { + const mark = `@${index}`; + groups.push([mark, match2]); + return mark; + }); + return { groups, path: path8 }; +}; +var replaceGroupMarks = (paths, groups) => { + for (let i2 = groups.length - 1; i2 >= 0; i2--) { + const [mark] = groups[i2]; + for (let j = paths.length - 1; j >= 0; j--) { + if (paths[j].includes(mark)) { + paths[j] = paths[j].replace(mark, groups[i2][1]); + break; } - ); - app.get("/serverMessages", function(c) { - const messages = import_npm_nconf5.default.get("server:messages"); - if (!messages) return c.json([]); - return c.json(messages, 200, { "Cache-Control": "no-store" }); - }); - app.get("/assets/:subpath{.+}", async function(c) { - const subpath = c.req.param("subpath"); - const basename72 = path6.basename(subpath); - const filePath = path6.join(staticServeConfig.distAssets, subpath); - try { - const file = await Deno.readFile(filePath); - const headers = {}; - if (basename72.includes("-cached")) { - headers["ETag"] = `"${basename72}"`; - headers["Cache-Control"] = "public,max-age=31536000,immutable"; - } - if (subpath.includes("js/sw-")) { - console.debug("adding header: Service-Worker-Allowed /"); - headers["Service-Worker-Allowed"] = "/"; - } - const ext = path6.extname(subpath).toLowerCase(); - const mimeTypes = { - ".js": "application/javascript", - ".mjs": "application/javascript", - ".css": "text/css", - ".html": "text/html", - ".json": "application/json", - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".gif": "image/gif", - ".svg": "image/svg+xml", - ".ico": "image/x-icon", - ".woff": "font/woff", - ".woff2": "font/woff2", - ".ttf": "font/ttf", - ".otf": "font/otf", - ".webp": "image/webp", - ".mp4": "video/mp4", - ".webm": "video/webm", - ".map": "application/json" - }; - const contentType = mimeTypes[ext] || "application/octet-stream"; - headers["Content-Type"] = contentType; - return c.body(file, 200, headers); - } catch { - return notFoundNoCache(c); + } + } + return paths; +}; +var patternCache = {}; +var getPattern = (label, next) => { + if (label === "*") { + return "*"; + } + const match2 = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); + if (match2) { + const cacheKey2 = `${label}#${next}`; + if (!patternCache[cacheKey2]) { + if (match2[2]) { + patternCache[cacheKey2] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey2, match2[1], new RegExp(`^${match2[2]}(?=/${next})`)] : [label, match2[1], new RegExp(`^${match2[2]}$`)]; + } else { + patternCache[cacheKey2] = [label, match2[1], true]; } - }); - if (isCheloniaDashboard) { - app.get("/dashboard/assets/:subpath{.+}", async function(c) { - const subpath = c.req.param("subpath"); - const basename72 = path6.basename(subpath); - const filePath = path6.join(staticServeConfig.distAssets, subpath); - try { - const file = await Deno.readFile(filePath); - const headers = {}; - if (basename72.includes("-cached")) { - headers["ETag"] = `"${basename72}"`; - headers["Cache-Control"] = "public,max-age=31536000,immutable"; - } - if (subpath.includes("js/sw-")) { - console.debug("adding header: Service-Worker-Allowed /"); - headers["Service-Worker-Allowed"] = "/"; - } - const ext = path6.extname(subpath).toLowerCase(); - const mimeTypes = { - ".js": "application/javascript", - ".mjs": "application/javascript", - ".css": "text/css", - ".html": "text/html", - ".json": "application/json", - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".gif": "image/gif", - ".svg": "image/svg+xml", - ".ico": "image/x-icon", - ".woff": "font/woff", - ".woff2": "font/woff2", - ".ttf": "font/ttf", - ".otf": "font/otf", - ".webp": "image/webp", - ".mp4": "video/mp4", - ".webm": "video/webm", - ".map": "application/json" - }; - const contentType = mimeTypes[ext] || "application/octet-stream"; - headers["Content-Type"] = contentType; - return c.body(file, 200, headers); - } catch { - return notFoundNoCache(c); - } - }); } - app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { + return patternCache[cacheKey2]; + } + return null; +}; +var tryDecode = (str, decoder) => { + try { + return decoder(str); + } catch { + return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match2) => { try { - const file = await Deno.readFile(staticServeConfig.distIndexHtml); - return c.body(file, 200, { "Content-Type": "text/html" }); + return decoder(match2); } catch { - return notFoundNoCache(c); + return match2; } }); - app.get("/", function(c) { - return c.redirect(staticServeConfig.redirect); - }); - app.post( - "/zkpp/register/:name", - zValidator("param", nameParamSchema), - zValidator("json", zkppRegisterBodySchema), - async function(c) { - const { name } = c.req.valid("param"); - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - const lookupResult = await esm_default("backend/db/lookupName", name); - if (lookupResult) { - throw new HTTPException(409); - } - try { - const payload = c.req.valid("json"); - if ("b" in payload) { - const result = registrationKey(name, payload.b); - if (result) { - return c.json(result); - } - } else { - const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); - if (result) { - return c.json(result); - } - } - } catch (e2) { - if (e2 instanceof HTTPException) throw e2; - e2.ip = getClientIP(c); - console.error(e2, "Error at POST /zkpp/{name}: " + e2.message); + } +}; +var tryDecodeURI = (str) => tryDecode(str, decodeURI); +var getPath = (request) => { + const url2 = request.url; + const start = url2.indexOf("/", url2.indexOf(":") + 4); + let i2 = start; + for (; i2 < url2.length; i2++) { + const charCode = url2.charCodeAt(i2); + if (charCode === 37) { + const queryIndex = url2.indexOf("?", i2); + const hashIndex = url2.indexOf("#", i2); + const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex); + const path8 = url2.slice(start, end); + return tryDecodeURI(path8.includes("%25") ? path8.replace(/%25/g, "%2525") : path8); + } else if (charCode === 63 || charCode === 35) { + break; + } + } + return url2.slice(start, i2); +}; +var getPathNoStrict = (request) => { + const result = getPath(request); + return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result; +}; +var mergePath = (base2, sub, ...rest) => { + if (rest.length) { + sub = mergePath(sub, ...rest); + } + return `${base2?.[0] === "/" ? "" : "/"}${base2}${sub === "/" ? "" : `${base2?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`; +}; +var checkOptionalParameter = (path8) => { + if (path8.charCodeAt(path8.length - 1) !== 63 || !path8.includes(":")) { + return null; + } + const segments = path8.split("/"); + const results = []; + let basePath = ""; + segments.forEach((segment) => { + if (segment !== "" && !/\:/.test(segment)) { + basePath += "/" + segment; + } else if (/\:/.test(segment)) { + if (/\?/.test(segment)) { + if (results.length === 0 && basePath === "") { + results.push("/"); + } else { + results.push(basePath); } - throw new HTTPException(500, { message: "internal error" }); + const optionalSegment = segment.replace("?", ""); + basePath += "/" + optionalSegment; + results.push(basePath); + } else { + basePath += "/" + segment; } - ); - app.get( - "/zkpp/:contractID/auth_hash", - zValidator("param", zkppContractParamSchema), - zValidator("query", zkppAuthHashQuerySchema), - async function(c) { - const { contractID } = c.req.valid("param"); - const { b } = c.req.valid("query"); - try { - const challenge = await getChallenge(contractID, b); - return challenge ? c.json(challenge) : notFoundNoCache(c); - } catch (e2) { - ; - e2.ip = getClientIP(c); - console.error(e2, "Error at GET /zkpp/{contractID}/auth_hash: " + e2.message); - } - throw new HTTPException(500, { message: "internal error" }); + } + }); + return results.filter((v2, i2, a) => a.indexOf(v2) === i2); +}; +var _decodeURI = (value) => { + if (!/[%+]/.test(value)) { + return value; + } + if (value.indexOf("+") !== -1) { + value = value.replace(/\+/g, " "); + } + return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value; +}; +var _getQueryParam = (url2, key, multiple) => { + let encoded; + if (!multiple && key && !/[%+]/.test(key)) { + let keyIndex2 = url2.indexOf("?", 8); + if (keyIndex2 === -1) { + return void 0; + } + if (!url2.startsWith(key, keyIndex2 + 1)) { + keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); + } + while (keyIndex2 !== -1) { + const trailingKeyCode = url2.charCodeAt(keyIndex2 + key.length + 1); + if (trailingKeyCode === 61) { + const valueIndex = keyIndex2 + key.length + 2; + const endIndex = url2.indexOf("&", valueIndex); + return _decodeURI(url2.slice(valueIndex, endIndex === -1 ? void 0 : endIndex)); + } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) { + return ""; } + keyIndex2 = url2.indexOf(`&${key}`, keyIndex2 + 1); + } + encoded = /[%+]/.test(url2); + if (!encoded) { + return void 0; + } + } + const results = {}; + encoded ??= /[%+]/.test(url2); + let keyIndex = url2.indexOf("?", 8); + while (keyIndex !== -1) { + const nextKeyIndex = url2.indexOf("&", keyIndex + 1); + let valueIndex = url2.indexOf("=", keyIndex); + if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) { + valueIndex = -1; + } + let name = url2.slice( + keyIndex + 1, + valueIndex === -1 ? nextKeyIndex === -1 ? void 0 : nextKeyIndex : valueIndex ); - app.get( - "/zkpp/:contractID/contract_hash", - zValidator("param", zkppContractParamSchema), - zValidator("query", zkppContractHashQuerySchema), - async function(c) { - const { contractID } = c.req.valid("param"); - const { r, s, sig, hc } = c.req.valid("query"); - try { - const salt = await getContractSalt(contractID, r, s, sig, hc); - if (salt) { - return c.json(salt); - } - } catch (e2) { - ; - e2.ip = getClientIP(c); - console.error(e2, "Error at GET /zkpp/{contractID}/contract_hash: " + e2.message); - } - throw new HTTPException(500, { message: "internal error" }); + if (encoded) { + name = _decodeURI(name); + } + keyIndex = nextKeyIndex; + if (name === "") { + continue; + } + let value; + if (valueIndex === -1) { + value = ""; + } else { + value = url2.slice(valueIndex + 1, nextKeyIndex === -1 ? void 0 : nextKeyIndex); + if (encoded) { + value = _decodeURI(value); } - ); - app.post( - "/zkpp/:contractID/updatePasswordHash", - zValidator("param", zkppContractParamSchema), - zValidator("json", zkppUpdatePasswordBodySchema), - async function(c) { - const { contractID } = c.req.valid("param"); - if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); - try { - const payload = c.req.valid("json"); - const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); - if (result) { - return c.json(result); - } - } catch (e2) { - if (e2 instanceof HTTPException) throw e2; - e2.ip = getClientIP(c); - console.error(e2, "Error at POST /zkpp/{contractID}/updatePasswordHash: " + e2.message); - } - throw new HTTPException(500, { message: "internal error" }); + } + if (multiple) { + if (!(results[name] && Array.isArray(results[name]))) { + results[name] = []; } - ); + ; + results[name].push(value); + } else { + results[name] ??= value; + } } -}); -var server_exports = {}; -__export(server_exports, { - app: () => app2 -}); -var import_npm_chalk3; -var import_npm_nconf6; -var cheloniaAppManifest; -var ARCHIVE_MODE2; -var ownerSizeTotalWorker; -var creditsWorker; -var app2; -var httpServer; -var appendToOrphanedNamesIndex; -var pushHeartbeatIntervalID; -var init_server = __esm({ - async "src/serve/server.ts"() { - "use strict"; - init_SPMessage(); - init_chelonia(); - init_functions(); - init_persistent_actions(); - init_presets(); - init_esm(); - import_npm_chalk3 = __toESM(require_source()); - init_dist(); - init_cors(); - init_dist2(); - init_createWorker(); - init_constants4(); - init_database(); - init_errors4(); - init_events2(); - init_instance_keys(); - init_pubsub2(); - init_push(); - import_npm_nconf6 = __toESM(require_nconf()); - cheloniaAppManifest = await (async () => { - const appDir2 = import_npm_nconf6.default.get("server:appDir") || process10.cwd(); - try { - return (await import(pathToFileURL(join82(appDir2, "chelonia.json")).toString(), { - with: { type: "json" } - })).default; - } catch { - console.warn("`chelonia.json` unparsable or not found. Version information will be unavailable."); + return key ? results[key] : results; +}; +var getQueryParam = _getQueryParam; +var getQueryParams = (url2, key) => { + return _getQueryParam(url2, key, true); +}; +var decodeURIComponent_ = decodeURIComponent; +var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_); +var HonoRequest = class { + /** + * `.raw` can get the raw Request object. + * + * @see {@link https://hono.dev/docs/api/request#raw} + * + * @example + * ```ts + * // For Cloudflare Workers + * app.post('/', async (c) => { + * const metadata = c.req.raw.cf?.hostMetadata? + * ... + * }) + * ``` + */ + raw; + #validatedData; + // Short name of validatedData + #matchResult; + routeIndex = 0; + /** + * `.path` can get the pathname of the request. + * + * @see {@link https://hono.dev/docs/api/request#path} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const pathname = c.req.path // `/about/me` + * }) + * ``` + */ + path; + bodyCache = {}; + constructor(request, path8 = "/", matchResult = [[]]) { + this.raw = request; + this.path = path8; + this.#matchResult = matchResult; + this.#validatedData = {}; + } + param(key) { + return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams(); + } + #getDecodedParam(key) { + const paramKey = this.#matchResult[0][this.routeIndex][1][key]; + const param = this.#getParamValue(paramKey); + return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param; + } + #getAllDecodedParams() { + const decoded = {}; + const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]); + for (const key of keys) { + const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]); + if (value !== void 0) { + decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value; } - })(); - ARCHIVE_MODE2 = import_npm_nconf6.default.get("server:archiveMode"); - if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { - process10.stderr.write("The size calculation worker must run more frequently than the credits worker for accurate billing"); - process10.exit(1); - } - ownerSizeTotalWorker = ARCHIVE_MODE2 || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/ownerSizeTotalWorker.js"); - creditsWorker = ARCHIVE_MODE2 || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/creditsWorker.js"); - app2 = new Hono2(); - app2.use("*", cors({ origin: "*" })); - app2.use("*", async (c, next) => { - await next(); - c.header("X-Frame-Options", "DENY"); - }); - if (process10.env.NODE_ENV === "development" && !process10.env.CI) { - app2.use("*", async (c, next) => { - await next(); - const ip = c.req.header("x-real-ip") || "unknown"; - console.debug(import_npm_chalk3.default`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`); - }); } - httpServer = createAdaptorServer({ fetch: app2.fetch }); - appendToOrphanedNamesIndex = appendToIndexFactory("_private_orphaned_names_index"); - esm_default("okTurtles.data/set", SERVER_INSTANCE, app2); - esm_default("sbp/selectors/register", { - "backend/server/persistState": async function(deserializedHEAD) { - const contractID = deserializedHEAD.contractID; - const cheloniaState = esm_default("chelonia/rootState"); - if (!cheloniaState.contracts[contractID] || cheloniaState.contracts[contractID].height < deserializedHEAD.head.height) { - return; - } - if (cheloniaState.contracts[contractID].HEAD === deserializedHEAD.hash) { - const state = { - contractState: cheloniaState[contractID], - cheloniaContractInfo: cheloniaState.contracts[contractID] - }; - await esm_default("chelonia.db/set", "_private_cheloniaState_" + contractID, JSON.stringify(state)); - } - if (contractID === deserializedHEAD.hash) { - await esm_default("backend/server/appendToContractIndex", contractID); - } - if (cheloniaState.contracts[contractID].previousKeyOp === deserializedHEAD.hash) { - await appendToIndexFactory(`_private_keyop_idx_${contractID}_${deserializedHEAD.head.height - deserializedHEAD.head.height % KEYOP_SEGMENT_LENGTH}`)(String(deserializedHEAD.head.height)); - } - }, - "backend/server/appendToContractIndex": appendToIndexFactory("_private_cheloniaState_index"), - "backend/server/broadcastKV": async function(contractID, key, entry) { - const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const pubsubMessage = createKvMessage(contractID, key, entry); - const subscribers = pubsub.enumerateSubscribers(contractID, key); - console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting KV change on ${contractID} to key ${key}`)); - await pubsub.broadcast(pubsubMessage, { to: subscribers, wsOnly: true }); - }, - "backend/server/broadcastEntry": async function(deserializedHEAD, entry) { - const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const contractID = deserializedHEAD.contractID; - const contractType = esm_default("chelonia/rootState").contracts[contractID]?.type; - const pubsubMessage = createMessage(NOTIFICATION_TYPE.ENTRY, entry, { contractID, contractType }); - const subscribers = pubsub.enumerateSubscribers(contractID); - console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting ${deserializedHEAD.description()}`)); - await pubsub.broadcast(pubsubMessage, { to: subscribers }); - }, - "backend/server/broadcastDeletion": async function(contractID) { - const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const pubsubMessage = createMessage(NOTIFICATION_TYPE.DELETION, contractID); - const subscribers = pubsub.enumerateSubscribers(contractID); - console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting deletion of ${contractID}`)); - await pubsub.broadcast(pubsubMessage, { to: subscribers }); - }, - "backend/server/handleEntry": async function(deserializedHEAD, entry) { - const contractID = deserializedHEAD.contractID; - if (deserializedHEAD.head.op === SPMessage.OP_CONTRACT) { - esm_default("okTurtles.data/get", PUBSUB_INSTANCE).channels.add(contractID); - } - await esm_default("chelonia/private/in/enqueueHandleEvent", contractID, entry); - await esm_default("backend/server/persistState", deserializedHEAD, entry); - esm_default("backend/server/broadcastEntry", deserializedHEAD, entry).catch((e2) => console.error(e2, "Error broadcasting entry", contractID, deserializedHEAD.hash)); - }, - "backend/server/saveOwner": async function(ownerID, resourceID) { - await esm_default("chelonia/queueInvocation", ownerID, async () => { - const owner = await esm_default("chelonia.db/get", ownerID); - if (!owner) { - throw new Error("Owner resource does not exist"); - } - await esm_default("chelonia.db/set", `_private_owner_${resourceID}`, ownerID); - const resourcesKey = `_private_resources_${ownerID}`; - await appendToIndexFactory(resourcesKey)(resourceID); - esm_default("chelonia.persistentActions/enqueue", ["backend/server/addToIndirectResourcesIndex", resourceID]); - }); - }, - "backend/server/addToIndirectResourcesIndex": async function(resourceID) { - const ownerID = await esm_default("chelonia.db/get", `_private_owner_${resourceID}`); - let indirectOwnerID = ownerID; - while (indirectOwnerID = await esm_default("chelonia.db/get", `_private_owner_${indirectOwnerID}`)) { - await appendToIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(resourceID); - } - }, - "backend/server/removeFromIndirectResourcesIndex": async function(resourceID) { - const ownerID = await esm_default("chelonia.db/get", `_private_owner_${resourceID}`); - const resources = await esm_default("chelonia.db/get", `_private_resources_${resourceID}`); - const indirectResources = resources ? await esm_default("chelonia.db/get", `_private_indirectResources_${resourceID}`) : void 0; - const allSubresources = [ - resourceID, - ...resources ? resources.split("\0") : [], - ...indirectResources ? indirectResources.split("\0") : [] - ]; - let indirectOwnerID = ownerID; - while (indirectOwnerID = await esm_default("chelonia.db/get", `_private_owner_${indirectOwnerID}`)) { - await removeFromIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(allSubresources); - } - }, - "backend/server/registerBillableEntity": appendToIndexFactory("_private_billable_entities"), - "backend/server/updateSize": function(resourceID, size, ultimateOwnerID) { - const sizeKey = `_private_size_${resourceID}`; - return updateSize(resourceID, sizeKey, size).then(() => { - return ownerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID, size, ultimateOwnerID }); - }); - }, - "backend/server/updateContractFilesTotalSize": function(resourceID, size) { - const sizeKey = `_private_contractFilesTotalSize_${resourceID}`; - return updateSize(resourceID, sizeKey, size, true); - }, - "backend/server/stop": async function() { - clearInterval(pushHeartbeatIntervalID); - if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { - await esm_default("backend/server/stopRateLimiters"); - } - await new Promise((resolve82, reject) => { - httpServer.close((err) => { - if (err) { - reject(err); - } else { - resolve82(); - } - }); - }); - await Promise.all([ - ownerSizeTotalWorker?.terminate(), - creditsWorker?.terminate() - ]); - }, - async "backend/deleteFile"(cid, ultimateOwnerID, skipIfDeleted) { - const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); - const rawManifest = await esm_default("chelonia.db/get", cid); - const size = await esm_default("chelonia.db/get", `_private_size_${cid}`); - if (owner && !ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(owner); - if (rawManifest === "") { - if (skipIfDeleted) return; - throw new BackendErrorGone(); - } - if (!rawManifest) { - if (skipIfDeleted) return; - throw new BackendErrorNotFound(); - } - try { - const manifest2 = JSON.parse(rawManifest); - if (!manifest2 || typeof manifest2 !== "object") throw new BackendErrorBadData("manifest format is invalid"); - if (manifest2.version !== "1.0.0") throw new BackendErrorBadData("unsupported manifest version"); - if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new BackendErrorBadData("missing chunks"); - await Promise.all(manifest2.chunks.map(([, cid2]) => esm_default("chelonia.db/delete", cid2))); - } catch (e2) { - console.warn(e2, `Error parsing manifest for ${cid}. It's probably not a file manifest.`); - throw new BackendErrorNotFound(); - } - const resourcesKey = `_private_resources_${owner}`; - await removeFromIndexFactory(resourcesKey)(cid); - await esm_default("backend/server/removeFromIndirectResourcesIndex", cid); - await esm_default("chelonia.db/delete", `_private_owner_${cid}`); - await esm_default("chelonia.db/delete", `_private_size_${cid}`); - await esm_default("chelonia.db/delete", `_private_deletionTokenDgst_${cid}`); - await esm_default("chelonia.db/set", cid, ""); - await esm_default("backend/server/updateContractFilesTotalSize", owner, -Number(size)); - if (ultimateOwnerID && size) { - await ownerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID: cid, size: -parseInt(size), ultimateOwnerID }); - } - }, - async "backend/deleteContract"(cid, ultimateOwnerID, skipIfDeleted) { - let contractsPendingDeletion = esm_default("okTurtles.data/get", "contractsPendingDeletion"); - if (!contractsPendingDeletion) { - contractsPendingDeletion = /* @__PURE__ */ new Set(); - esm_default("okTurtles.data/set", "contractsPendingDeletion", contractsPendingDeletion); - } - if (contractsPendingDeletion.has(cid)) { - return; - } - contractsPendingDeletion.add(cid); - return await esm_default("chelonia/queueInvocation", cid, async () => { - const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); - if (!ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(cid); - const rawManifest = await esm_default("chelonia.db/get", cid); - const size = await esm_default("chelonia.db/get", `_private_size_${cid}`); - if (rawManifest === "") { - if (skipIfDeleted) return; - throw new BackendErrorGone(); - } - if (!rawManifest) { - if (skipIfDeleted) return; - throw new BackendErrorNotFound(); - } - const resourcesKey = `_private_resources_${cid}`; - const resources = await esm_default("chelonia.db/get", resourcesKey); - if (resources) { - await Promise.allSettled(resources.split("\0").map((resourceCid) => { - const parsed = parseCID(resourceCid); - if (parsed.code === multicodes.SHELTER_CONTRACT_DATA) { - return esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", resourceCid, ultimateOwnerID, true]); - } else if (parsed.code === multicodes.SHELTER_FILE_MANIFEST) { - return esm_default("chelonia.persistentActions/enqueue", ["backend/deleteFile", resourceCid, ultimateOwnerID, true]); - } else { - console.warn({ cid, resourceCid, code: parsed.code }, "Resource should be deleted but it is of an unknown type"); - } - return void 0; - })); - } - await esm_default("chelonia.db/delete", resourcesKey); - const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", cid); - if (latestHEADinfo) { - for (let i2 = latestHEADinfo.height; i2 > 0; i2--) { - const eventKey = `_private_hidx=${cid}#${i2}`; - const event = await esm_default("chelonia.db/get", eventKey); - if (event) { - await esm_default("chelonia.db/delete", JSON.parse(event).hash); - await esm_default("chelonia.db/delete", eventKey); - } - if (i2 % KEYOP_SEGMENT_LENGTH === 0) { - await esm_default("chelonia.db/delete", `_private_keyop_idx_${cid}_${i2}`); - } - } - await esm_default("chelonia/db/deleteLatestHEADinfo", cid); - } - const kvIndexKey = `_private_kvIdx_${cid}`; - const kvKeys = await esm_default("chelonia.db/get", kvIndexKey); - if (kvKeys) { - await Promise.all(kvKeys.split("\0").map((key) => { - return esm_default("chelonia.db/delete", `_private_kv_${cid}_${key}`); - })); - } - await esm_default("chelonia.db/delete", kvIndexKey); - await esm_default("backend/server/removeFromIndirectResourcesIndex", cid); - await esm_default("chelonia.db/delete", `_private_indirectResources_${cid}`); - await esm_default("chelonia.db/get", `_private_cid2name_${cid}`).then((name) => { - if (!name) return; - return Promise.all([ - esm_default("chelonia.db/delete", `_private_cid2name_${cid}`), - appendToOrphanedNamesIndex(name) - ]); - }); - await esm_default("chelonia.db/delete", `_private_rid_${cid}`); - await esm_default("chelonia.db/delete", `_private_owner_${cid}`); - await esm_default("chelonia.db/delete", `_private_size_${cid}`); - await esm_default("chelonia.db/delete", `_private_contractFilesTotalSize_${cid}`); - await esm_default("chelonia.db/delete", `_private_deletionTokenDgst_${cid}`); - await removeFromIndexFactory(`_private_resources_${owner}`)(cid); - await esm_default("chelonia.db/delete", `_private_hidx=${cid}#0`); - await esm_default("chelonia.db/delete", `_private_keyop_idx_${cid}_0`); - await esm_default("chelonia.db/set", cid, ""); - esm_default("chelonia/private/removeImmediately", cid); - if (size) { - await ownerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID: cid, size: -parseInt(size), ultimateOwnerID }); - } - await esm_default("chelonia.db/delete", `_private_cheloniaState_${cid}`); - await removeFromIndexFactory("_private_cheloniaState_index")(cid); - await removeFromIndexFactory("_private_billable_entities")(cid); - esm_default("backend/server/broadcastDeletion", cid).catch((e2) => { - console.error(e2, "Error broadcasting contract deletion", cid); - }); - }).finally(() => { - contractsPendingDeletion.delete(cid); - }).catch((e2) => { - console.error(e2, "Error in contract deletion cleanup"); - throw e2; - }); - } + return decoded; + } + #getParamValue(paramKey) { + return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey; + } + query(key) { + return getQueryParam(this.url, key); + } + queries(key) { + return getQueryParams(this.url, key); + } + header(name) { + if (name) { + return this.raw.headers.get(name) ?? void 0; + } + const headerData = {}; + this.raw.headers.forEach((value, key) => { + headerData[key] = value; }); - esm_default("okTurtles.data/set", PUBSUB_INSTANCE, createServer(httpServer, { - serverHandlers: { - connection(socket) { - const versionInfo = { - appVersion: cheloniaAppManifest?.appVersion || null, - contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( - Object.entries(cheloniaAppManifest?.contracts).map(([k, v2]) => [k, v2.version]) - ) : null - }; - socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)); - } - }, - socketHandlers: { - // The `close()` handler signals the server that the WS has been closed and - // that subsequent messages to subscribed channels should now be sent to its - // associated web push subscription, if it exists. - close() { - const socket = this; - const { server } = this; - const subscriptionId = socket.pushSubscriptionId; - if (!subscriptionId) return; - if (!server.pushSubscriptions[subscriptionId]) return; - server.pushSubscriptions[subscriptionId].sockets.delete(socket); - delete socket.pushSubscriptionId; - if (server.pushSubscriptions[subscriptionId].sockets.size === 0) { - server.pushSubscriptions[subscriptionId].subscriptions.forEach((channelID) => { - if (!server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); - } - server.subscribersByChannelID[channelID].add(server.pushSubscriptions[subscriptionId]); - }); - } - } - }, - messageHandlers: { - [REQUEST_TYPE.PUSH_ACTION]: async function({ data }) { - const socket = this; - const { action, payload } = data; - if (!action) { - socket.send(createPushErrorResponse({ message: "'action' field is required" })); - } - const handler = pushServerActionhandlers[action]; - if (handler) { - try { - await handler.call(socket, payload); - } catch (error2) { - const message = error2?.message || `push server failed to perform [${action}] action`; - console.warn(error2, `[${socket.ip}] Action '${action}' for '${REQUEST_TYPE.PUSH_ACTION}' handler failed: ${message}`); - socket.send(createPushErrorResponse({ actionType: action, message })); - } - } else { - socket.send(createPushErrorResponse({ message: `No handler for the '${action}' action` })); - } - }, - // This handler adds subscribed channels to the web push subscription - // associated with the WS, so that when the WS is closed we can continue - // sending messages as web push notifications. - [NOTIFICATION_TYPE.SUB]({ channelID }) { - const socket = this; - const { server } = this; - if (!socket.pushSubscriptionId) return; - if (!server.pushSubscriptions[socket.pushSubscriptionId]) { - delete socket.pushSubscriptionId; - return; - } - addChannelToSubscription(server, socket.pushSubscriptionId, channelID); - }, - // This handler removes subscribed channels from the web push subscription - // associated with the WS, so that when the WS is closed we don't send - // messages as web push notifications. - [NOTIFICATION_TYPE.UNSUB]({ channelID }) { - const socket = this; - const { server } = this; - if (!socket.pushSubscriptionId) return; - if (!server.pushSubscriptions[socket.pushSubscriptionId]) { - delete socket.pushSubscriptionId; - return; - } - deleteChannelFromSubscription(server, socket.pushSubscriptionId, channelID); + return headerData; + } + async parseBody(options2) { + return parseBody(this, options2); + } + #cachedBody = (key) => { + const { bodyCache, raw: raw2 } = this; + const cachedBody = bodyCache[key]; + if (cachedBody) { + return cachedBody; + } + const anyCachedKey = Object.keys(bodyCache)[0]; + if (anyCachedKey) { + return bodyCache[anyCachedKey].then((body) => { + if (anyCachedKey === "json") { + body = JSON.stringify(body); } - } - })); - (async function() { - await initDB(); - await ownerSizeTotalWorker?.ready; - await creditsWorker?.ready; - await esm_default("chelonia/configure", SERVER); - esm_default("chelonia.persistentActions/configure", { - databaseKey: "_private_persistent_actions" - }); - const savedStateIndex = await esm_default("chelonia.db/get", "_private_cheloniaState_index"); - if (savedStateIndex) { - const recoveredState = /* @__PURE__ */ Object.create(null); - recoveredState.contracts = /* @__PURE__ */ Object.create(null); - const channels = esm_default("okTurtles.data/get", PUBSUB_INSTANCE).channels; - await Promise.all(savedStateIndex.split("\0").map(async (contractID) => { - const cpSerialized = await esm_default("chelonia.db/get", `_private_cheloniaState_${contractID}`); - if (!cpSerialized) { - console.warn(`[server] missing state for contractID ${contractID} - skipping setup for this contract`); - return; - } - const cp = JSON.parse(cpSerialized); - recoveredState[contractID] = cp.contractState; - recoveredState.contracts[contractID] = cp.cheloniaContractInfo; - channels.add(contractID); - })); - Object.assign(esm_default("chelonia/rootState"), recoveredState); - } - const savedWebPushIndex = await esm_default("chelonia.db/get", "_private_webpush_index"); - if (savedWebPushIndex) { - const { pushSubscriptions, subscribersByChannelID } = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - await Promise.all(savedWebPushIndex.split("\0").map(async (subscriptionId) => { - const subscriptionSerialized = await esm_default("chelonia.db/get", `_private_webpush_${subscriptionId}`); - if (!subscriptionSerialized) { - console.warn(`[server] missing state for subscriptionId '${subscriptionId}' - skipping setup for this subscription`); - return; - } - const { settings, subscriptionInfo, channelIDs } = JSON.parse(subscriptionSerialized); - pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { channelIDs, settings }); - channelIDs.forEach((channelID) => { - if (!subscribersByChannelID[channelID]) subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); - subscribersByChannelID[channelID].add(pushSubscriptions[subscriptionId]); - }); - })); - } - esm_default("chelonia.persistentActions/load").catch((e2) => { - console.error(e2, "Error loading persistent actions"); - }); - await Promise.resolve().then(() => (init_routes(), routes_exports)); - const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; - const port = import_npm_nconf6.default.get("server:port") ?? 8e3; - httpServer.listen(port, host, () => { - const addr = httpServer.address(); - const uri = `http://${addr.address}:${addr.port}`; - console.info("Backend server running at:", uri); - esm_default("okTurtles.events/emit", SERVER_RUNNING, { info: { uri } }); + return new Response(body)[key](); }); - })(); - (() => { - const map = /* @__PURE__ */ new WeakMap(); - pushHeartbeatIntervalID = setInterval(() => { - const now = Date.now(); - const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - const notification = JSON.stringify({ type: "recurring" }); - Object.values(pubsub?.pushSubscriptions || {}).filter( - (pushSubscription) => !!pushSubscription.settings.heartbeatInterval && pushSubscription.sockets.size === 0 - ).forEach((pushSubscription) => { - const last = map.get(pushSubscription) ?? Number.NEGATIVE_INFINITY; - if (now - last < pushSubscription.settings.heartbeatInterval) return; - postEvent(pushSubscription, notification).then(() => { - map.set(pushSubscription, now); - }).catch((e2) => { - console.warn(e2, "Error sending recurring message to web push client", pushSubscription.id); - }); - }); - }, 1 * 60 * 60 * 1e3); - })(); + } + return bodyCache[key] = raw2[key](); + }; + /** + * `.json()` can parse Request body of type `application/json` + * + * @see {@link https://hono.dev/docs/api/request#json} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.json() + * }) + * ``` + */ + json() { + return this.#cachedBody("text").then((text) => JSON.parse(text)); + } + /** + * `.text()` can parse Request body of type `text/plain` + * + * @see {@link https://hono.dev/docs/api/request#text} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.text() + * }) + * ``` + */ + text() { + return this.#cachedBody("text"); + } + /** + * `.arrayBuffer()` parse Request body as an `ArrayBuffer` + * + * @see {@link https://hono.dev/docs/api/request#arraybuffer} + * + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.arrayBuffer() + * }) + * ``` + */ + arrayBuffer() { + return this.#cachedBody("arrayBuffer"); + } + /** + * Parses the request body as a `Blob`. + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.blob(); + * }); + * ``` + * @see https://hono.dev/docs/api/request#blob + */ + blob() { + return this.#cachedBody("blob"); + } + /** + * Parses the request body as `FormData`. + * @example + * ```ts + * app.post('/entry', async (c) => { + * const body = await c.req.formData(); + * }); + * ``` + * @see https://hono.dev/docs/api/request#formdata + */ + formData() { + return this.#cachedBody("formData"); + } + /** + * Adds validated data to the request. + * + * @param target - The target of the validation. + * @param data - The validated data to add. + */ + addValidatedData(target, data) { + this.#validatedData[target] = data; + } + valid(target) { + return this.#validatedData[target]; + } + /** + * `.url()` can get the request url strings. + * + * @see {@link https://hono.dev/docs/api/request#url} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const url = c.req.url // `http://localhost:8787/about/me` + * ... + * }) + * ``` + */ + get url() { + return this.raw.url; } -}); -var serve_exports = {}; -__export(serve_exports, { - default: () => serve_default, - removeSignalHandlers: () => removeSignalHandlers -}); -function logSBP(_domain, selector, data) { - if (!dontLog[selector]) { - if (selector === "backend/server/handleEntry") { - console.debug(import_npm_chalk4.default.bold(`[sbp] ${selector}`), data[0].description()); - } else { - console.debug(import_npm_chalk4.default.bold(`[sbp] ${selector}`), data); - } + /** + * `.method()` can get the method name of the request. + * + * @see {@link https://hono.dev/docs/api/request#method} + * + * @example + * ```ts + * app.get('/about/me', (c) => { + * const method = c.req.method // `GET` + * }) + * ``` + */ + get method() { + return this.raw.method; } -} -function removeSignalHandlers() { - for (const [signal, handler] of signalHandlers) { - process11.removeListener(signal, handler); + get [GET_MATCH_RESULT]() { + return this.#matchResult; } - signalHandlers.length = 0; -} -var import_npm_chalk4; -var dontLog; -var serve_default; -var exit2; -var signalHandlers; -var handleSignal; -var init_serve = __esm({ - "src/serve/index.ts"() { - "use strict"; - init_esm3(); - init_esm9(); - init_esm10(); - init_esm(); - import_npm_chalk4 = __toESM(require_source()); - init_events2(); - init_instance_keys(); - init_logger(); - console.info("NODE_ENV =", process11.env.NODE_ENV); - dontLog = { - "backend/server/broadcastEntry": true, - "backend/server/broadcastDeletion": true, - "backend/server/broadcastKV": true - }; - ["backend"].forEach((domain) => esm_default("sbp/filters/domain/add", domain, logSBP)); - [].forEach((sel) => esm_default("sbp/filters/selector/add", sel, logSBP)); - serve_default = () => new Promise((resolve82, reject) => { - esm_default("okTurtles.events/on", SERVER_RUNNING, function() { - console.info(import_npm_chalk4.default.bold("backend startup sequence complete.")); - resolve82(); - }); - init_server().then(() => server_exports).catch(reject); - }); - esm_default("okTurtles.events/once", SERVER_EXITING, () => { - esm_default("okTurtles.data/apply", PUBSUB_INSTANCE, function(pubsub) { - esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { - return new Promise((resolve82) => { - pubsub.on("close", async function() { - try { - removeSignalHandlers(); - await esm_default("chelonia.persistentActions/unload"); - await esm_default("backend/server/stop"); - console.info("Server down"); - } catch (err) { - console.error(err, "Error during shutdown"); - } finally { - resolve82(); - } - }); - pubsub.close(); - pubsub.clients.forEach((client) => client.terminate()); - }); - }); - }); - }); - process11.on("uncaughtException", (err) => { - console.error(err, "[server] Unhandled exception"); - process11.exit(1); - }); - process11.on("unhandledRejection", (reason) => { - console.error(reason, "[server] Unhandled promise rejection:", reason); - process11.exit(1); - }); - exit2 = (code2) => { - esm_default("okTurtles.events/once", SERVER_EXITING, () => { - esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { - process11.send?.({}); - process11.nextTick(() => process11.exit(code2)); - }); - }); - esm_default("okTurtles.events/emit", SERVER_EXITING); - }; - signalHandlers = []; - handleSignal = (signal, code2) => { - const handler = () => { - console.error(`Exiting upon receiving ${signal} (${code2})`); - exit2(128 + code2); - }; - signalHandlers.push([signal, handler]); - process11.on(signal, handler); - }; - [ - ["SIGHUP", 1], - ["SIGINT", 2], - ["SIGQUIT", 3], - ["SIGTERM", 15], - ["SIGUSR1", 10], - ["SIGUSR2", 11] - ].forEach(([signal, code2]) => handleSignal(signal, code2)); + /** + * `.matchedRoutes()` can return a matched route in the handler + * + * @deprecated + * + * Use matchedRoutes helper defined in "hono/route" instead. + * + * @see {@link https://hono.dev/docs/api/request#matchedroutes} + * + * @example + * ```ts + * app.use('*', async function logger(c, next) { + * await next() + * c.req.matchedRoutes.forEach(({ handler, method, path }, i) => { + * const name = handler.name || (handler.length < 2 ? '[handler]' : '[middleware]') + * console.log( + * method, + * ' ', + * path, + * ' '.repeat(Math.max(10 - path.length, 0)), + * name, + * i === c.req.routeIndex ? '<- respond from here' : '' + * ) + * }) + * }) + * ``` + */ + get matchedRoutes() { + return this.#matchResult[0].map(([[, route]]) => route); } -}); -init_esm(); -var import_npm_nconf7 = __toESM(require_nconf()); -function getLineColFromPtr(string3, ptr) { - let lines = string3.slice(0, ptr).split(/\r\n|\n|\r/g); - return [lines.length, lines.pop().length + 1]; -} -function makeCodeBlock(string3, line, column) { - let lines = string3.split(/\r\n|\n|\r/g); - let codeblock = ""; - let numberLen = (Math.log10(line + 1) | 0) + 1; - for (let i2 = line - 1; i2 <= line + 1; i2++) { - let l = lines[i2 - 1]; - if (!l) - continue; - codeblock += i2.toString().padEnd(numberLen, " "); - codeblock += ": "; - codeblock += l; - codeblock += "\n"; - if (i2 === line) { - codeblock += " ".repeat(numberLen + column + 2); - codeblock += "^\n"; + /** + * `routePath()` can retrieve the path registered within the handler + * + * @deprecated + * + * Use routePath helper defined in "hono/route" instead. + * + * @see {@link https://hono.dev/docs/api/request#routepath} + * + * @example + * ```ts + * app.get('/posts/:id', (c) => { + * return c.json({ path: c.req.routePath }) + * }) + * ``` + */ + get routePath() { + return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path; + } +}; +var HtmlEscapedCallbackPhase = { + Stringify: 1, + BeforeStream: 2, + Stream: 3 +}; +var raw = (value, callbacks) => { + const escapedString = new String(value); + escapedString.isEscaped = true; + escapedString.callbacks = callbacks; + return escapedString; +}; +var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => { + if (typeof str === "object" && !(str instanceof String)) { + if (!(str instanceof Promise)) { + str = str.toString(); + } + if (str instanceof Promise) { + str = await str; } } - return codeblock; -} -var TomlError = class extends Error { - line; - column; - codeblock; - constructor(message, options2) { - const [line, column] = getLineColFromPtr(options2.toml, options2.ptr); - const codeblock = makeCodeBlock(options2.toml, line, column); - super(`Invalid TOML document: ${message} - -${codeblock}`, options2); - this.line = line; - this.column = column; - this.codeblock = codeblock; + const callbacks = str.callbacks; + if (!callbacks?.length) { + return Promise.resolve(str); + } + if (buffer) { + buffer[0] += str; + } else { + buffer = [str]; + } + const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then( + (res) => Promise.all( + res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer)) + ).then(() => buffer[0]) + ); + if (preserveCallbacks) { + return raw(await resStr, callbacks); + } else { + return resStr; } }; -function isEscaped(str, ptr) { - let i2 = 0; - while (str[ptr - ++i2] === "\\") - ; - return --i2 && i2 % 2; -} -function indexOfNewline(str, start = 0, end = str.length) { - let idx = str.indexOf("\n", start); - if (str[idx - 1] === "\r") - idx--; - return idx <= end ? idx : -1; -} -function skipComment(str, ptr) { - for (let i2 = ptr; i2 < str.length; i2++) { - let c = str[i2]; - if (c === "\n") - return i2; - if (c === "\r" && str[i2 + 1] === "\n") - return i2 + 1; - if (c < " " && c !== " " || c === "\x7F") { - throw new TomlError("control characters are not allowed in comments", { - toml: str, - ptr - }); +var TEXT_PLAIN = "text/plain; charset=UTF-8"; +var setDefaultContentType = (contentType, headers) => { + return { + "Content-Type": contentType, + ...headers + }; +}; +var createResponseInstance = (body, init2) => new Response(body, init2); +var Context = class { + #rawRequest; + #req; + /** + * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers. + * + * @see {@link https://hono.dev/docs/api/context#env} + * + * @example + * ```ts + * // Environment object for Cloudflare Workers + * app.get('*', async c => { + * const counter = c.env.COUNTER + * }) + * ``` + */ + env = {}; + #var; + finalized = false; + /** + * `.error` can get the error object from the middleware if the Handler throws an error. + * + * @see {@link https://hono.dev/docs/api/context#error} + * + * @example + * ```ts + * app.use('*', async (c, next) => { + * await next() + * if (c.error) { + * // do something... + * } + * }) + * ``` + */ + error; + #status; + #executionCtx; + #res; + #layout; + #renderer; + #notFoundHandler; + #preparedHeaders; + #matchResult; + #path; + /** + * Creates an instance of the Context class. + * + * @param req - The Request object. + * @param options - Optional configuration options for the context. + */ + constructor(req, options2) { + this.#rawRequest = req; + if (options2) { + this.#executionCtx = options2.executionCtx; + this.env = options2.env; + this.#notFoundHandler = options2.notFoundHandler; + this.#path = options2.path; + this.#matchResult = options2.matchResult; } } - return str.length; -} -function skipVoid(str, ptr, banNewLines, banComments) { - let c; - while ((c = str[ptr]) === " " || c === " " || !banNewLines && (c === "\n" || c === "\r" && str[ptr + 1] === "\n")) - ptr++; - return banComments || c !== "#" ? ptr : skipVoid(str, skipComment(str, ptr), banNewLines); -} -function skipUntil(str, ptr, sep, end, banNewLines = false) { - if (!end) { - ptr = indexOfNewline(str, ptr); - return ptr < 0 ? str.length : ptr; + /** + * `.req` is the instance of {@link HonoRequest}. + */ + get req() { + this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult); + return this.#req; } - for (let i2 = ptr; i2 < str.length; i2++) { - let c = str[i2]; - if (c === "#") { - i2 = indexOfNewline(str, i2); - } else if (c === sep) { - return i2 + 1; - } else if (c === end || banNewLines && (c === "\n" || c === "\r" && str[i2 + 1] === "\n")) { - return i2; + /** + * @see {@link https://hono.dev/docs/api/context#event} + * The FetchEvent associated with the current request. + * + * @throws Will throw an error if the context does not have a FetchEvent. + */ + get event() { + if (this.#executionCtx && "respondWith" in this.#executionCtx) { + return this.#executionCtx; + } else { + throw Error("This context has no FetchEvent"); } } - throw new TomlError("cannot find end of structure", { - toml: str, - ptr - }); -} -function getStringEnd(str, seek) { - let first = str[seek]; - let target = first === str[seek + 1] && str[seek + 1] === str[seek + 2] ? str.slice(seek, seek + 3) : first; - seek += target.length - 1; - do - seek = str.indexOf(target, ++seek); - while (seek > -1 && first !== "'" && isEscaped(str, seek)); - if (seek > -1) { - seek += target.length; - if (target.length > 1) { - if (str[seek] === first) - seek++; - if (str[seek] === first) - seek++; + /** + * @see {@link https://hono.dev/docs/api/context#executionctx} + * The ExecutionContext associated with the current request. + * + * @throws Will throw an error if the context does not have an ExecutionContext. + */ + get executionCtx() { + if (this.#executionCtx) { + return this.#executionCtx; + } else { + throw Error("This context has no ExecutionContext"); } } - return seek; -} -var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}:\d{2}(?:\.\d+)?)?(Z|[-+]\d{2}:\d{2})?$/i; -var TomlDate = class _TomlDate extends Date { - #hasDate = false; - #hasTime = false; - #offset = null; - constructor(date3) { - let hasDate = true; - let hasTime = true; - let offset = "Z"; - if (typeof date3 === "string") { - let match2 = date3.match(DATE_TIME_RE); - if (match2) { - if (!match2[1]) { - hasDate = false; - date3 = `0000-01-01T${date3}`; + /** + * @see {@link https://hono.dev/docs/api/context#res} + * The Response object for the current request. + */ + get res() { + return this.#res ||= createResponseInstance(null, { + headers: this.#preparedHeaders ??= new Headers() + }); + } + /** + * Sets the Response object for the current request. + * + * @param _res - The Response object to set. + */ + set res(_res) { + if (this.#res && _res) { + _res = createResponseInstance(_res.body, _res); + for (const [k, v2] of this.#res.headers.entries()) { + if (k === "content-type") { + continue; } - hasTime = !!match2[2]; - hasTime && date3[10] === " " && (date3 = date3.replace(" ", "T")); - if (match2[2] && +match2[2] > 23) { - date3 = ""; + if (k === "set-cookie") { + const cookies = this.#res.headers.getSetCookie(); + _res.headers.delete("set-cookie"); + for (const cookie of cookies) { + _res.headers.append("set-cookie", cookie); + } } else { - offset = match2[3] || null; - date3 = date3.toUpperCase(); - if (!offset && hasTime) - date3 += "Z"; + _res.headers.set(k, v2); } - } else { - date3 = ""; } } - super(date3); - if (!isNaN(this.getTime())) { - this.#hasDate = hasDate; - this.#hasTime = hasTime; - this.#offset = offset; + this.#res = _res; + this.finalized = true; + } + /** + * `.render()` can create a response within a layout. + * + * @see {@link https://hono.dev/docs/api/context#render-setrenderer} + * + * @example + * ```ts + * app.get('/', (c) => { + * return c.render('Hello!') + * }) + * ``` + */ + render = (...args) => { + this.#renderer ??= (content) => this.html(content); + return this.#renderer(...args); + }; + /** + * Sets the layout for the response. + * + * @param layout - The layout to set. + * @returns The layout function. + */ + setLayout = (layout) => this.#layout = layout; + /** + * Gets the current layout for the response. + * + * @returns The current layout function. + */ + getLayout = () => this.#layout; + /** + * `.setRenderer()` can set the layout in the custom middleware. + * + * @see {@link https://hono.dev/docs/api/context#render-setrenderer} + * + * @example + * ```tsx + * app.use('*', async (c, next) => { + * c.setRenderer((content) => { + * return c.html( + * + * + *

{content}

+ * + * + * ) + * }) + * await next() + * }) + * ``` + */ + setRenderer = (renderer) => { + this.#renderer = renderer; + }; + /** + * `.header()` can set headers. + * + * @see {@link https://hono.dev/docs/api/context#header} + * + * @example + * ```ts + * app.get('/welcome', (c) => { + * // Set headers + * c.header('X-Message', 'Hello!') + * c.header('Content-Type', 'text/plain') + * + * return c.body('Thank you for coming') + * }) + * ``` + */ + header = (name, value, options2) => { + if (this.finalized) { + this.#res = createResponseInstance(this.#res.body, this.#res); + } + const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers(); + if (value === void 0) { + headers.delete(name); + } else if (options2?.append) { + headers.append(name, value); + } else { + headers.set(name, value); + } + }; + status = (status) => { + this.#status = status; + }; + /** + * `.set()` can set the value specified by the key. + * + * @see {@link https://hono.dev/docs/api/context#set-get} + * + * @example + * ```ts + * app.use('*', async (c, next) => { + * c.set('message', 'Hono is hot!!') + * await next() + * }) + * ``` + */ + set = (key, value) => { + this.#var ??= /* @__PURE__ */ new Map(); + this.#var.set(key, value); + }; + /** + * `.get()` can use the value specified by the key. + * + * @see {@link https://hono.dev/docs/api/context#set-get} + * + * @example + * ```ts + * app.get('/', (c) => { + * const message = c.get('message') + * return c.text(`The message is "${message}"`) + * }) + * ``` + */ + get = (key) => { + return this.#var ? this.#var.get(key) : void 0; + }; + /** + * `.var` can access the value of a variable. + * + * @see {@link https://hono.dev/docs/api/context#var} + * + * @example + * ```ts + * const result = c.var.client.oneMethod() + * ``` + */ + // c.var.propName is a read-only + get var() { + if (!this.#var) { + return {}; } + return Object.fromEntries(this.#var); } - isDateTime() { - return this.#hasDate && this.#hasTime; + #newResponse(data, arg, headers) { + const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers(); + if (typeof arg === "object" && "headers" in arg) { + const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers); + for (const [key, value] of argHeaders) { + if (key.toLowerCase() === "set-cookie") { + responseHeaders.append(key, value); + } else { + responseHeaders.set(key, value); + } + } + } + if (headers) { + for (const [k, v2] of Object.entries(headers)) { + if (typeof v2 === "string") { + responseHeaders.set(k, v2); + } else { + responseHeaders.delete(k); + for (const v22 of v2) { + responseHeaders.append(k, v22); + } + } + } + } + const status = typeof arg === "number" ? arg : arg?.status ?? this.#status; + return createResponseInstance(data, { status, headers: responseHeaders }); } - isLocal() { - return !this.#hasDate || !this.#hasTime || !this.#offset; + newResponse = (...args) => this.#newResponse(...args); + /** + * `.body()` can return the HTTP response. + * You can set headers with `.header()` and set HTTP status code with `.status`. + * This can also be set in `.text()`, `.json()` and so on. + * + * @see {@link https://hono.dev/docs/api/context#body} + * + * @example + * ```ts + * app.get('/welcome', (c) => { + * // Set headers + * c.header('X-Message', 'Hello!') + * c.header('Content-Type', 'text/plain') + * // Set HTTP status code + * c.status(201) + * + * // Return the response body + * return c.body('Thank you for coming') + * }) + * ``` + */ + body = (data, arg, headers) => this.#newResponse(data, arg, headers); + /** + * `.text()` can render text as `Content-Type:text/plain`. + * + * @see {@link https://hono.dev/docs/api/context#text} + * + * @example + * ```ts + * app.get('/say', (c) => { + * return c.text('Hello!') + * }) + * ``` + */ + text = (text, arg, headers) => { + return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse( + text, + arg, + setDefaultContentType(TEXT_PLAIN, headers) + ); + }; + /** + * `.json()` can render JSON as `Content-Type:application/json`. + * + * @see {@link https://hono.dev/docs/api/context#json} + * + * @example + * ```ts + * app.get('/api', (c) => { + * return c.json({ message: 'Hello!' }) + * }) + * ``` + */ + json = (object2, arg, headers) => { + return this.#newResponse( + JSON.stringify(object2), + arg, + setDefaultContentType("application/json", headers) + ); + }; + html = (html2, arg, headers) => { + const res = (html22) => this.#newResponse(html22, arg, setDefaultContentType("text/html; charset=UTF-8", headers)); + return typeof html2 === "object" ? resolveCallback(html2, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html2); + }; + /** + * `.redirect()` can Redirect, default status code is 302. + * + * @see {@link https://hono.dev/docs/api/context#redirect} + * + * @example + * ```ts + * app.get('/redirect', (c) => { + * return c.redirect('/') + * }) + * app.get('/redirect-permanently', (c) => { + * return c.redirect('/', 301) + * }) + * ``` + */ + redirect = (location, status) => { + const locationString = String(location); + this.header( + "Location", + // Multibyes should be encoded + // eslint-disable-next-line no-control-regex + !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString) + ); + return this.newResponse(null, status ?? 302); + }; + /** + * `.notFound()` can return the Not Found Response. + * + * @see {@link https://hono.dev/docs/api/context#notfound} + * + * @example + * ```ts + * app.get('/notfound', (c) => { + * return c.notFound() + * }) + * ``` + */ + notFound = () => { + this.#notFoundHandler ??= () => createResponseInstance(); + return this.#notFoundHandler(this); + }; +}; +var METHOD_NAME_ALL = "ALL"; +var METHOD_NAME_ALL_LOWERCASE = "all"; +var METHODS = ["get", "post", "put", "delete", "options", "patch"]; +var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built."; +var UnsupportedPathError = class extends Error { +}; +var COMPOSED_HANDLER = "__COMPOSED_HANDLER"; +var notFoundHandler = (c) => { + return c.text("404 Not Found", 404); +}; +var errorHandler = (err, c) => { + if ("getResponse" in err) { + const res = err.getResponse(); + return c.newResponse(res.body, res); } - isDate() { - return this.#hasDate && !this.#hasTime; + console.error(err); + return c.text("Internal Server Error", 500); +}; +var Hono = class _Hono { + get; + post; + put; + delete; + options; + patch; + all; + on; + use; + /* + This class is like an abstract class and does not have a router. + To use it, inherit the class and implement router in the constructor. + */ + router; + getPath; + // Cannot use `#` because it requires visibility at JavaScript runtime. + _basePath = "/"; + #path = "/"; + routes = []; + constructor(options2 = {}) { + const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE]; + allMethods.forEach((method) => { + this[method] = (args1, ...args) => { + if (typeof args1 === "string") { + this.#path = args1; + } else { + this.#addRoute(method, this.#path, args1); + } + args.forEach((handler) => { + this.#addRoute(method, this.#path, handler); + }); + return this; + }; + }); + this.on = (method, path8, ...handlers) => { + for (const p of [path8].flat()) { + this.#path = p; + for (const m3 of [method].flat()) { + handlers.map((handler) => { + this.#addRoute(m3.toUpperCase(), this.#path, handler); + }); + } + } + return this; + }; + this.use = (arg1, ...handlers) => { + if (typeof arg1 === "string") { + this.#path = arg1; + } else { + this.#path = "*"; + handlers.unshift(arg1); + } + handlers.forEach((handler) => { + this.#addRoute(METHOD_NAME_ALL, this.#path, handler); + }); + return this; + }; + const { strict, ...optionsWithoutStrict } = options2; + Object.assign(this, optionsWithoutStrict); + this.getPath = strict ?? true ? options2.getPath ?? getPath : getPathNoStrict; } - isTime() { - return this.#hasTime && !this.#hasDate; + #clone() { + const clone2 = new _Hono({ + router: this.router, + getPath: this.getPath + }); + clone2.errorHandler = this.errorHandler; + clone2.#notFoundHandler = this.#notFoundHandler; + clone2.routes = this.routes; + return clone2; + } + #notFoundHandler = notFoundHandler; + // Cannot use `#` because it requires visibility at JavaScript runtime. + errorHandler = errorHandler; + /** + * `.route()` allows grouping other Hono instance in routes. + * + * @see {@link https://hono.dev/docs/api/routing#grouping} + * + * @param {string} path - base Path + * @param {Hono} app - other Hono instance + * @returns {Hono} routed Hono instance + * + * @example + * ```ts + * const app = new Hono() + * const app2 = new Hono() + * + * app2.get("/user", (c) => c.text("user")) + * app.route("/api", app2) // GET /api/user + * ``` + */ + route(path8, app2) { + const subApp = this.basePath(path8); + app2.routes.map((r) => { + let handler; + if (app2.errorHandler === errorHandler) { + handler = r.handler; + } else { + handler = async (c, next) => (await compose([], app2.errorHandler)(c, () => r.handler(c, next))).res; + handler[COMPOSED_HANDLER] = r.handler; + } + subApp.#addRoute(r.method, r.path, handler); + }); + return this; } - isValid() { - return this.#hasDate || this.#hasTime; + /** + * `.basePath()` allows base paths to be specified. + * + * @see {@link https://hono.dev/docs/api/routing#base-path} + * + * @param {string} path - base Path + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * const api = new Hono().basePath('/api') + * ``` + */ + basePath(path8) { + const subApp = this.#clone(); + subApp._basePath = mergePath(this._basePath, path8); + return subApp; } - toISOString() { - let iso = super.toISOString(); - if (this.isDate()) - return iso.slice(0, 10); - if (this.isTime()) - return iso.slice(11, 23); - if (this.#offset === null) - return iso.slice(0, -1); - if (this.#offset === "Z") - return iso; - let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6); - offset = this.#offset[0] === "-" ? offset : -offset; - let offsetDate = new Date(this.getTime() - offset * 6e4); - return offsetDate.toISOString().slice(0, -1) + this.#offset; + /** + * `.onError()` handles an error and returns a customized Response. + * + * @see {@link https://hono.dev/docs/api/hono#error-handling} + * + * @param {ErrorHandler} handler - request Handler for error + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * app.onError((err, c) => { + * console.error(`${err}`) + * return c.text('Custom Error Message', 500) + * }) + * ``` + */ + onError = (handler) => { + this.errorHandler = handler; + return this; + }; + /** + * `.notFound()` allows you to customize a Not Found Response. + * + * @see {@link https://hono.dev/docs/api/hono#not-found} + * + * @param {NotFoundHandler} handler - request handler for not-found + * @returns {Hono} changed Hono instance + * + * @example + * ```ts + * app.notFound((c) => { + * return c.text('Custom 404 Message', 404) + * }) + * ``` + */ + notFound = (handler) => { + this.#notFoundHandler = handler; + return this; + }; + /** + * `.mount()` allows you to mount applications built with other frameworks into your Hono application. + * + * @see {@link https://hono.dev/docs/api/hono#mount} + * + * @param {string} path - base Path + * @param {Function} applicationHandler - other Request Handler + * @param {MountOptions} [options] - options of `.mount()` + * @returns {Hono} mounted Hono instance + * + * @example + * ```ts + * import { Router as IttyRouter } from 'itty-router' + * import { Hono } from 'hono' + * // Create itty-router application + * const ittyRouter = IttyRouter() + * // GET /itty-router/hello + * ittyRouter.get('/hello', () => new Response('Hello from itty-router')) + * + * const app = new Hono() + * app.mount('/itty-router', ittyRouter.handle) + * ``` + * + * @example + * ```ts + * const app = new Hono() + * // Send the request to another application without modification. + * app.mount('/app', anotherApp, { + * replaceRequest: (req) => req, + * }) + * ``` + */ + mount(path8, applicationHandler, options2) { + let replaceRequest; + let optionHandler; + if (options2) { + if (typeof options2 === "function") { + optionHandler = options2; + } else { + optionHandler = options2.optionHandler; + if (options2.replaceRequest === false) { + replaceRequest = (request) => request; + } else { + replaceRequest = options2.replaceRequest; + } + } + } + const getOptions = optionHandler ? (c) => { + const options22 = optionHandler(c); + return Array.isArray(options22) ? options22 : [options22]; + } : (c) => { + let executionContext = void 0; + try { + executionContext = c.executionCtx; + } catch { + } + return [c.env, executionContext]; + }; + replaceRequest ||= (() => { + const mergedPath = mergePath(this._basePath, path8); + const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length; + return (request) => { + const url2 = new URL(request.url); + url2.pathname = url2.pathname.slice(pathPrefixLength) || "/"; + return new Request(url2, request); + }; + })(); + const handler = async (c, next) => { + const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c)); + if (res) { + return res; + } + await next(); + }; + this.#addRoute(METHOD_NAME_ALL, mergePath(path8, "*"), handler); + return this; } - static wrapAsOffsetDateTime(jsDate, offset = "Z") { - let date3 = new _TomlDate(jsDate); - date3.#offset = offset; - return date3; + #addRoute(method, path8, handler) { + method = method.toUpperCase(); + path8 = mergePath(this._basePath, path8); + const r = { basePath: this._basePath, path: path8, method, handler }; + this.router.add(method, path8, [handler, r]); + this.routes.push(r); } - static wrapAsLocalDateTime(jsDate) { - let date3 = new _TomlDate(jsDate); - date3.#offset = null; - return date3; + #handleError(err, c) { + if (err instanceof Error) { + return this.errorHandler(err, c); + } + throw err; + } + #dispatch(request, executionCtx, env2, method) { + if (method === "HEAD") { + return (async () => new Response(null, await this.#dispatch(request, executionCtx, env2, "GET")))(); + } + const path8 = this.getPath(request, { env: env2 }); + const matchResult = this.router.match(method, path8); + const c = new Context(request, { + path: path8, + matchResult, + env: env2, + executionCtx, + notFoundHandler: this.#notFoundHandler + }); + if (matchResult[0].length === 1) { + let res; + try { + res = matchResult[0][0][0][0](c, async () => { + c.res = await this.#notFoundHandler(c); + }); + } catch (err) { + return this.#handleError(err, c); + } + return res instanceof Promise ? res.then( + (resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c)) + ).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c); + } + const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler); + return (async () => { + try { + const context = await composed(c); + if (!context.finalized) { + throw new Error( + "Context is not finalized. Did you forget to return a Response object or `await next()`?" + ); + } + return context.res; + } catch (err) { + return this.#handleError(err, c); + } + })(); + } + /** + * `.fetch()` will be entry point of your app. + * + * @see {@link https://hono.dev/docs/api/hono#fetch} + * + * @param {Request} request - request Object of request + * @param {Env} Env - env Object + * @param {ExecutionContext} - context of execution + * @returns {Response | Promise} response of request + * + */ + fetch = (request, ...rest) => { + return this.#dispatch(request, rest[1], rest[0], request.method); + }; + /** + * `.request()` is a useful method for testing. + * You can pass a URL or pathname to send a GET request. + * app will return a Response object. + * ```ts + * test('GET /hello is ok', async () => { + * const res = await app.request('/hello') + * expect(res.status).toBe(200) + * }) + * ``` + * @see https://hono.dev/docs/api/hono#request + */ + request = (input, requestInit, Env, executionCtx) => { + if (input instanceof Request) { + return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx); + } + input = input.toString(); + return this.fetch( + new Request( + /^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, + requestInit + ), + Env, + executionCtx + ); + }; + /** + * `.fire()` automatically adds a global fetch event listener. + * This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers. + * @deprecated + * Use `fire` from `hono/service-worker` instead. + * ```ts + * import { Hono } from 'hono' + * import { fire } from 'hono/service-worker' + * + * const app = new Hono() + * // ... + * fire(app) + * ``` + * @see https://hono.dev/docs/api/hono#fire + * @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API + * @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/ + */ + fire = () => { + addEventListener("fetch", (event) => { + event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method)); + }); + }; +}; +var emptyParam = []; +function match(method, path8) { + const matchers = this.buildAllMatchers(); + const match2 = (method2, path22) => { + const matcher = matchers[method2] || matchers[METHOD_NAME_ALL]; + const staticMatch = matcher[2][path22]; + if (staticMatch) { + return staticMatch; + } + const match3 = path22.match(matcher[0]); + if (!match3) { + return [[], emptyParam]; + } + const index = match3.indexOf("", 1); + return [matcher[1][index], match3]; + }; + this.match = match2; + return match2(method, path8); +} +var LABEL_REG_EXP_STR = "[^/]+"; +var ONLY_WILDCARD_REG_EXP_STR = ".*"; +var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)"; +var PATH_ERROR = /* @__PURE__ */ Symbol(); +var regExpMetaChars = new Set(".\\+*[^]$()"); +function compareKey(a, b) { + if (a.length === 1) { + return b.length === 1 ? a < b ? -1 : 1 : -1; } - static wrapAsLocalDate(jsDate) { - let date3 = new _TomlDate(jsDate); - date3.#hasTime = false; - date3.#offset = null; - return date3; + if (b.length === 1) { + return 1; } - static wrapAsLocalTime(jsDate) { - let date3 = new _TomlDate(jsDate); - date3.#hasDate = false; - date3.#offset = null; - return date3; + if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) { + return 1; + } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) { + return -1; } -}; -var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/; -var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/; -var LEADING_ZERO = /^[+-]?0[0-9_]/; -var ESCAPE_REGEX = /^[0-9a-f]{4,8}$/i; -var ESC_MAP = { - b: "\b", - t: " ", - n: "\n", - f: "\f", - r: "\r", - '"': '"', - "\\": "\\" -}; -function parseString(str, ptr = 0, endPtr = str.length) { - let isLiteral = str[ptr] === "'"; - let isMultiline = str[ptr++] === str[ptr] && str[ptr] === str[ptr + 1]; - if (isMultiline) { - endPtr -= 2; - if (str[ptr += 2] === "\r") - ptr++; - if (str[ptr] === "\n") - ptr++; + if (a === LABEL_REG_EXP_STR) { + return 1; + } else if (b === LABEL_REG_EXP_STR) { + return -1; } - let tmp = 0; - let isEscape; - let parsed = ""; - let sliceStart = ptr; - while (ptr < endPtr - 1) { - let c = str[ptr++]; - if (c === "\n" || c === "\r" && str[ptr] === "\n") { - if (!isMultiline) { - throw new TomlError("newlines are not allowed in strings", { - toml: str, - ptr: ptr - 1 - }); + return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length; +} +var Node = class _Node { + #index; + #varIndex; + #children = /* @__PURE__ */ Object.create(null); + insert(tokens, index, paramMap, context, pathErrorCheckOnly) { + if (tokens.length === 0) { + if (this.#index !== void 0) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; } - } else if (c < " " && c !== " " || c === "\x7F") { - throw new TomlError("control characters are not allowed in strings", { - toml: str, - ptr: ptr - 1 - }); + this.#index = index; + return; } - if (isEscape) { - isEscape = false; - if (c === "u" || c === "U") { - let code2 = str.slice(ptr, ptr += c === "u" ? 4 : 8); - if (!ESCAPE_REGEX.test(code2)) { - throw new TomlError("invalid unicode escape", { - toml: str, - ptr: tmp - }); + const [token, ...restTokens] = tokens; + const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/); + let node; + if (pattern) { + const name = pattern[1]; + let regexpStr = pattern[2] || LABEL_REG_EXP_STR; + if (name && pattern[2]) { + if (regexpStr === ".*") { + throw PATH_ERROR; + } + regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:"); + if (/\((?!\?:)/.test(regexpStr)) { + throw PATH_ERROR; + } + } + node = this.#children[regexpStr]; + if (!node) { + if (Object.keys(this.#children).some( + (k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR + )) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; } - try { - parsed += String.fromCodePoint(parseInt(code2, 16)); - } catch { - throw new TomlError("invalid unicode escape", { - toml: str, - ptr: tmp - }); + node = this.#children[regexpStr] = new _Node(); + if (name !== "") { + node.#varIndex = context.varIndex++; } - } else if (isMultiline && (c === "\n" || c === " " || c === " " || c === "\r")) { - ptr = skipVoid(str, ptr - 1, true); - if (str[ptr] !== "\n" && str[ptr] !== "\r") { - throw new TomlError("invalid escape: only line-ending whitespace may be escaped", { - toml: str, - ptr: tmp - }); + } + if (!pathErrorCheckOnly && name !== "") { + paramMap.push([name, node.#varIndex]); + } + } else { + node = this.#children[token]; + if (!node) { + if (Object.keys(this.#children).some( + (k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR + )) { + throw PATH_ERROR; + } + if (pathErrorCheckOnly) { + return; } - ptr = skipVoid(str, ptr); - } else if (c in ESC_MAP) { - parsed += ESC_MAP[c]; - } else { - throw new TomlError("unrecognized escape sequence", { - toml: str, - ptr: tmp - }); + node = this.#children[token] = new _Node(); } - sliceStart = ptr; - } else if (!isLiteral && c === "\\") { - tmp = ptr - 1; - isEscape = true; - parsed += str.slice(sliceStart, tmp); } + node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly); } - return parsed + str.slice(sliceStart, endPtr - 1); -} -function parseValue(value, toml, ptr, integersAsBigInt) { - if (value === "true") - return true; - if (value === "false") - return false; - if (value === "-inf") - return -Infinity; - if (value === "inf" || value === "+inf") - return Infinity; - if (value === "nan" || value === "+nan" || value === "-nan") - return NaN; - if (value === "-0") - return integersAsBigInt ? 0n : 0; - let isInt = INT_REGEX.test(value); - if (isInt || FLOAT_REGEX.test(value)) { - if (LEADING_ZERO.test(value)) { - throw new TomlError("leading zeroes are not allowed", { - toml, - ptr - }); + buildRegExpStr() { + const childKeys = Object.keys(this.#children).sort(compareKey); + const strList = childKeys.map((k) => { + const c = this.#children[k]; + return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr(); + }); + if (typeof this.#index === "number") { + strList.unshift(`#${this.#index}`); } - value = value.replace(/_/g, ""); - let numeric = +value; - if (isNaN(numeric)) { - throw new TomlError("invalid number", { - toml, - ptr + if (strList.length === 0) { + return ""; + } + if (strList.length === 1) { + return strList[0]; + } + return "(?:" + strList.join("|") + ")"; + } +}; +var Trie = class { + #context = { varIndex: 0 }; + #root = new Node(); + insert(path8, index, pathErrorCheckOnly) { + const paramAssoc = []; + const groups = []; + for (let i2 = 0; ; ) { + let replaced = false; + path8 = path8.replace(/\{[^}]+\}/g, (m3) => { + const mark = `@\\${i2}`; + groups[i2] = [mark, m3]; + i2++; + replaced = true; + return mark; }); + if (!replaced) { + break; + } } - if (isInt) { - if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) { - throw new TomlError("integer value cannot be represented losslessly", { - toml, - ptr - }); + const tokens = path8.match(/(?::[^\/]+)|(?:\/\*$)|./g) || []; + for (let i2 = groups.length - 1; i2 >= 0; i2--) { + const [mark] = groups[i2]; + for (let j = tokens.length - 1; j >= 0; j--) { + if (tokens[j].indexOf(mark) !== -1) { + tokens[j] = tokens[j].replace(mark, groups[i2][1]); + break; + } } - if (isInt || integersAsBigInt === true) - numeric = BigInt(value); } - return numeric; + this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly); + return paramAssoc; } - const date3 = new TomlDate(value); - if (!date3.isValid()) { - throw new TomlError("invalid value", { - toml, - ptr + buildRegExp() { + let regexp = this.#root.buildRegExpStr(); + if (regexp === "") { + return [/^$/, [], []]; + } + let captureIndex = 0; + const indexReplacementMap = []; + const paramReplacementMap = []; + regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => { + if (handlerIndex !== void 0) { + indexReplacementMap[++captureIndex] = Number(handlerIndex); + return "$()"; + } + if (paramIndex !== void 0) { + paramReplacementMap[Number(paramIndex)] = ++captureIndex; + return ""; + } + return ""; }); + return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap]; } - return date3; +}; +var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)]; +var wildcardRegExpCache = /* @__PURE__ */ Object.create(null); +function buildWildcardRegExp(path8) { + return wildcardRegExpCache[path8] ??= new RegExp( + path8 === "*" ? "" : `^${path8.replace( + /\/\*$|([.\\+*[^\]$()])/g, + (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)" + )}$` + ); } -function sliceAndTrimEndOf(str, startPtr, endPtr, allowNewLines) { - let value = str.slice(startPtr, endPtr); - let commentIdx = value.indexOf("#"); - if (commentIdx > -1) { - skipComment(str, commentIdx); - value = value.slice(0, commentIdx); +function clearWildcardRegExpCache() { + wildcardRegExpCache = /* @__PURE__ */ Object.create(null); +} +function buildMatcherFromPreprocessedRoutes(routes) { + const trie = new Trie(); + const handlerData = []; + if (routes.length === 0) { + return nullMatcher; } - let trimmed = value.trimEnd(); - if (!allowNewLines) { - let newlineIdx = value.indexOf("\n", trimmed.length); - if (newlineIdx > -1) { - throw new TomlError("newlines are not allowed in inline tables", { - toml: str, - ptr: startPtr + newlineIdx - }); + const routesWithStaticPathFlag = routes.map( + (route) => [!/\*|\/:/.test(route[0]), ...route] + ).sort( + ([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length + ); + const staticMap = /* @__PURE__ */ Object.create(null); + for (let i2 = 0, j = -1, len = routesWithStaticPathFlag.length; i2 < len; i2++) { + const [pathErrorCheckOnly, path8, handlers] = routesWithStaticPathFlag[i2]; + if (pathErrorCheckOnly) { + staticMap[path8] = [handlers.map(([h2]) => [h2, /* @__PURE__ */ Object.create(null)]), emptyParam]; + } else { + j++; } - } - return [trimmed, commentIdx]; -} -function extractValue(str, ptr, end, depth, integersAsBigInt) { - if (depth === 0) { - throw new TomlError("document contains excessively nested structures. aborting.", { - toml: str, - ptr + let paramAssoc; + try { + paramAssoc = trie.insert(path8, j, pathErrorCheckOnly); + } catch (e2) { + throw e2 === PATH_ERROR ? new UnsupportedPathError(path8) : e2; + } + if (pathErrorCheckOnly) { + continue; + } + handlerData[j] = handlers.map(([h2, paramCount]) => { + const paramIndexMap = /* @__PURE__ */ Object.create(null); + paramCount -= 1; + for (; paramCount >= 0; paramCount--) { + const [key, value] = paramAssoc[paramCount]; + paramIndexMap[key] = value; + } + return [h2, paramIndexMap]; }); } - let c = str[ptr]; - if (c === "[" || c === "{") { - let [value, endPtr2] = c === "[" ? parseArray(str, ptr, depth, integersAsBigInt) : parseInlineTable(str, ptr, depth, integersAsBigInt); - let newPtr = end ? skipUntil(str, endPtr2, ",", end) : endPtr2; - if (endPtr2 - newPtr && end === "}") { - let nextNewLine = indexOfNewline(str, endPtr2, newPtr); - if (nextNewLine > -1) { - throw new TomlError("newlines are not allowed in inline tables", { - toml: str, - ptr: nextNewLine - }); + const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp(); + for (let i2 = 0, len = handlerData.length; i2 < len; i2++) { + for (let j = 0, len2 = handlerData[i2].length; j < len2; j++) { + const map = handlerData[i2][j]?.[1]; + if (!map) { + continue; + } + const keys = Object.keys(map); + for (let k = 0, len3 = keys.length; k < len3; k++) { + map[keys[k]] = paramReplacementMap[map[keys[k]]]; } } - return [value, newPtr]; } - let endPtr; - if (c === '"' || c === "'") { - endPtr = getStringEnd(str, ptr); - let parsed = parseString(str, ptr, endPtr); - if (end) { - endPtr = skipVoid(str, endPtr, end !== "]"); - if (str[endPtr] && str[endPtr] !== "," && str[endPtr] !== end && str[endPtr] !== "\n" && str[endPtr] !== "\r") { - throw new TomlError("unexpected character encountered", { - toml: str, - ptr: endPtr + const handlerMap = []; + for (const i2 in indexReplacementMap) { + handlerMap[i2] = handlerData[indexReplacementMap[i2]]; + } + return [regexp, handlerMap, staticMap]; +} +function findMiddleware(middleware, path8) { + if (!middleware) { + return void 0; + } + for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) { + if (buildWildcardRegExp(k).test(path8)) { + return [...middleware[k]]; + } + } + return void 0; +} +var RegExpRouter = class { + name = "RegExpRouter"; + #middleware; + #routes; + constructor() { + this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; + this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) }; + } + add(method, path8, handler) { + const middleware = this.#middleware; + const routes = this.#routes; + if (!middleware || !routes) { + throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); + } + if (!middleware[method]) { + ; + [middleware, routes].forEach((handlerMap) => { + handlerMap[method] = /* @__PURE__ */ Object.create(null); + Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => { + handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]]; + }); + }); + } + if (path8 === "/*") { + path8 = "*"; + } + const paramCount = (path8.match(/\/:/g) || []).length; + if (/\*$/.test(path8)) { + const re = buildWildcardRegExp(path8); + if (method === METHOD_NAME_ALL) { + Object.keys(middleware).forEach((m3) => { + middleware[m3][path8] ||= findMiddleware(middleware[m3], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; }); + } else { + middleware[method][path8] ||= findMiddleware(middleware[method], path8) || findMiddleware(middleware[METHOD_NAME_ALL], path8) || []; } - endPtr += +(str[endPtr] === ","); + Object.keys(middleware).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + Object.keys(middleware[m3]).forEach((p) => { + re.test(p) && middleware[m3][p].push([handler, paramCount]); + }); + } + }); + Object.keys(routes).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + Object.keys(routes[m3]).forEach( + (p) => re.test(p) && routes[m3][p].push([handler, paramCount]) + ); + } + }); + return; + } + const paths = checkOptionalParameter(path8) || [path8]; + for (let i2 = 0, len = paths.length; i2 < len; i2++) { + const path22 = paths[i2]; + Object.keys(routes).forEach((m3) => { + if (method === METHOD_NAME_ALL || method === m3) { + routes[m3][path22] ||= [ + ...findMiddleware(middleware[m3], path22) || findMiddleware(middleware[METHOD_NAME_ALL], path22) || [] + ]; + routes[m3][path22].push([handler, paramCount - len + i2 + 1]); + } + }); } - return [parsed, endPtr]; } - endPtr = skipUntil(str, ptr, ",", end); - let slice = sliceAndTrimEndOf(str, ptr, endPtr - +(str[endPtr - 1] === ","), end === "]"); - if (!slice[0]) { - throw new TomlError("incomplete key-value declaration: no value specified", { - toml: str, - ptr + match = match; + buildAllMatchers() { + const matchers = /* @__PURE__ */ Object.create(null); + Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => { + matchers[method] ||= this.#buildMatcher(method); }); - } - if (end && slice[1] > -1) { - endPtr = skipVoid(str, ptr + slice[1]); - endPtr += +(str[endPtr] === ","); - } - return [ - parseValue(slice[0], str, ptr, integersAsBigInt), - endPtr - ]; -} -var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/; -function parseKey(str, ptr, end = "=") { - let dot = ptr - 1; - let parsed = []; - let endPtr = str.indexOf(end, ptr); - if (endPtr < 0) { - throw new TomlError("incomplete key-value: cannot find end of key", { - toml: str, - ptr + this.#middleware = this.#routes = void 0; + clearWildcardRegExpCache(); + return matchers; + } + #buildMatcher(method) { + const routes = []; + let hasOwnRoute = method === METHOD_NAME_ALL; + [this.#middleware, this.#routes].forEach((r) => { + const ownRoute = r[method] ? Object.keys(r[method]).map((path8) => [path8, r[method][path8]]) : []; + if (ownRoute.length !== 0) { + hasOwnRoute ||= true; + routes.push(...ownRoute); + } else if (method !== METHOD_NAME_ALL) { + routes.push( + ...Object.keys(r[METHOD_NAME_ALL]).map((path8) => [path8, r[METHOD_NAME_ALL][path8]]) + ); + } }); + if (!hasOwnRoute) { + return null; + } else { + return buildMatcherFromPreprocessedRoutes(routes); + } } - do { - let c = str[ptr = ++dot]; - if (c !== " " && c !== " ") { - if (c === '"' || c === "'") { - if (c === str[ptr + 1] && c === str[ptr + 2]) { - throw new TomlError("multiline strings are not allowed in keys", { - toml: str, - ptr - }); - } - let eos = getStringEnd(str, ptr); - if (eos < 0) { - throw new TomlError("unfinished string encountered", { - toml: str, - ptr - }); +}; +var SmartRouter = class { + name = "SmartRouter"; + #routers = []; + #routes = []; + constructor(init2) { + this.#routers = init2.routers; + } + add(method, path8, handler) { + if (!this.#routes) { + throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT); + } + this.#routes.push([method, path8, handler]); + } + match(method, path8) { + if (!this.#routes) { + throw new Error("Fatal error"); + } + const routers = this.#routers; + const routes = this.#routes; + const len = routers.length; + let i2 = 0; + let res; + for (; i2 < len; i2++) { + const router = routers[i2]; + try { + for (let i22 = 0, len2 = routes.length; i22 < len2; i22++) { + router.add(...routes[i22]); } - dot = str.indexOf(".", eos); - let strEnd = str.slice(eos, dot < 0 || dot > endPtr ? endPtr : dot); - let newLine = indexOfNewline(strEnd); - if (newLine > -1) { - throw new TomlError("newlines are not allowed in keys", { - toml: str, - ptr: ptr + dot + newLine - }); + res = router.match(method, path8); + } catch (e2) { + if (e2 instanceof UnsupportedPathError) { + continue; } - if (strEnd.trimStart()) { - throw new TomlError("found extra tokens after the string part", { - toml: str, - ptr: eos - }); + throw e2; + } + this.match = router.match.bind(router); + this.#routers = [router]; + this.#routes = void 0; + break; + } + if (i2 === len) { + throw new Error("Fatal error"); + } + this.name = `SmartRouter + ${this.activeRouter.name}`; + return res; + } + get activeRouter() { + if (this.#routes || this.#routers.length !== 1) { + throw new Error("No active router has been determined yet."); + } + return this.#routers[0]; + } +}; +var emptyParams = /* @__PURE__ */ Object.create(null); +var hasChildren = (children) => { + for (const _ in children) { + return true; + } + return false; +}; +var Node2 = class _Node2 { + #methods; + #children; + #patterns; + #order = 0; + #params = emptyParams; + constructor(method, handler, children) { + this.#children = children || /* @__PURE__ */ Object.create(null); + this.#methods = []; + if (method && handler) { + const m3 = /* @__PURE__ */ Object.create(null); + m3[method] = { handler, possibleKeys: [], score: 0 }; + this.#methods = [m3]; + } + this.#patterns = []; + } + insert(method, path8, handler) { + this.#order = ++this.#order; + let curNode = this; + const parts = splitRoutingPath(path8); + const possibleKeys = []; + for (let i2 = 0, len = parts.length; i2 < len; i2++) { + const p = parts[i2]; + const nextP = parts[i2 + 1]; + const pattern = getPattern(p, nextP); + const key = Array.isArray(pattern) ? pattern[0] : p; + if (key in curNode.#children) { + curNode = curNode.#children[key]; + if (pattern) { + possibleKeys.push(pattern[1]); } - if (endPtr < eos) { - endPtr = str.indexOf(end, eos); - if (endPtr < 0) { - throw new TomlError("incomplete key-value: cannot find end of key", { - toml: str, - ptr - }); + continue; + } + curNode.#children[key] = new _Node2(); + if (pattern) { + curNode.#patterns.push(pattern); + possibleKeys.push(pattern[1]); + } + curNode = curNode.#children[key]; + } + curNode.#methods.push({ + [method]: { + handler, + possibleKeys: possibleKeys.filter((v2, i2, a) => a.indexOf(v2) === i2), + score: this.#order + } + }); + return curNode; + } + #pushHandlerSets(handlerSets, node, method, nodeParams, params) { + for (let i2 = 0, len = node.#methods.length; i2 < len; i2++) { + const m3 = node.#methods[i2]; + const handlerSet = m3[method] || m3[METHOD_NAME_ALL]; + const processedSet = {}; + if (handlerSet !== void 0) { + handlerSet.params = /* @__PURE__ */ Object.create(null); + handlerSets.push(handlerSet); + if (nodeParams !== emptyParams || params && params !== emptyParams) { + for (let i22 = 0, len2 = handlerSet.possibleKeys.length; i22 < len2; i22++) { + const key = handlerSet.possibleKeys[i22]; + const processed = processedSet[handlerSet.score]; + handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]; + processedSet[handlerSet.score] = true; + } + } + } + } + } + search(method, path8) { + const handlerSets = []; + this.#params = emptyParams; + const curNode = this; + let curNodes = [curNode]; + const parts = splitPath(path8); + const curNodesQueue = []; + const len = parts.length; + let partOffsets = null; + for (let i2 = 0; i2 < len; i2++) { + const part = parts[i2]; + const isLast = i2 === len - 1; + const tempNodes = []; + for (let j = 0, len2 = curNodes.length; j < len2; j++) { + const node = curNodes[j]; + const nextNode = node.#children[part]; + if (nextNode) { + nextNode.#params = node.#params; + if (isLast) { + if (nextNode.#children["*"]) { + this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params); + } + this.#pushHandlerSets(handlerSets, nextNode, method, node.#params); + } else { + tempNodes.push(nextNode); } } - parsed.push(parseString(str, ptr, eos)); - } else { - dot = str.indexOf(".", ptr); - let part = str.slice(ptr, dot < 0 || dot > endPtr ? endPtr : dot); - if (!KEY_PART_RE.test(part)) { - throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", { - toml: str, - ptr - }); + for (let k = 0, len3 = node.#patterns.length; k < len3; k++) { + const pattern = node.#patterns[k]; + const params = node.#params === emptyParams ? {} : { ...node.#params }; + if (pattern === "*") { + const astNode = node.#children["*"]; + if (astNode) { + this.#pushHandlerSets(handlerSets, astNode, method, node.#params); + astNode.#params = params; + tempNodes.push(astNode); + } + continue; + } + const [key, name, matcher] = pattern; + if (!part && !(matcher instanceof RegExp)) { + continue; + } + const child = node.#children[key]; + if (matcher instanceof RegExp) { + if (partOffsets === null) { + partOffsets = new Array(len); + let offset = path8[0] === "/" ? 1 : 0; + for (let p = 0; p < len; p++) { + partOffsets[p] = offset; + offset += parts[p].length + 1; + } + } + const restPathString = path8.substring(partOffsets[i2]); + const m3 = matcher.exec(restPathString); + if (m3) { + params[name] = m3[0]; + this.#pushHandlerSets(handlerSets, child, method, node.#params, params); + if (hasChildren(child.#children)) { + child.#params = params; + const componentCount = m3[0].match(/\//)?.length ?? 0; + const targetCurNodes = curNodesQueue[componentCount] ||= []; + targetCurNodes.push(child); + } + continue; + } + } + if (matcher === true || matcher.test(part)) { + params[name] = part; + if (isLast) { + this.#pushHandlerSets(handlerSets, child, method, params, node.#params); + if (child.#children["*"]) { + this.#pushHandlerSets( + handlerSets, + child.#children["*"], + method, + params, + node.#params + ); + } + } else { + child.#params = params; + tempNodes.push(child); + } + } } - parsed.push(part.trimEnd()); } + const shifted = curNodesQueue.shift(); + curNodes = shifted ? tempNodes.concat(shifted) : tempNodes; } - } while (dot + 1 && dot < endPtr); - return [parsed, skipVoid(str, endPtr + 1, true, true)]; -} -function parseInlineTable(str, ptr, depth, integersAsBigInt) { - let res = {}; - let seen = /* @__PURE__ */ new Set(); - let c; - let comma = 0; - ptr++; - while ((c = str[ptr++]) !== "}" && c) { - let err = { toml: str, ptr: ptr - 1 }; - if (c === "\n") { - throw new TomlError("newlines are not allowed in inline tables", err); - } else if (c === "#") { - throw new TomlError("inline tables cannot contain comments", err); - } else if (c === ",") { - throw new TomlError("expected key-value, found comma", err); - } else if (c !== " " && c !== " ") { - let k; - let t = res; - let hasOwn = false; - let [key, keyEndPtr] = parseKey(str, ptr - 1); - for (let i2 = 0; i2 < key.length; i2++) { - if (i2) - t = hasOwn ? t[k] : t[k] = {}; - k = key[i2]; - if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) { - throw new TomlError("trying to redefine an already defined value", { - toml: str, - ptr - }); + if (handlerSets.length > 1) { + handlerSets.sort((a, b) => { + return a.score - b.score; + }); + } + return [handlerSets.map(({ handler, params }) => [handler, params])]; + } +}; +var TrieRouter = class { + name = "TrieRouter"; + #node; + constructor() { + this.#node = new Node2(); + } + add(method, path8, handler) { + const results = checkOptionalParameter(path8); + if (results) { + for (let i2 = 0, len = results.length; i2 < len; i2++) { + this.#node.insert(method, results[i2], handler); + } + return; + } + this.#node.insert(method, path8, handler); + } + match(method, path8) { + return this.#node.search(method, path8); + } +}; +var Hono2 = class extends Hono { + /** + * Creates an instance of the Hono class. + * + * @param options - Optional configuration options for the Hono instance. + */ + constructor(options2 = {}) { + super(options2); + this.router = options2.router ?? new SmartRouter({ + routers: [new RegExpRouter(), new TrieRouter()] + }); + } +}; +var cors = (options2) => { + const defaults = { + origin: "*", + allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"], + allowHeaders: [], + exposeHeaders: [] + }; + const opts = { + ...defaults, + ...options2 + }; + const findAllowOrigin = ((optsOrigin) => { + if (typeof optsOrigin === "string") { + if (optsOrigin === "*") { + if (opts.credentials) { + return (origin) => origin || null; } - if (!hasOwn && k === "__proto__") { - Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true }); + return () => optsOrigin; + } else { + return (origin) => optsOrigin === origin ? origin : null; + } + } else if (typeof optsOrigin === "function") { + return optsOrigin; + } else { + return (origin) => optsOrigin.includes(origin) ? origin : null; + } + })(opts.origin); + const findAllowMethods = ((optsAllowMethods) => { + if (typeof optsAllowMethods === "function") { + return optsAllowMethods; + } else if (Array.isArray(optsAllowMethods)) { + return () => optsAllowMethods; + } else { + return () => []; + } + })(opts.allowMethods); + return async function cors2(c, next) { + function set(key, value) { + c.res.headers.set(key, value); + } + const allowOrigin = await findAllowOrigin(c.req.header("origin") || "", c); + if (allowOrigin) { + set("Access-Control-Allow-Origin", allowOrigin); + } + if (opts.credentials) { + set("Access-Control-Allow-Credentials", "true"); + } + if (opts.exposeHeaders?.length) { + set("Access-Control-Expose-Headers", opts.exposeHeaders.join(",")); + } + if (c.req.method === "OPTIONS") { + if (opts.origin !== "*" || opts.credentials) { + set("Vary", "Origin"); + } + if (opts.maxAge != null) { + set("Access-Control-Max-Age", opts.maxAge.toString()); + } + const allowMethods = await findAllowMethods(c.req.header("origin") || "", c); + if (allowMethods.length) { + set("Access-Control-Allow-Methods", allowMethods.join(",")); + } + let headers = opts.allowHeaders; + if (!headers?.length) { + const requestHeaders = c.req.header("Access-Control-Request-Headers"); + if (requestHeaders) { + headers = requestHeaders.split(/\s*,\s*/); } } - if (hasOwn) { - throw new TomlError("trying to redefine an already defined value", { - toml: str, - ptr - }); + if (headers?.length) { + set("Access-Control-Allow-Headers", headers.join(",")); + c.res.headers.append("Vary", "Access-Control-Request-Headers"); } - let [value, valueEndPtr] = extractValue(str, keyEndPtr, "}", depth - 1, integersAsBigInt); - seen.add(value); - t[k] = value; - ptr = valueEndPtr; - comma = str[ptr - 1] === "," ? ptr - 1 : 0; + c.res.headers.delete("Content-Length"); + c.res.headers.delete("Content-Type"); + return new Response(null, { + headers: c.res.headers, + status: 204, + statusText: "No Content" + }); + } + await next(); + if (opts.origin !== "*" || opts.credentials) { + c.header("Vary", "Origin", { append: true }); } + }; +}; +var RequestError = class extends Error { + constructor(message, options2) { + super(message, options2); + this.name = "RequestError"; } - if (comma) { - throw new TomlError("trailing commas are not allowed in inline tables", { - toml: str, - ptr: comma - }); +}; +var toRequestError = (e2) => { + if (e2 instanceof RequestError) { + return e2; } - if (!c) { - throw new TomlError("unfinished table encountered", { - toml: str, - ptr + return new RequestError(e2.message, { cause: e2 }); +}; +var GlobalRequest = global.Request; +var Request2 = class extends GlobalRequest { + constructor(input, options2) { + if (typeof input === "object" && getRequestCache in input) { + input = input[getRequestCache](); + } + if (typeof options2?.body?.getReader !== "undefined") { + ; + options2.duplex ??= "half"; + } + super(input, options2); + } +}; +var newHeadersFromIncoming = (incoming) => { + const headerRecord = []; + const rawHeaders = incoming.rawHeaders; + for (let i2 = 0; i2 < rawHeaders.length; i2 += 2) { + const { [i2]: key, [i2 + 1]: value } = rawHeaders; + if (key.charCodeAt(0) !== /*:*/ + 58) { + headerRecord.push([key, value]); + } + } + return new Headers(headerRecord); +}; +var wrapBodyStream = Symbol("wrapBodyStream"); +var newRequestFromIncoming = (method, url2, headers, incoming, abortController) => { + const init2 = { + method, + headers, + signal: abortController.signal + }; + if (method === "TRACE") { + init2.method = "GET"; + const req = new Request2(url2, init2); + Object.defineProperty(req, "method", { + get() { + return "TRACE"; + } }); + return req; } - return [res, ptr]; -} -function parseArray(str, ptr, depth, integersAsBigInt) { - let res = []; - let c; - ptr++; - while ((c = str[ptr++]) !== "]" && c) { - if (c === ",") { - throw new TomlError("expected value, found comma", { - toml: str, - ptr: ptr - 1 + if (!(method === "GET" || method === "HEAD")) { + if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) { + init2.body = new ReadableStream({ + start(controller) { + controller.enqueue(incoming.rawBody); + controller.close(); + } }); - } else if (c === "#") - ptr = skipComment(str, ptr); - else if (c !== " " && c !== " " && c !== "\n" && c !== "\r") { - let e2 = extractValue(str, ptr - 1, "]", depth - 1, integersAsBigInt); - res.push(e2[0]); - ptr = e2[1]; + } else if (incoming[wrapBodyStream]) { + let reader; + init2.body = new ReadableStream({ + async pull(controller) { + try { + reader ||= Readable2.toWeb(incoming).getReader(); + const { done, value } = await reader.read(); + if (done) { + controller.close(); + } else { + controller.enqueue(value); + } + } catch (error2) { + controller.error(error2); + } + } + }); + } else { + init2.body = Readable2.toWeb(incoming); } } - if (!c) { - throw new TomlError("unfinished array encountered", { - toml: str, - ptr - }); + return new Request2(url2, init2); +}; +var getRequestCache = Symbol("getRequestCache"); +var requestCache = Symbol("requestCache"); +var incomingKey = Symbol("incomingKey"); +var urlKey = Symbol("urlKey"); +var headersKey = Symbol("headersKey"); +var abortControllerKey = Symbol("abortControllerKey"); +var getAbortController = Symbol("getAbortController"); +var requestPrototype = { + get method() { + return this[incomingKey].method || "GET"; + }, + get url() { + return this[urlKey]; + }, + get headers() { + return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]); + }, + [getAbortController]() { + this[getRequestCache](); + return this[abortControllerKey]; + }, + [getRequestCache]() { + this[abortControllerKey] ||= new AbortController(); + return this[requestCache] ||= newRequestFromIncoming( + this.method, + this[urlKey], + this.headers, + this[incomingKey], + this[abortControllerKey] + ); } - return [res, ptr]; -} -function peekTable(key, table, meta, type) { - let t = table; - let m3 = meta; - let k; - let hasOwn = false; - let state; - for (let i2 = 0; i2 < key.length; i2++) { - if (i2) { - t = hasOwn ? t[k] : t[k] = {}; - m3 = (state = m3[k]).c; - if (type === 0 && (state.t === 1 || state.t === 2)) { - return null; - } - if (state.t === 2) { - let l = t.length - 1; - t = t[l]; - m3 = m3[l].c; - } +}; +[ + "body", + "bodyUsed", + "cache", + "credentials", + "destination", + "integrity", + "mode", + "redirect", + "referrer", + "referrerPolicy", + "signal", + "keepalive" +].forEach((k) => { + Object.defineProperty(requestPrototype, k, { + get() { + return this[getRequestCache]()[k]; } - k = key[i2]; - if ((hasOwn = Object.hasOwn(t, k)) && m3[k]?.t === 0 && m3[k]?.d) { - return null; + }); +}); +["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { + Object.defineProperty(requestPrototype, k, { + value: function() { + return this[getRequestCache]()[k](); } - if (!hasOwn) { - if (k === "__proto__") { - Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true }); - Object.defineProperty(m3, k, { enumerable: true, configurable: true, writable: true }); - } - m3[k] = { - t: i2 < key.length - 1 && type === 2 ? 3 : type, - d: false, - i: 0, - c: {} - }; + }); +}); +Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { + value: function(depth, options2, inspectFn) { + const props = { + method: this.method, + url: this.url, + headers: this.headers, + nativeRequest: this[requestCache] + }; + return `Request (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; + } +}); +Object.setPrototypeOf(requestPrototype, Request2.prototype); +var newRequest = (incoming, defaultHostname) => { + const req = Object.create(requestPrototype); + req[incomingKey] = incoming; + const incomingUrl = incoming.url || ""; + if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL. + (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) { + if (incoming instanceof Http2ServerRequest) { + throw new RequestError("Absolute URL for :path is not allowed in HTTP/2"); + } + try { + const url22 = new URL(incomingUrl); + req[urlKey] = url22.href; + } catch (e2) { + throw new RequestError("Invalid absolute URL", { cause: e2 }); } + return req; } - state = m3[k]; - if (state.t !== type && !(type === 1 && state.t === 3)) { - return null; + const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname; + if (!host) { + throw new RequestError("Missing host header"); } - if (type === 2) { - if (!state.d) { - state.d = true; - t[k] = []; + let scheme; + if (incoming instanceof Http2ServerRequest) { + scheme = incoming.scheme; + if (!(scheme === "http" || scheme === "https")) { + throw new RequestError("Unsupported scheme"); } - t[k].push(t = {}); - state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} }; - } - if (state.d) { - return null; + } else { + scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http"; } - state.d = true; - if (type === 1) { - t = hasOwn ? t[k] : t[k] = {}; - } else if (type === 0 && hasOwn) { - return null; + const url2 = new URL(`${scheme}://${host}${incomingUrl}`); + if (url2.hostname.length !== host.length && url2.hostname !== host.replace(/:\d+$/, "")) { + throw new RequestError("Invalid host header"); } - return [k, t, state.c]; -} -function parse8(toml, { maxDepth = 1e3, integersAsBigInt } = {}) { - let res = {}; - let meta = {}; - let tbl = res; - let m3 = meta; - for (let ptr = skipVoid(toml, 0); ptr < toml.length; ) { - if (toml[ptr] === "[") { - let isTableArray = toml[++ptr] === "["; - let k = parseKey(toml, ptr += +isTableArray, "]"); - if (isTableArray) { - if (toml[k[1] - 1] !== "]") { - throw new TomlError("expected end of table declaration", { - toml, - ptr: k[1] - 1 - }); - } - k[1]++; - } - let p = peekTable( - k[0], - res, - meta, - isTableArray ? 2 : 1 - /* Type.EXPLICIT */ - ); - if (!p) { - throw new TomlError("trying to redefine an already defined table or value", { - toml, - ptr - }); + req[urlKey] = url2.href; + return req; +}; +var responseCache = Symbol("responseCache"); +var getResponseCache = Symbol("getResponseCache"); +var cacheKey = Symbol("cache"); +var GlobalResponse = global.Response; +var Response2 = class _Response { + #body; + #init; + [getResponseCache]() { + delete this[cacheKey]; + return this[responseCache] ||= new GlobalResponse(this.#body, this.#init); + } + constructor(body, init2) { + let headers; + this.#body = body; + if (init2 instanceof _Response) { + const cachedGlobalResponse = init2[responseCache]; + if (cachedGlobalResponse) { + this.#init = cachedGlobalResponse; + this[getResponseCache](); + return; + } else { + this.#init = init2.#init; + headers = new Headers(init2.#init.headers); } - m3 = p[2]; - tbl = p[1]; - ptr = k[1]; } else { - let k = parseKey(toml, ptr); - let p = peekTable( - k[0], - tbl, - m3, - 0 - /* Type.DOTTED */ - ); - if (!p) { - throw new TomlError("trying to redefine an already defined table or value", { - toml, - ptr - }); + this.#init = init2; + } + if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) { + ; + this[cacheKey] = [init2?.status || 200, body, headers || init2?.headers]; + } + } + get headers() { + const cache2 = this[cacheKey]; + if (cache2) { + if (!(cache2[2] instanceof Headers)) { + cache2[2] = new Headers( + cache2[2] || { "content-type": "text/plain; charset=UTF-8" } + ); } - let v2 = extractValue(toml, k[1], void 0, maxDepth, integersAsBigInt); - p[1][p[0]] = v2[0]; - ptr = v2[1]; + return cache2[2]; } - ptr = skipVoid(toml, ptr, true); - if (toml[ptr] && toml[ptr] !== "\n" && toml[ptr] !== "\r") { - throw new TomlError("each key-value declaration must be followed by an end-of-line", { - toml, - ptr - }); + return this[getResponseCache]().headers; + } + get status() { + return this[cacheKey]?.[0] ?? this[getResponseCache]().status; + } + get ok() { + const status = this.status; + return status >= 200 && status < 300; + } +}; +["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => { + Object.defineProperty(Response2.prototype, k, { + get() { + return this[getResponseCache]()[k]; } - ptr = skipVoid(toml, ptr); + }); +}); +["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => { + Object.defineProperty(Response2.prototype, k, { + value: function() { + return this[getResponseCache]()[k](); + } + }); +}); +Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), { + value: function(depth, options2, inspectFn) { + const props = { + status: this.status, + headers: this.headers, + ok: this.ok, + nativeResponse: this[responseCache] + }; + return `Response (lightweight) ${inspectFn(props, { ...options2, depth: depth == null ? null : depth - 1 })}`; } - return res; +}); +Object.setPrototypeOf(Response2, GlobalResponse); +Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype); +async function readWithoutBlocking(readPromise) { + return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]); } -var BARE_KEY = /^[a-z0-9-_]+$/i; -function extendedTypeOf(obj) { - let type = typeof obj; - if (type === "object") { - if (Array.isArray(obj)) - return "array"; - if (obj instanceof Date) - return "date"; +function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) { + const cancel = (error2) => { + reader.cancel(error2).catch(() => { + }); + }; + writable.on("close", cancel); + writable.on("error", cancel); + (currentReadPromise ?? reader.read()).then(flow, handleStreamError); + return reader.closed.finally(() => { + writable.off("close", cancel); + writable.off("error", cancel); + }); + function handleStreamError(error2) { + if (error2) { + writable.destroy(error2); + } + } + function onDrain() { + reader.read().then(flow, handleStreamError); + } + function flow({ done, value }) { + try { + if (done) { + writable.end(); + } else if (!writable.write(value)) { + writable.once("drain", onDrain); + } else { + return reader.read().then(flow, handleStreamError); + } + } catch (e2) { + handleStreamError(e2); + } } - return type; } -function isArrayOfTables(obj) { - for (let i2 = 0; i2 < obj.length; i2++) { - if (extendedTypeOf(obj[i2]) !== "object") - return false; +function writeFromReadableStream(stream, writable) { + if (stream.locked) { + throw new TypeError("ReadableStream is locked."); + } else if (writable.destroyed) { + return; } - return obj.length != 0; + return writeFromReadableStreamDefaultReader(stream.getReader(), writable); } -function formatString(s) { - return JSON.stringify(s).replace(/\x7f/g, "\\u007f"); +var buildOutgoingHttpHeaders = (headers) => { + const res = {}; + if (!(headers instanceof Headers)) { + headers = new Headers(headers ?? void 0); + } + const cookies = []; + for (const [k, v2] of headers) { + if (k === "set-cookie") { + cookies.push(v2); + } else { + res[k] = v2; + } + } + if (cookies.length > 0) { + res["set-cookie"] = cookies; + } + res["content-type"] ??= "text/plain; charset=UTF-8"; + return res; +}; +var X_ALREADY_SENT = "x-hono-already-sent"; +if (typeof global.crypto === "undefined") { + global.crypto = crypto2; } -function stringifyValue(val, type, depth, numberAsFloat) { - if (depth === 0) { - throw new Error("Could not stringify the object: maximum object depth exceeded"); +var outgoingEnded = Symbol("outgoingEnded"); +var incomingDraining = Symbol("incomingDraining"); +var DRAIN_TIMEOUT_MS = 500; +var MAX_DRAIN_BYTES = 64 * 1024 * 1024; +var drainIncoming = (incoming) => { + const incomingWithDrainState = incoming; + if (incoming.destroyed || incomingWithDrainState[incomingDraining]) { + return; } - if (type === "number") { - if (isNaN(val)) - return "nan"; - if (val === Infinity) - return "inf"; - if (val === -Infinity) - return "-inf"; - if (numberAsFloat && Number.isInteger(val)) - return val.toFixed(1); - return val.toString(); + incomingWithDrainState[incomingDraining] = true; + if (incoming instanceof Http2ServerRequest2) { + try { + ; + incoming.stream?.close?.(h2constants.NGHTTP2_NO_ERROR); + } catch { + } + return; } - if (type === "bigint" || type === "boolean") { - return val.toString(); + let bytesRead = 0; + const cleanup = () => { + clearTimeout(timer2); + incoming.off("data", onData); + incoming.off("end", cleanup); + incoming.off("error", cleanup); + }; + const forceClose = () => { + cleanup(); + const socket = incoming.socket; + if (socket && !socket.destroyed) { + socket.destroySoon(); + } + }; + const timer2 = setTimeout(forceClose, DRAIN_TIMEOUT_MS); + timer2.unref?.(); + const onData = (chunk) => { + bytesRead += chunk.length; + if (bytesRead > MAX_DRAIN_BYTES) { + forceClose(); + } + }; + incoming.on("data", onData); + incoming.on("end", cleanup); + incoming.on("error", cleanup); + incoming.resume(); +}; +var handleRequestError = () => new Response(null, { + status: 400 +}); +var handleFetchError = (e2) => new Response(null, { + status: e2 instanceof Error && (e2.name === "TimeoutError" || e2.constructor.name === "TimeoutError") ? 504 : 500 +}); +var handleResponseError = (e2, outgoing) => { + const err = e2 instanceof Error ? e2 : new Error("unknown error", { cause: e2 }); + if (err.code === "ERR_STREAM_PREMATURE_CLOSE") { + console.info("The user aborted a request."); + } else { + console.error(e2); + if (!outgoing.headersSent) { + outgoing.writeHead(500, { "Content-Type": "text/plain" }); + } + outgoing.end(`Error: ${err.message}`); + outgoing.destroy(err); } - if (type === "string") { - return formatString(val); +}; +var flushHeaders = (outgoing) => { + if ("flushHeaders" in outgoing && outgoing.writable) { + outgoing.flushHeaders(); } - if (type === "date") { - if (isNaN(val.getTime())) { - throw new TypeError("cannot serialize invalid date"); +}; +var responseViaCache = async (res, outgoing) => { + let [status, body, header] = res[cacheKey]; + let hasContentLength = false; + if (!header) { + header = { "content-type": "text/plain; charset=UTF-8" }; + } else if (header instanceof Headers) { + hasContentLength = header.has("content-length"); + header = buildOutgoingHttpHeaders(header); + } else if (Array.isArray(header)) { + const headerObj = new Headers(header); + hasContentLength = headerObj.has("content-length"); + header = buildOutgoingHttpHeaders(headerObj); + } else { + for (const key in header) { + if (key.length === 14 && key.toLowerCase() === "content-length") { + hasContentLength = true; + break; + } } - return val.toISOString(); } - if (type === "object") { - return stringifyInlineTable(val, depth, numberAsFloat); + if (!hasContentLength) { + if (typeof body === "string") { + header["Content-Length"] = Buffer.byteLength(body); + } else if (body instanceof Uint8Array) { + header["Content-Length"] = body.byteLength; + } else if (body instanceof Blob) { + header["Content-Length"] = body.size; + } } - if (type === "array") { - return stringifyArray(val, depth, numberAsFloat); + outgoing.writeHead(status, header); + if (typeof body === "string" || body instanceof Uint8Array) { + outgoing.end(body); + } else if (body instanceof Blob) { + outgoing.end(new Uint8Array(await body.arrayBuffer())); + } else { + flushHeaders(outgoing); + await writeFromReadableStream(body, outgoing)?.catch( + (e2) => handleResponseError(e2, outgoing) + ); + } + ; + outgoing[outgoingEnded]?.(); +}; +var isPromise = (res) => typeof res.then === "function"; +var responseViaResponseObject = async (res, outgoing, options2 = {}) => { + if (isPromise(res)) { + if (options2.errorHandler) { + try { + res = await res; + } catch (err) { + const errRes = await options2.errorHandler(err); + if (!errRes) { + return; + } + res = errRes; + } + } else { + res = await res.catch(handleFetchError); + } + } + if (cacheKey in res) { + return responseViaCache(res, outgoing); + } + const resHeaderRecord = buildOutgoingHttpHeaders(res.headers); + if (res.body) { + const reader = res.body.getReader(); + const values = []; + let done = false; + let currentReadPromise = void 0; + if (resHeaderRecord["transfer-encoding"] !== "chunked") { + let maxReadCount = 2; + for (let i2 = 0; i2 < maxReadCount; i2++) { + currentReadPromise ||= reader.read(); + const chunk = await readWithoutBlocking(currentReadPromise).catch((e2) => { + console.error(e2); + done = true; + }); + if (!chunk) { + if (i2 === 1) { + await new Promise((resolve82) => setTimeout(resolve82)); + maxReadCount = 3; + continue; + } + break; + } + currentReadPromise = void 0; + if (chunk.value) { + values.push(chunk.value); + } + if (chunk.done) { + done = true; + break; + } + } + if (done && !("content-length" in resHeaderRecord)) { + resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0); + } + } + outgoing.writeHead(res.status, resHeaderRecord); + values.forEach((value) => { + ; + outgoing.write(value); + }); + if (done) { + outgoing.end(); + } else { + if (values.length === 0) { + flushHeaders(outgoing); + } + await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise); + } + } else if (resHeaderRecord[X_ALREADY_SENT]) { + } else { + outgoing.writeHead(res.status, resHeaderRecord); + outgoing.end(); + } + ; + outgoing[outgoingEnded]?.(); +}; +var getRequestListener = (fetchCallback, options2 = {}) => { + const autoCleanupIncoming = options2.autoCleanupIncoming ?? true; + if (options2.overrideGlobalObjects !== false && global.Request !== Request2) { + Object.defineProperty(global, "Request", { + value: Request2 + }); + Object.defineProperty(global, "Response", { + value: Response2 + }); + } + return async (incoming, outgoing) => { + let res, req; + try { + req = newRequest(incoming, options2.hostname); + let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD"; + if (!incomingEnded) { + ; + incoming[wrapBodyStream] = true; + incoming.on("end", () => { + incomingEnded = true; + }); + if (incoming instanceof Http2ServerRequest2) { + ; + outgoing[outgoingEnded] = () => { + if (!incomingEnded) { + setTimeout(() => { + if (!incomingEnded) { + setTimeout(() => { + drainIncoming(incoming); + }); + } + }); + } + }; + } + outgoing.on("finish", () => { + if (!incomingEnded) { + drainIncoming(incoming); + } + }); + } + outgoing.on("close", () => { + const abortController = req[abortControllerKey]; + if (abortController) { + if (incoming.errored) { + req[abortControllerKey].abort(incoming.errored.toString()); + } else if (!outgoing.writableFinished) { + req[abortControllerKey].abort("Client connection prematurely closed."); + } + } + if (!incomingEnded) { + setTimeout(() => { + if (!incomingEnded) { + setTimeout(() => { + drainIncoming(incoming); + }); + } + }); + } + }); + res = fetchCallback(req, { incoming, outgoing }); + if (cacheKey in res) { + return responseViaCache(res, outgoing); + } + } catch (e2) { + if (!res) { + if (options2.errorHandler) { + res = await options2.errorHandler(req ? e2 : toRequestError(e2)); + if (!res) { + return; + } + } else if (!req) { + res = handleRequestError(); + } else { + res = handleFetchError(e2); + } + } else { + return handleResponseError(e2, outgoing); + } + } + try { + return await responseViaResponseObject(res, outgoing, options2); + } catch (e2) { + return handleResponseError(e2, outgoing); + } + }; +}; +var createAdaptorServer = (options2) => { + const fetchCallback = options2.fetch; + const requestListener = getRequestListener(fetchCallback, { + hostname: options2.hostname, + overrideGlobalObjects: options2.overrideGlobalObjects, + autoCleanupIncoming: options2.autoCleanupIncoming + }); + const createServer2 = options2.createServer || createServerHTTP; + const server = createServer2(options2.serverOptions || {}, requestListener); + return server; +}; +init_esm7(); +init_esm(); +Object.defineProperties(Buffer13, { + [serdesDeserializeSymbol]: { + value(buf2) { + return Buffer13.from(buf2); + } + }, + [serdesSerializeSymbol]: { + value(buf2) { + return new Uint8Array(buf2.buffer, buf2.byteOffset, buf2.byteLength); + } + }, + [serdesTagSymbol]: { + value: "node:buffer" + } +}); +deserializer.register(Buffer13); +var createWorker = (path8) => { + let worker; + let ready; + const launchWorker = () => { + worker = new Worker(new URL(path8, import.meta.url), { type: "module" }); + return new Promise((resolve82, reject) => { + const msgHandler = (event) => { + const msg = event.data; + if (msg === "ready") { + worker.removeEventListener("error", reject, { capture: false }); + worker.addEventListener("error", (ev) => { + const e2 = ev.error; + console.error(e2, `Running worker ${basename52(path8)} terminated. Attempting relaunch...`); + worker.removeEventListener("message", msgHandler, false); + ready = launchWorker().catch((e3) => { + console.error(e3, `Error on worker ${basename52(path8)} relaunch`); + process5.exit(1); + }); + }, false); + resolve82(); + } else if (msg && typeof msg === "object" && msg.type === "sbp" && Array.isArray(msg.data) && String(msg.data[0]).startsWith("chelonia.db/")) { + const port = msg.port; + Promise.try(() => esm_default(...deserializer(msg.data))).then((r) => { + const { data, transferables } = serializer(r); + port.postMessage([true, data], transferables); + }).catch((e2) => { + const { data, transferables } = serializer(e2); + port.postMessage([false, data], transferables); + }).finally(() => { + port.close(); + }); + } + }; + worker.addEventListener("message", msgHandler, false); + worker.addEventListener("error", reject, { capture: false, once: true }); + }); + }; + ready = launchWorker(); + const rpcSbp = (...args) => { + return ready.then(() => new Promise((resolve82, reject) => { + const mc = new MessageChannel(); + const cleanup = /* @__PURE__ */ ((worker2) => () => { + worker2.removeEventListener("error", reject, { capture: true }); + mc.port2.close(); + mc.port2.onmessage = null; + mc.port2.onmessageerror = null; + })(worker); + mc.port2.onmessage = (event) => { + cleanup(); + const [success, result] = event.data; + if (success) return resolve82(result); + reject(result); + }; + mc.port2.onmessageerror = () => { + cleanup(); + reject(new Error("Message error")); + }; + worker.postMessage([mc.port1, ...args], [mc.port1]); + worker.addEventListener("error", reject, { capture: false, once: true }); + })); + }; + return { + ready, + rpcSbp, + terminate: () => worker.terminate() + }; +}; +var createWorker_default = createWorker; +init_SPMessage(); +init_functions(); +init_esm(); +var import_npm_bottleneck = __toESM(require_lib6()); +var import_npm_chalk = __toESM(require_source()); +var getConnInfo = (c) => { + const bindings = c.env.server ? c.env.server : c.env; + const address = bindings.incoming.socket.remoteAddress; + const port = bindings.incoming.socket.remotePort; + const family = bindings.incoming.socket.remoteFamily; + return { + remote: { + address, + port, + addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0 + } + }; +}; +var import_npm_pino = __toESM(require_pino()); +var prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; +function logMethod(args, method) { + const stringIdx = typeof args[0] === "string" ? 0 : 1; + if (args.length > 1) { + for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { + args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; + } } + method.apply(this, args); } -function stringifyInlineTable(obj, depth, numberAsFloat) { - let keys = Object.keys(obj); - if (keys.length === 0) - return "{}"; - let res = "{ "; - for (let i2 = 0; i2 < keys.length; i2++) { - let k = keys[i2]; - if (i2) - res += ", "; - res += BARE_KEY.test(k) ? k : formatString(k); - res += " = "; - res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat); +var logger; +if (prettyPrint) { + try { + logger = (0, import_npm_pino.default)({ + hooks: { logMethod }, + transport: { + target: "pino-pretty", + options: { + colorize: true + } + } + }); + } catch (e2) { + console.warn("pino-pretty transport unavailable, using basic logging", e2); + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); } - return res + " }"; +} else { + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); } -function stringifyArray(array2, depth, numberAsFloat) { - if (array2.length === 0) - return "[]"; - let res = "[ "; - for (let i2 = 0; i2 < array2.length; i2++) { - if (i2) - res += ", "; - if (array2[i2] === null || array2[i2] === void 0) { - throw new TypeError("arrays cannot contain null or undefined values"); - } - res += stringifyValue(array2[i2], extendedTypeOf(array2[i2]), depth - 1, numberAsFloat); +var logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); +if (Object.keys(logger.levels.values).includes(logLevel)) { + logger.level = logLevel; +} else { + logger.warn(`Unknown log level: ${logLevel}`); +} +console.debug = logger.debug.bind(logger); +console.info = logger.info.bind(logger); +console.log = logger.info.bind(logger); +console.warn = logger.warn.bind(logger); +console.error = logger.error.bind(logger); +var logger_default = logger; +var import_npm_nconf4 = __toESM(require_nconf()); +function extractBearer(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "bearer "; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; + return { token: authorization.slice(prefix.length) }; +} +function extractShelter(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "shelter "; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; + try { + const billableContractID = verifyShelterAuthorizationHeader(authorization); + return { billableContractID }; + } catch (e2) { + console.warn(e2, "Shelter authorization failed"); + return null; } - return res + " ]"; } -function stringifyArrayTable(array2, key, depth, numberAsFloat) { - if (depth === 0) { - throw new Error("Could not stringify the object: maximum object depth exceeded"); +var extractors = { + "chel-bearer": extractBearer, + "chel-shelter": extractShelter +}; +function authMiddleware(strategies, mode = "required") { + const strategyList = Array.isArray(strategies) ? strategies : [strategies]; + return async (c, next) => { + for (const strategy of strategyList) { + const extractor = extractors[strategy]; + if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`); + const credentials = extractor(c); + if (credentials) { + c.set("credentials", credentials); + c.set("authStrategy", strategy); + return next(); + } + } + if (mode === "optional") { + c.set("credentials", {}); + c.set("authStrategy", ""); + return next(); + } + throw new HTTPException(401, { message: "Unauthorized" }); + }; +} +var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/; +var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/; +var trimCookieWhitespace = (value) => { + let start = 0; + let end = value.length; + while (start < end) { + const charCode = value.charCodeAt(start); + if (charCode !== 32 && charCode !== 9) { + break; + } + start++; } - let res = ""; - for (let i2 = 0; i2 < array2.length; i2++) { - res += `[[${key}]] -`; - res += stringifyTable(array2[i2], key, depth, numberAsFloat); - res += "\n\n"; + while (end > start) { + const charCode = value.charCodeAt(end - 1); + if (charCode !== 32 && charCode !== 9) { + break; + } + end--; } - return res; -} -function stringifyTable(obj, prefix, depth, numberAsFloat) { - if (depth === 0) { - throw new Error("Could not stringify the object: maximum object depth exceeded"); + return start === 0 && end === value.length ? value : value.slice(start, end); +}; +var parse42 = (cookie, name) => { + if (name && cookie.indexOf(name) === -1) { + return {}; } - let preamble = ""; - let tables = ""; - let keys = Object.keys(obj); - for (let i2 = 0; i2 < keys.length; i2++) { - let k = keys[i2]; - if (obj[k] !== null && obj[k] !== void 0) { - let type = extendedTypeOf(obj[k]); - if (type === "symbol" || type === "function") { - throw new TypeError(`cannot serialize values of type '${type}'`); - } - let key = BARE_KEY.test(k) ? k : formatString(k); - if (type === "array" && isArrayOfTables(obj[k])) { - tables += stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat); - } else if (type === "object") { - let tblKey = prefix ? `${prefix}.${key}` : key; - tables += `[${tblKey}] -`; - tables += stringifyTable(obj[k], tblKey, depth - 1, numberAsFloat); - tables += "\n\n"; - } else { - preamble += key; - preamble += " = "; - preamble += stringifyValue(obj[k], type, depth, numberAsFloat); - preamble += "\n"; + const pairs = cookie.split(";"); + const parsedCookie = {}; + for (const pairStr of pairs) { + const valueStartPos = pairStr.indexOf("="); + if (valueStartPos === -1) { + continue; + } + const cookieName = trimCookieWhitespace(pairStr.substring(0, valueStartPos)); + if (name && name !== cookieName || !validCookieNameRegEx.test(cookieName)) { + continue; + } + let cookieValue = trimCookieWhitespace(pairStr.substring(valueStartPos + 1)); + if (cookieValue.startsWith('"') && cookieValue.endsWith('"')) { + cookieValue = cookieValue.slice(1, -1); + } + if (validCookieValueRegEx.test(cookieValue)) { + parsedCookie[cookieName] = cookieValue.indexOf("%") !== -1 ? tryDecode(cookieValue, decodeURIComponent_) : cookieValue; + if (name) { + break; } } } - return `${preamble} -${tables}`.trim(); -} -function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) { - if (extendedTypeOf(obj) !== "object") { - throw new TypeError("stringify can only be called with an object"); + return parsedCookie; +}; +var getCookie = (c, key, prefix) => { + const cookie = c.req.raw.headers.get("Cookie"); + if (typeof key === "string") { + if (!cookie) { + return void 0; + } + let finalKey = key; + if (prefix === "secure") { + finalKey = "__Secure-" + key; + } else if (prefix === "host") { + finalKey = "__Host-" + key; + } + const obj2 = parse42(cookie, finalKey); + return obj2[finalKey]; } - return stringifyTable(obj, "", maxDepth, numbersAsFloat); + if (!cookie) { + return {}; + } + const obj = parse42(cookie); + return obj; +}; +var bufferToFormData = (arrayBuffer, contentType) => { + const response = new Response(arrayBuffer, { + headers: { + "Content-Type": contentType + } + }); + return response.formData(); +}; +var jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; +var multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/; +var urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/; +var validator = (target, validationFunc) => { + return async (c, next) => { + let value = {}; + const contentType = c.req.header("Content-Type"); + switch (target) { + case "json": + if (!contentType || !jsonRegex.test(contentType)) { + break; + } + try { + value = await c.req.json(); + } catch { + const message = "Malformed JSON in request body"; + throw new HTTPException(400, { message }); + } + break; + case "form": { + if (!contentType || !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))) { + break; + } + let formData; + if (c.req.bodyCache.formData) { + formData = await c.req.bodyCache.formData; + } else { + try { + const arrayBuffer = await c.req.arrayBuffer(); + formData = await bufferToFormData(arrayBuffer, contentType); + c.req.bodyCache.formData = formData; + } catch (e2) { + let message = "Malformed FormData request."; + message += e2 instanceof Error ? ` ${e2.message}` : ` ${String(e2)}`; + throw new HTTPException(400, { message }); + } + } + const form = /* @__PURE__ */ Object.create(null); + formData.forEach((value2, key) => { + if (key.endsWith("[]")) { + ; + (form[key] ??= []).push(value2); + } else if (Array.isArray(form[key])) { + ; + form[key].push(value2); + } else if (Object.hasOwn(form, key)) { + form[key] = [form[key], value2]; + } else { + form[key] = value2; + } + }); + value = form; + break; + } + case "query": + value = Object.fromEntries( + Object.entries(c.req.queries()).map(([k, v2]) => { + return v2.length === 1 ? [k, v2[0]] : [k, v2]; + }) + ); + break; + case "param": + value = c.req.param(); + break; + case "header": + value = c.req.header(); + break; + case "cookie": + value = getCookie(c); + break; + } + const res = await validationFunc(value, c); + if (res instanceof Response) { + return res; + } + c.req.addValidatedData(target, res); + return await next(); + }; +}; +function zValidatorFunction(target, schema, hook, options2) { + return validator(target, async (value, c) => { + let validatorValue = value; + if (target === "header" && "_def" in schema || target === "header" && "_zod" in schema) { + const schemaKeys = Object.keys("in" in schema ? schema.in.shape : schema.shape); + const caseInsensitiveKeymap = Object.fromEntries(schemaKeys.map((key) => [key.toLowerCase(), key])); + validatorValue = Object.fromEntries(Object.entries(value).map(([key, value$1]) => [caseInsensitiveKeymap[key] || key, value$1])); + } + const result = options2 && options2.validationFunction ? await options2.validationFunction(schema, validatorValue) : await schema.safeParseAsync(validatorValue); + if (hook) { + const hookResult = await hook({ + data: validatorValue, + ...result, + target + }, c); + if (hookResult) { + if (hookResult instanceof Response) return hookResult; + if ("response" in hookResult) return hookResult.response; + } + } + if (!result.success) return c.json(result, 400); + return result.data; + }); } -var commands_exports = {}; -__export(commands_exports, { - deploy: () => module3, - eventsAfter: () => module4, - get: () => module5, - hash: () => module6, - keygen: () => module7, - manifest: () => module8, - migrate: () => module9, - pin: () => module10, - serve: () => module11, - upload: () => module2, - verifySignature: () => module12, - version: () => module13 -}); +var zValidator = zValidatorFunction; init_zod(); -init_functions(); -init_esm(); -init_database(); -init_functions(); -async function createEntryFromFile(filepath, multicode) { - const buffer = await Deno.readFile(filepath); - const key = createCID(buffer, multicode); - return [key, buffer]; -} -function exit(x3, internal = false) { - const msg = x3 instanceof Error ? x3.message : String(x3); - if (internal) throw new Error(msg); - console.error("[chel]", red("Error:"), msg); - Deno.exit(1); -} -function isValidKey(key) { - return !/[\x00-\x1f\x7f\t\\/]/.test(key); -} -async function readRemoteData(src2, key) { - const buffer = await fetch(`${src2}/file/${key}`).then(async (r) => r.ok ? await r.arrayBuffer() : await Promise.reject(new Error(`failed network request to ${src2}: ${r.status} - ${r.statusText}`))); - return new Uint8Array(buffer); -} -async function revokeNet() { - await Deno.permissions.revoke({ name: "net" }); -} -var readJsonFile = async (file) => { - const contents = await Deno.readTextFile(resolve8(String(file))); - return JSON.parse(contents); +var ERROR_MESSAGE = "Payload Too Large"; +var BodyLimitError = class extends Error { + constructor(message) { + super(message); + this.name = "BodyLimitError"; + } }; -var findManifestFiles = async (path8) => { - const visited = /* @__PURE__ */ new Set(); - const internal = async (path9) => { - if (visited.has(path9)) { - return /* @__PURE__ */ new Set(); +var bodyLimit = (options2) => { + const onError = options2.onError || (() => { + const res = new Response(ERROR_MESSAGE, { + status: 413 + }); + throw new HTTPException(413, { res }); + }); + const maxSize = options2.maxSize; + return async function bodyLimit2(c, next) { + if (!c.req.raw.body) { + return next(); } - visited.add(path9); - const entries = Deno.readDir(path9); - const manifests = /* @__PURE__ */ new Set(); - for await (const entry of entries) { - const realPath2 = await Deno.realPath(join32(path9, entry.name)); - const info = await Deno.lstat(realPath2); - if (info.isDirectory) { - const subitems = await internal(realPath2); - for (const item of subitems) { - manifests.add(item); + const hasTransferEncoding = c.req.raw.headers.has("transfer-encoding"); + const hasContentLength = c.req.raw.headers.has("content-length"); + if (hasTransferEncoding && hasContentLength) { + } + if (hasContentLength && !hasTransferEncoding) { + const contentLength = parseInt(c.req.raw.headers.get("content-length") || "0", 10); + return contentLength > maxSize ? onError(c) : next(); + } + let size = 0; + const rawReader = c.req.raw.body.getReader(); + const reader = new ReadableStream({ + async start(controller) { + try { + for (; ; ) { + const { done, value } = await rawReader.read(); + if (done) { + break; + } + size += value.length; + if (size > maxSize) { + controller.error(new BodyLimitError(ERROR_MESSAGE)); + break; + } + controller.enqueue(value); + } + } finally { + controller.close(); } - } else if (entry.name.toLowerCase().endsWith(".manifest.json")) { - manifests.add(join32(path9, entry.name)); } + }); + const requestInit = { body: reader, duplex: "half" }; + c.req.raw = new Request(c.req.raw, requestInit); + await next(); + if (c.error instanceof BodyLimitError) { + c.res = await onError(c); } - return manifests; }; - const realPath = await Deno.realPath(path8); - return internal(realPath); }; -async function upload(args, internal = false) { - const { url: url2, files } = args; - if (!url2) { - await initDB({ skipDbPreloading: true }); - } - const uploaded = []; - const uploaderFn = url2 ? uploadEntryToURL : uploadEntryToDB; - for (const filepath_ of files) { - let type = multicodes.RAW; - let filepath = filepath_; - if (internal) { - if (filepath_[1] !== "|") throw new Error("Invalid path format"); - switch (filepath_[0]) { - case "r": - break; - case "m": - type = multicodes.SHELTER_CONTRACT_MANIFEST; - break; - case "t": - type = multicodes.SHELTER_CONTRACT_TEXT; - break; - default: - throw new Error("Unknown file type: " + filepath_[0]); +var MEGABYTE = 1048576; +var SECOND = 1e3; +var CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; +var KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; +var NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? { + const contentType = c.req.header("content-type") || ""; + let data; + try { + if (contentType.includes("application/x-www-form-urlencoded")) { + const form = await c.req.parseBody(); + data = Object.fromEntries( + Object.entries(form).filter(([, v2]) => typeof v2 === "string") + ); + } else { + data = await c.req.json(); } - filepath = filepath_.slice(2); + } catch { + throw new HTTPException(400, { message: "Invalid request body" }); } - const entry = await createEntryFromFile(filepath, type); - const destination = await uploaderFn(entry, url2); - if (!internal) { - console.log(green("uploaded:"), destination); + const result = schema.safeParse(data); + if (!result.success) { + throw new HTTPException(400, { message: "Invalid request body" }); + } + c.set("validatedBody", result.data); + return next(); + }; +} +var cidLookupTable = { + [multicodes.SHELTER_CONTRACT_MANIFEST]: "application/vnd.shelter.contractmanifest+json", + [multicodes.SHELTER_CONTRACT_TEXT]: "application/vnd.shelter.contracttext", + [multicodes.SHELTER_CONTRACT_DATA]: "application/vnd.shelter.contractdata+json", + [multicodes.SHELTER_FILE_MANIFEST]: "application/vnd.shelter.filemanifest+json", + [multicodes.SHELTER_FILE_CHUNK]: "application/vnd.shelter.filechunk+octet-stream" +}; +var limiterKey = (ip) => { + const ipVersion = isIP(ip); + if (ipVersion === 4) { + return ip; + } else if (ipVersion === 6) { + const [address, zoneIdx] = ip.split("%"); + const segments = address.split(":"); + let isCompressed = false; + for (let i2 = 0; i2 < segments.length - 1; i2++) { + if (!isCompressed && segments[i2] === "") { + const requiredSegments = 8 - (segments.length - 1); + if (requiredSegments < 0) { + throw new Error("Invalid IPv6 address: too many segments"); + } + if ((i2 === 0 || i2 === segments.length - 2) && segments[i2 + 1] === "") { + segments[i2 + 1] = "0"; + } + if (i2 === 0 && segments.length === 3 && segments[i2 + 2] === "") { + segments[i2 + 2] = "0"; + } + segments.splice(i2, 1, ...new Array(requiredSegments).fill("0")); + isCompressed = true; + continue; + } + segments[i2] = segments[i2].replace(/^0+/, "0"); + } + if (segments.length === 8 && isIP(segments[7]) === 4) { + return segments[7]; + } else if (segments.length === 8) { + if (zoneIdx) { + segments[7] = segments[7].replace(/^0+/, "0"); + return segments.join(":").toLowerCase() + "%" + zoneIdx; + } else { + return segments.slice(0, 4).join(":").toLowerCase() + "::"; + } } else { - console.log(green(`${relative7(".", filepath)}:`), destination); + throw new Error("Invalid IPv6 address"); } - uploaded.push([filepath, destination]); } - return uploaded; -} -async function uploadEntryToURL([cid, buffer], url2) { - const form = new FormData(); - form.append("hash", cid); - form.append("data", new Blob([buffer])); - return await fetch(`${url2}/dev-file`, { method: "POST", body: form }).then(handleFetchResult2("text")).then((r) => { - if (r !== `/file/${cid}`) { - throw new Error(`server returned bad URL: ${r}`); + throw new Error("Invalid address format"); +}; +var ctEq = (expected, actual) => { + let r = actual.length ^ expected.length; + for (let i2 = 0; i2 < actual.length; i2++) { + r |= actual.codePointAt(i2) ^ expected.codePointAt(i2); + } + return r === 0; +}; +var currentLimiters = []; +var rateLimitersInstalled = false; +function installRateLimiterSelectorsOnce() { + if (rateLimitersInstalled) return; + rateLimitersInstalled = true; + esm_default("sbp/selectors/register", { + "backend/server/stopRateLimiters": async function() { + const limiters = currentLimiters; + await Promise.allSettled(limiters.map((l) => l.disconnect())); + for (const limiter of limiters) { + clearInterval(limiter.interval); + } } - return `${url2}${r}`; }); } -function uploadEntryToDB([cid, buffer]) { - return esm_default("chelonia.db/set", cid, Buffer12.from(buffer)).then(() => cid); -} -function handleFetchResult2(type) { - return async function(r) { - if (!r.ok) throw new Error(`${r.status}: ${r.statusText}`); - return await r[type](); +function getStaticServeConfig() { + const isCheloniaDashboard = process7.env.IS_CHELONIA_DASHBOARD_DEV; + const appDir = import_npm_nconf4.default.get("server:appDir") || "."; + const dashboardDir = import.meta.dirname || "./build/dist-dashboard"; + return { + routePath: isCheloniaDashboard ? "/dashboard/{path*}" : "/app/{path*}", + distAssets: path5.resolve(path5.join(isCheloniaDashboard ? dashboardDir : appDir, "assets")), + distIndexHtml: path5.resolve(path5.join(isCheloniaDashboard ? dashboardDir : appDir, "index.html")), + redirect: isCheloniaDashboard ? "/dashboard/" : "/app/" }; } -var module2 = { - builder: (yargs) => { - return yargs.option("url", { - describe: "URL of a remote server", - requiresArg: true, - string: true - }).positional("files", { - describe: "Files to upload", - demandOption: true, - array: true, - type: "string" - }); - }, - command: "upload ", - describe: "Requires read and write access to the destination.", - postHandler: (argv) => { - return void upload(argv); +var errorMapper = (e2) => { + switch (e2?.name) { + case "BackendErrorNotFound": + throw new HTTPException(404); + case "BackendErrorGone": + throw new HTTPException(410); + case "BackendErrorBadData": + throw new HTTPException(422, { message: e2.message }); + default: + console.error(e2, "Unexpected backend error"); + throw new HTTPException(500, { message: e2.message ?? "internal error" }); } }; -var CONTRACT_TEXT_PREFIX = "t|"; -var CONTRACT_MANIFEST_PREFIX = "m|"; -var ContractBodySchema = object({ - contract: object({ file: string2() }), - contractSlim: object({ file: string2() }).optional() -}); -async function deploy(args) { - const { manifests } = args; - const toUpload = []; - const manifestSet = /* @__PURE__ */ new Set(); - for (const manifestPath of manifests) { - try { - const realPath = await Deno.realPath(manifestPath); - const info = await Deno.lstat(realPath); - if (info.isDirectory) { - const items = await findManifestFiles(realPath); - for (const item of items) { - manifestSet.add(item); +function getClientIP(c) { + const headerIP = c.req.header("x-real-ip"); + if (headerIP) return headerIP; + try { + const info = getConnInfo(c); + return info.remote.address || "unknown"; + } catch { + return "unknown"; + } +} +function notFoundNoCache(c) { + return c.body(null, 404, { "Cache-Control": "no-store" }); +} +function safePathWithin(base2, subpath) { + const resolved = path5.resolve(base2, subpath); + if (!resolved.startsWith(base2 + path5.sep) && resolved !== base2) return null; + return resolved; +} +function serveAsset(c, subpath, assetsDir) { + const basename72 = path5.basename(subpath); + const filePath = safePathWithin(assetsDir, subpath); + if (!filePath) return Promise.resolve(notFoundNoCache(c)); + return Deno.readFile(filePath).then((file) => { + const headers = {}; + if (basename72.includes("-cached")) { + headers["ETag"] = `"${basename72}"`; + headers["Cache-Control"] = "public,max-age=31536000,immutable"; + } + if (subpath.includes("js/sw-")) { + console.debug("adding header: Service-Worker-Allowed /"); + headers["Service-Worker-Allowed"] = "/"; + } + const ext = path5.extname(subpath).toLowerCase(); + headers["Content-Type"] = MIME_TYPES[ext] || "application/octet-stream"; + return c.body(file, 200, headers); + }).catch(() => notFoundNoCache(c)); +} +function registerRoutes(app2) { + for (const limiter of currentLimiters) { + limiter.disconnect(); + clearInterval(limiter.interval); + } + const FILE_UPLOAD_MAX_BYTES = import_npm_nconf4.default.get("server:fileUploadMaxBytes") || 30 * MEGABYTE; + const SIGNUP_LIMIT_MIN = import_npm_nconf4.default.get("server:signup:limit:minute") || 2; + const SIGNUP_LIMIT_HOUR = import_npm_nconf4.default.get("server:signup:limit:hour") || 10; + const SIGNUP_LIMIT_DAY = import_npm_nconf4.default.get("server:signup:limit:day") || 50; + const SIGNUP_LIMIT_DISABLED = process7.env.NODE_ENV !== "production" || import_npm_nconf4.default.get("server:signup:limit:disabled"); + const ARCHIVE_MODE = import_npm_nconf4.default.get("server:archiveMode"); + const limiterPerMinute = new import_npm_bottleneck.default.Group({ + strategy: import_npm_bottleneck.default.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_MIN, + reservoirRefreshInterval: 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_MIN + }); + const limiterPerHour = new import_npm_bottleneck.default.Group({ + strategy: import_npm_bottleneck.default.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_HOUR, + reservoirRefreshInterval: 60 * 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_HOUR + }); + const limiterPerDay = new import_npm_bottleneck.default.Group({ + strategy: import_npm_bottleneck.default.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_DAY, + reservoirRefreshInterval: 24 * 60 * 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_DAY + }); + currentLimiters = [limiterPerMinute, limiterPerHour, limiterPerDay]; + installRateLimiterSelectorsOnce(); + const isCheloniaDashboard = process7.env.IS_CHELONIA_DASHBOARD_DEV; + const staticServeConfig = getStaticServeConfig(); + app2.post( + "/event", + bodyLimit({ maxSize: MEGABYTE }), + authMiddleware("chel-shelter", "optional"), + zValidator("header", eventHeaderSchema), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const ip = getClientIP(c); + try { + const payload = await c.req.text(); + if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); + const validatedHeaders = c.req.valid("header"); + const deserializedHEAD = SPMessage.deserializeHEAD(payload); + try { + const parsed = maybeParseCID(deserializedHEAD.head.manifest); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { + throw new HTTPException(422, { message: "Invalid manifest" }); + } + const credentials = c.get("credentials"); + if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { + const manifest2 = await esm_default("chelonia.db/get", deserializedHEAD.head.manifest); + const parsedManifest = JSON.parse(manifest2); + const { name } = JSON.parse(parsedManifest.body); + if (name !== "gi.contracts/identity") { + throw new HTTPException(401, { message: "This contract type requires ownership information" }); + } + if (import_npm_nconf4.default.get("server:signup:disabled")) { + throw new HTTPException(403, { message: "Registration disabled" }); + } + if (!SIGNUP_LIMIT_DISABLED) { + try { + const keyedIp = limiterKey(ip); + await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()); + await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()); + await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()); + } catch { + console.warn("rate limit hit for IP:", ip); + throw new HTTPException(429, { message: "Rate limit exceeded" }); + } + } + } + const saltUpdateToken = validatedHeaders["shelter-salt-update-token"]; + let updateSalts; + if (saltUpdateToken) { + updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken); + } + await esm_default("backend/server/handleEntry", deserializedHEAD, payload); + await updateSalts?.(deserializedHEAD.hash); + if (deserializedHEAD.isFirstMessage) { + if (credentials?.billableContractID) { + await esm_default("backend/server/saveOwner", credentials.billableContractID, deserializedHEAD.contractID); + } else { + await esm_default("backend/server/registerBillableEntity", deserializedHEAD.contractID); + } + const name = validatedHeaders["shelter-namespace-registration"]; + if (name) { + const cheloniaState = esm_default("chelonia/rootState"); + if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === "gi.contracts/identity") { + try { + await esm_default("backend/db/registerName", name, deserializedHEAD.contractID); + } catch (registerErr) { + if (registerErr.name === "BackendErrorConflict") { + throw new HTTPException(409, { message: "Name already exists" }); + } + throw registerErr; + } + const saltRegistrationToken = validatedHeaders["shelter-salt-registration-token"]; + console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`); + if (saltRegistrationToken) { + await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken); + } + } + } + const deletionTokenDgst = validatedHeaders["shelter-deletion-token-digest"]; + if (deletionTokenDgst) { + await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst); + } + } + await esm_default("backend/server/updateSize", deserializedHEAD.contractID, Buffer14.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : void 0); + } catch (err) { + if (err instanceof HTTPException) throw err; + console.error(err, import_npm_chalk.default.bold.yellow(err.name)); + if (err.name === "ChelErrorDBBadPreviousHEAD" || err.name === "ChelErrorAlreadyProcessed") { + const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", deserializedHEAD.contractID) ?? { HEAD: null, height: 0 }; + return c.json({ message: err.message, data: { HEADinfo } }, 409, { + "shelter-headinfo-head": HEADinfo.HEAD, + "shelter-headinfo-height": String(HEADinfo.height) + }); + } else if (err.name === "ChelErrorSignatureError") { + throw new HTTPException(422, { message: "Invalid signature" }); + } else if (err.name === "ChelErrorSignatureKeyUnauthorized") { + throw new HTTPException(403, { message: "Unauthorized signing key" }); + } + throw err; } - } else { - manifestSet.add(realPath); + return c.text(deserializedHEAD.hash); + } catch (err) { + if (err instanceof HTTPException) throw err; + err.ip = ip; + logger_default.error(err, "POST /event", err.message); + throw err; } - } catch { - console.warn(`Skipping invalid path: ${manifestPath}`); - continue; } - } - for (const manifestPath of manifestSet) { - const manifestText = await Deno.readTextFile(manifestPath); - const json = JSON.parse(manifestText); - const body = ContractBodySchema.parse(JSON.parse(json.body)); - const dirname82 = dirname8(manifestPath); - toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contract.file)); - if (body.contractSlim) { - toUpload.push(CONTRACT_TEXT_PREFIX + join8(dirname82, body.contractSlim.file)); + ); + app2.get( + "/eventsAfter/:contractID/:since/:limit?", + zValidator("param", eventsAfterParamSchema), + async function(c) { + const { contractID, since, limit } = c.req.valid("param"); + const keyOps2 = c.req.query("keyOps"); + const ip = getClientIP(c); + try { + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); + } + const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: keyOps2 === "true" }); + c.req.raw.signal.addEventListener("abort", () => stream.destroy()); + const streamHeaders = stream.headers || {}; + const webStream = Readable3.toWeb(stream); + return new Response(webStream, { + headers: { "content-type": "application/octet-stream", ...streamHeaders } + }); + } catch (err) { + if (err instanceof HTTPException) throw err; + err.ip = ip; + logger_default.error(err, `GET /eventsAfter/${contractID}/${since}`, err.message); + errorMapper(err); + } } - toUpload.push(CONTRACT_MANIFEST_PREFIX + manifestPath); - } - await upload({ ...args, files: toUpload }, true); -} -var module3 = { - builder: (yargs) => { - return yargs.option("url", { - describe: "URL of a remote server", - requiresArg: true, - string: true - }).positional("manifests", { - describe: "Manifest files to deploy (if a directory is passed in, all manifests in that directory, and sub-directories, will be added)", - demandOption: true, - array: true, - type: "string" + ); + app2.get( + "/ownResources", + authMiddleware("chel-shelter", "required"), + async function(c) { + const billableContractID = c.get("credentials").billableContractID; + const resources = (await esm_default("chelonia.db/get", `_private_resources_${billableContractID}`))?.split("\0"); + return c.json(resources || []); + } + ); + if (process7.env.NODE_ENV === "development") { + const levelToColor = { + error: import_npm_chalk.default.bold.red, + warn: import_npm_chalk.default.yellow, + log: import_npm_chalk.default.green, + info: import_npm_chalk.default.green, + debug: import_npm_chalk.default.blue + }; + app2.post("/log", async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const body = await c.req.json(); + if (!body.level || !body.value) throw new HTTPException(400, { message: "level and value are required" }); + const ip = getClientIP(c); + const log2 = levelToColor[body.level]; + console.debug(import_npm_chalk.default.bold.yellow(`REMOTE LOG (${ip}): `) + log2(`[${body.level}] ${body.value}`)); + return c.body(null, 200); }); - }, - command: "deploy ", - describe: "", - postHandler: (argv) => { - return deploy(argv); } -}; -init_esm(); -init_database(); -async function eventsAfter2({ limit, url: url2, contractID, height }) { - try { - let messages; - if (url2) { - messages = await getRemoteMessagesSince(url2, contractID, height, limit); + app2.get("/name/:name", zValidator("param", nameParamSchema), async function(c) { + const { name } = c.req.valid("param"); + try { + const lookupResult = await esm_default("backend/db/lookupName", name); + return lookupResult ? c.text(lookupResult) : notFoundNoCache(c); + } catch (err) { + logger_default.error(err, `GET /name/${name}`, err.message); + throw err; + } + }); + app2.get("/latestHEADinfo/:contractID", zValidator("param", cidParamSchema), async function(c) { + const { contractID } = c.req.valid("param"); + try { + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400); + const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); + if (HEADinfo === "") { + throw new HTTPException(410); + } + if (!HEADinfo) { + console.warn(`[backend] latestHEADinfo not found for ${contractID}`); + return notFoundNoCache(c); + } + return c.json(HEADinfo, 200, { "Cache-Control": "no-store" }); + } catch (err) { + if (err instanceof HTTPException) throw err; + logger_default.error(err, `GET /latestHEADinfo/${contractID}`, err.message); + throw err; + } + }); + app2.get("/time", function(c) { + return c.text((/* @__PURE__ */ new Date()).toISOString(), 200, { + "Cache-Control": "no-store" + }); + }); + app2.post("/streams-test", async function(c) { + const raw2 = await c.req.arrayBuffer(); + const buf2 = Buffer14.from(raw2); + if (buf2.byteLength === 2 && buf2.toString() === "ok") { + return c.body(null, 204); } else { - await initDB({ skipDbPreloading: true }); - messages = await getMessagesSince(contractID, height, limit); + throw new HTTPException(400); + } + }); + if (process7.env.NODE_ENV === "development") { + app2.post("/dev-file", bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + try { + console.log("FILE UPLOAD!"); + const formData = await c.req.parseBody({ all: true }); + const hash3 = formData["hash"]; + const data = formData["data"]; + if (!hash3) throw new HTTPException(400, { message: "missing hash" }); + if (!data) throw new HTTPException(400, { message: "missing data" }); + const parsed = maybeParseCID(hash3); + if (!parsed) throw new HTTPException(400, { message: "invalid hash" }); + const ourHash = createCID(data, parsed.code); + if (ourHash !== hash3) { + console.error(`hash(${hash3}) != ourHash(${ourHash})`); + throw new HTTPException(400, { message: "bad hash!" }); + } + await esm_default("chelonia.db/set", hash3, data); + return c.text("/file/" + hash3); + } catch (err) { + if (err instanceof HTTPException) throw err; + logger_default.error(err); + throw new HTTPException(500, { message: "File upload failed" }); + } + }); + } + app2.post( + "/file", + bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), + authMiddleware("chel-shelter", "required"), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + try { + console.info("FILE UPLOAD!"); + const credentials = c.get("credentials"); + if (!credentials?.billableContractID) { + throw new HTTPException(401, { message: "Uploading files requires ownership information" }); + } + const contentType = c.req.header("content-type") || ""; + if (!contentType.includes("multipart/form-data")) { + throw new HTTPException(400, { message: "Expected multipart/form-data" }); + } + const formData = await c.req.formData(); + const manifestFile = formData.get("manifest"); + if (!manifestFile) throw new HTTPException(400, { message: "missing manifest" }); + if (manifestFile.name !== "manifest.json") throw new HTTPException(400, { message: "wrong manifest filename" }); + const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()); + const manifest2 = (() => { + try { + return JSON.parse(Buffer14.from(manifestPayload).toString()); + } catch { + throw new HTTPException(422, { message: "Error parsing manifest" }); + } + })(); + if (typeof manifest2 !== "object") throw new HTTPException(422, { message: "manifest format is invalid" }); + if (manifest2.version !== "1.0.0") throw new HTTPException(422, { message: "unsupported manifest version" }); + if (manifest2.cipher !== "aes256gcm") throw new HTTPException(422, { message: "unsupported cipher" }); + if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new HTTPException(422, { message: "missing chunks" }); + const chunkFiles = []; + for (let i2 = 0; ; i2++) { + const chunkFile = formData.get(String(i2)); + if (!chunkFile) break; + chunkFiles.push(chunkFile); + } + let ourSize = 0; + const chunks = await Promise.all(manifest2.chunks.map(async (chunk, i2) => { + if (!Array.isArray(chunk) || chunk.length !== 2 || typeof chunk[0] !== "number" || typeof chunk[1] !== "string" || !Number.isSafeInteger(chunk[0]) || chunk[0] <= 0) { + throw new HTTPException(422, { message: "bad chunk description" }); + } + if (!chunkFiles[i2]) { + throw new HTTPException(400, { message: "chunk missing in submitted data" }); + } + const chunkPayload = new Uint8Array(await chunkFiles[i2].arrayBuffer()); + const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK); + if (chunkPayload.byteLength !== chunk[0]) { + throw new HTTPException(400, { message: "bad chunk size" }); + } + if (ourHash !== chunk[1]) { + throw new HTTPException(400, { message: "bad chunk hash" }); + } + ourSize += chunk[0]; + return [ourHash, chunkPayload]; + })); + if (ourSize !== manifest2.size) throw new HTTPException(400, { message: "Mismatched total size" }); + const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST); + if (await esm_default("chelonia.db/get", manifestHash)) { + throw new Error(`Manifest ${manifestHash} already exists`); + } + await Promise.all(chunks.map(async ([cid]) => { + const exists = !!await esm_default("chelonia.db/get", cid); + if (exists) { + throw new Error(`Chunk ${cid} already exists`); + } + })); + await Promise.all(chunks.map(([cid, data]) => esm_default("chelonia.db/set", cid, data))); + await esm_default("chelonia.db/set", manifestHash, manifestPayload); + await esm_default("backend/server/saveOwner", credentials.billableContractID, manifestHash); + const size = manifest2.size + manifestPayload.byteLength; + await esm_default("backend/server/updateSize", manifestHash, size); + await esm_default("backend/server/updateContractFilesTotalSize", credentials.billableContractID, size); + const deletionTokenDgst = c.req.header("shelter-deletion-token-digest"); + if (deletionTokenDgst) { + await esm_default("chelonia.db/set", `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst); + } + return c.text(manifestHash); + } catch (err) { + if (err instanceof HTTPException) throw err; + logger_default.error(err, "POST /file", err.message); + throw err; + } + } + ); + app2.get("/file/:hash", zValidator("param", cidHashParamSchema), async function(c) { + const { hash: hash3 } = c.req.valid("param"); + const parsed = maybeParseCID(hash3); + if (!parsed) { + throw new HTTPException(400); + } + const blobOrString = await esm_default("chelonia.db/get", `any:${hash3}`); + if (blobOrString?.length === 0) { + throw new HTTPException(410); + } else if (!blobOrString) { + return notFoundNoCache(c); + } + const type = cidLookupTable[parsed.code] || "application/octet-stream"; + return c.body(blobOrString, 200, { + "ETag": `"${hash3}"`, + "Cache-Control": "public,max-age=31536000,immutable", + // CSP to disable everything -- this only affects direct navigation to the + // `/file` URL. + // The CSP below prevents any sort of resource loading or script execution + // on direct navigation. The `nosniff` header instructs the browser to + // honour the provided content-type. + "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox", + "X-Content-Type-Options": "nosniff", + "Content-Type": type + }); + }); + app2.post( + "/deleteFile/:hash", + authMiddleware(["chel-shelter", "chel-bearer"], "required"), + zValidator("param", cidHashParamSchema), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const { hash: hash3 } = c.req.valid("param"); + const strategy = c.get("authStrategy"); + const parsed = maybeParseCID(hash3); + if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { + throw new HTTPException(400); + } + const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); + if (!owner) { + throw new HTTPException(404); + } + const credentials = c.get("credentials"); + switch (strategy) { + case "chel-shelter": { + const ultimateOwner = await lookupUltimateOwner(owner); + if (!ctEq(credentials.billableContractID, ultimateOwner)) { + throw new HTTPException(401, { message: "Invalid shelter auth" }); + } + break; + } + case "chel-bearer": { + const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); + if (!expectedTokenDgst) { + throw new HTTPException(404); + } + const tokenDgst = blake32Hash(credentials.token); + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: "Invalid token" }); + } + break; + } + default: + throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); + } + try { + await esm_default("backend/deleteFile", hash3, null, true); + return c.body(null, 200); + } catch (e2) { + errorMapper(e2); + } + } + ); + app2.post( + "/deleteContract/:hash", + authMiddleware(["chel-shelter", "chel-bearer"], "required"), + zValidator("param", cidHashParamSchema), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const { hash: hash3 } = c.req.valid("param"); + const strategy = c.get("authStrategy"); + const credentials = c.get("credentials"); + switch (strategy) { + case "chel-shelter": { + const owner = await esm_default("chelonia.db/get", `_private_owner_${hash3}`); + if (!owner) { + throw new HTTPException(404); + } + const ultimateOwner = await lookupUltimateOwner(owner); + if (!ctEq(credentials.billableContractID, ultimateOwner)) { + throw new HTTPException(401, { message: "Invalid shelter auth" }); + } + break; + } + case "chel-bearer": { + const expectedTokenDgst = await esm_default("chelonia.db/get", `_private_deletionTokenDgst_${hash3}`); + if (!expectedTokenDgst) { + throw new HTTPException(404); + } + const tokenDgst = blake32Hash(credentials.token); + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: "Invalid token" }); + } + break; + } + default: + throw new HTTPException(401, { message: "Missing or invalid auth strategy" }); + } + const username = await esm_default("chelonia.db/get", `_private_cid2name_${hash3}`); + try { + const [id] = esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", hash3, null, true]); + if (username) { + const ip = getClientIP(c); + console.info({ contractID: hash3, username, ip, taskId: id }, "Scheduled deletion on named contract"); + } + return c.json({ id }, 202); + } catch (e2) { + errorMapper(e2); + } + } + ); + app2.post( + "/kv/:contractID/:key", + bodyLimit({ maxSize: 6 * MEGABYTE }), + authMiddleware("chel-shelter", "required"), + zValidator("param", kvParamSchema), + async function(c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const { contractID, key } = c.req.valid("param"); + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); + } + const credentials = c.get("credentials"); + if (!ctEq(credentials.billableContractID, contractID)) { + throw new HTTPException(401); + } + const payloadBuffer = Buffer14.from(await c.req.arrayBuffer()); + return esm_default("chelonia/queueInvocation", contractID, async () => { + const existing = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); + const expectedEtag = c.req.header("if-match"); + if (!expectedEtag) { + throw new HTTPException(400, { message: "if-match is required" }); + } + const cid = existing ? createCID(existing, multicodes.RAW) : ""; + if (expectedEtag === "*") { + } else { + if (!expectedEtag.split(",").map((v2) => v2.trim()).includes(`"${cid}"`)) { + return new Response(existing || "", { + status: 412, + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` + } + }); + } + } + try { + const serializedData = JSON.parse(payloadBuffer.toString()); + const { contracts } = esm_default("chelonia/rootState"); + if (contracts[contractID].height !== Number(serializedData.height)) { + return new Response(existing || "", { + status: 409, + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` + } + }); + } + esm_default("chelonia/parseEncryptedOrUnencryptedDetachedMessage", { + contractID, + serializedData, + meta: key + }); + } catch (parseErr) { + if (parseErr instanceof Response) throw parseErr; + throw new HTTPException(422); + } + const existingSize = existing ? Buffer14.from(existing).byteLength : 0; + await esm_default("chelonia.db/set", `_private_kv_${contractID}_${key}`, payloadBuffer); + await esm_default("backend/server/updateSize", contractID, payloadBuffer.byteLength - existingSize); + await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key); + esm_default("backend/server/broadcastKV", contractID, key, payloadBuffer.toString()).catch((e2) => console.error(e2, "Error broadcasting KV update", contractID, key)); + return c.body(null, 204); + }); } - console.log(JSON.stringify(messages, null, 2)); - } catch (error2) { - exit(error2); - } -} -async function getMessagesSince(contractID, sinceHeight, limit) { - const readable = await esm_default("backend/db/streamEntriesAfter", contractID, sinceHeight, limit); - return new Promise((resolve82, reject) => { - const data = []; - readable.on("readable", () => { - let chunk; - while (null !== (chunk = readable.read())) { - data.push(chunk); + ); + app2.get( + "/kv/:contractID/:key", + authMiddleware("chel-shelter", "required"), + zValidator("param", kvParamSchema), + async function(c) { + const { contractID, key } = c.req.valid("param"); + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400); } - }); - readable.on("error", reject); - readable.on("end", () => { - const events = JSON.parse(data.join("")).map((s) => { - return JSON.parse(new TextDecoder().decode(decodeBase64(s))); + const credentials = c.get("credentials"); + if (!ctEq(credentials.billableContractID, contractID)) { + throw new HTTPException(401); + } + const result = await esm_default("chelonia.db/get", `_private_kv_${contractID}_${key}`); + if (!result) { + return notFoundNoCache(c); + } + const cid = createCID(result, multicodes.RAW); + return new Response(result, { + headers: { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"`, + "Cache-Control": "no-store" + } }); - resolve82(events); - }); + } + ); + app2.get("/serverMessages", function(c) { + const messages = import_npm_nconf4.default.get("server:messages"); + if (!messages) return c.json([]); + return c.json(messages, 200, { "Cache-Control": "no-store" }); }); -} -async function getRemoteMessagesSince(src2, contractID, sinceHeight, limit) { - const response = await fetch(`${src2}/eventsAfter/${contractID}/${sinceHeight}`); - if (!response.ok) { - const bodyText = await response.text().catch(() => "") || ""; - throw new Error(`failed network request to ${src2}: ${response.status} - ${response.statusText} - '${bodyText}'`); - } - const b64messages = await response.json(); - if (b64messages.length > limit) { - b64messages.length = limit; + app2.get("/assets/:subpath{.+}", async function(c) { + const subpath = c.req.param("subpath"); + return serveAsset(c, subpath, staticServeConfig.distAssets); + }); + if (isCheloniaDashboard) { + app2.get("/dashboard/assets/:subpath{.+}", async function(c) { + const subpath = c.req.param("subpath"); + return serveAsset(c, subpath, staticServeConfig.distAssets); + }); } - return b64messages.map((b64str) => JSON.parse(new TextDecoder().decode(decodeBase64(b64str)))); -} -var module4 = { - builder: (yargs) => { - return yargs.option("limit", { - describe: "Limit", - default: 50, - number: true, - requiresArg: true, - coerce(v2) { - if (!Number.isSafeInteger(v2) || v2 < 0) { - throw new Error("--limit must be a valid non-negative integer"); + app2.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { + try { + const file = await Deno.readFile(staticServeConfig.distIndexHtml); + return c.body(file, 200, { "Content-Type": "text/html" }); + } catch { + return notFoundNoCache(c); + } + }); + app2.get("/", function(c) { + return c.redirect(staticServeConfig.redirect); + }); + app2.post( + "/zkpp/register/:name", + zValidator("param", nameParamSchema), + zValidatorFormOrJson(zkppRegisterBodySchema), + async function(c) { + const { name } = c.req.valid("param"); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + const payload = c.get("validatedBody"); + const lookupResult = await esm_default("backend/db/lookupName", name); + if (lookupResult) { + throw new HTTPException(409); + } + try { + if ("b" in payload) { + const result = registrationKey(name, payload.b); + if (result) { + return c.json(result); + } + } else { + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); + if (result) { + return c.json(result); + } } - return v2; + } catch (e2) { + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); + console.error(e2, "Error at POST /zkpp/register/:name: " + e2.message); } - }).option("url", { - describe: "URL of a remote server", - string: true - }).positional("contractID", { - describe: "Contract ID", - demandOption: true, - type: "string" - }).positional("height", { - describe: "Height", - demandOption: true, - type: "number" - }); - }, - command: "eventsAfter ", - describe: "Displays a JSON array of the first LIMIT events that happened in a given contract, since a given entry identified by its hash.\n\n- Older events are displayed first.\n- The output is parseable with tools such as 'jq'.\n- If --url is given, then its /eventsAfter REST endpoint will be called.\n", - postHandler: (argv) => { - return eventsAfter2(argv); - } -}; -init_esm(); -init_database(); -async function get({ key, url: url2 }) { - if (!url2) { - await initDB({ skipDbPreloading: true }); - } - try { - const data = url2 ? await readRemoteData(url2, key) : await esm_default("chelonia.db/get", key); - if (data === void 0) exit(`no entry found for ${key}`); - if (typeof data === "string") { - console.log(data); - } else { - await writeAll(Deno.stdout, data); + throw new HTTPException(500, { message: "internal error" }); } - } catch (error2) { - exit(error2); - } + ); + app2.get( + "/zkpp/:contractID/auth_hash", + zValidator("param", zkppContractParamSchema), + zValidator("query", zkppAuthHashQuerySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + const { b } = c.req.valid("query"); + try { + const challenge = await getChallenge(contractID, b); + return challenge ? c.json(challenge) : notFoundNoCache(c); + } catch (e2) { + ; + e2.ip = getClientIP(c); + console.error(e2, "Error at GET /zkpp/{contractID}/auth_hash: " + e2.message); + } + throw new HTTPException(500, { message: "internal error" }); + } + ); + app2.get( + "/zkpp/:contractID/contract_hash", + zValidator("param", zkppContractParamSchema), + zValidator("query", zkppContractHashQuerySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + const { r, s, sig, hc } = c.req.valid("query"); + try { + const salt = await getContractSalt(contractID, r, s, sig, hc); + if (salt) { + return c.json(salt); + } + } catch (e2) { + ; + e2.ip = getClientIP(c); + console.error(e2, "Error at GET /zkpp/{contractID}/contract_hash: " + e2.message); + } + throw new HTTPException(500, { message: "internal error" }); + } + ); + app2.post( + "/zkpp/:contractID/updatePasswordHash", + zValidator("param", zkppContractParamSchema), + zValidator("json", zkppUpdatePasswordBodySchema), + async function(c) { + const { contractID } = c.req.valid("param"); + if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); + try { + const payload = c.req.valid("json"); + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); + if (result) { + return c.json(result); + } + } catch (e2) { + if (e2 instanceof HTTPException) throw e2; + e2.ip = getClientIP(c); + console.error(e2, "Error at POST /zkpp/{contractID}/updatePasswordHash: " + e2.message); + } + throw new HTTPException(500, { message: "internal error" }); + } + ); } -var module5 = { - builder: (yargs) => { - return yargs.option("url", { - describe: "URL of a remote server", - string: true - }).positional("key", { - describe: "Database key", - demandOption: true, - type: "string" - }); - }, - command: "get ", - describe: "Retrieves the entry associated with a given key, from a given database or server.\n\n- The output can be piped to a file, like this: chel get https://url.com mygreatlongkey > file.png", - postHandler: (argv) => { - return get(argv); - } -}; +var CREDITS_WORKER_TASK_TIME_INTERVAL = 3e5; +var OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL = 3e4; +init_esm4(); init_functions(); -async function hash22({ filename }, multicode = multicodes.RAW, internal = false) { - const [cid] = await createEntryFromFile(filename, multicode); - if (!internal) { - console.log(`CID(${filename}):`, cid); - } - return cid; -} -var module6 = { - builder: (yargs) => { - return yargs.positional("filename", { - describe: "File name", - demandOption: true, - type: "string" - }); - }, - command: "hash ", - describe: "Computes and logs the content identifier (CID) for the given file.\n' + 'File contents will be interpreted as raw binary data, unless the file extension is '.json'.", - postHandler: (argv) => { - return void hash22(argv); - } +init_esm(); +var rfc8291Ikm_default = async (uaPublic, salt) => { + const [[asPrivateKey, asPublic], uaPublicKey] = await Promise.all([ + crypto.subtle.generateKey( + { + name: "ECDH", + namedCurve: "P-256" + }, + false, + ["deriveKey"] + ).then(async (asKeyPair) => { + const asPublic2 = await crypto.subtle.exportKey( + "raw", + asKeyPair.publicKey + ); + return [asKeyPair.privateKey, asPublic2]; + }), + crypto.subtle.importKey( + "raw", + uaPublic, + { name: "ECDH", namedCurve: "P-256" }, + false, + [] + ) + ]); + const ecdhSecret = await crypto.subtle.deriveKey( + { + name: "ECDH", + public: uaPublicKey + }, + asPrivateKey, + { + name: "HKDF", + hash: "SHA-256" + }, + false, + ["deriveBits"] + ); + const infoString = new Uint8Array([ + 87, + 101, + 98, + 80, + 117, + 115, + 104, + 58, + 32, + 105, + 110, + 102, + 111, + 0 + ]); + const info = new Uint8Array(infoString.byteLength + uaPublic.byteLength + asPublic.byteLength); + info.set(infoString, 0); + info.set(uaPublic, infoString.byteLength); + info.set( + new Uint8Array(asPublic), + infoString.byteLength + uaPublic.byteLength + ); + const IKM = await crypto.subtle.deriveBits( + { + name: "HKDF", + hash: "SHA-256", + salt, + info + }, + ecdhSecret, + 32 << 3 + ); + return [asPublic, IKM]; }; -init_esm7(); -var keygen2 = async (args) => { - await revokeNet(); - const key = keygen(EDWARDS25519SHA512BATCH); - const pubKeyData = { - version: "1.0.0", - pubkey: serializeKey(key, false) - }; - const keyData = { - ...pubKeyData, - privkey: serializeKey(key, true) - }; - const result = JSON.stringify(keyData); - const pubResult = JSON.stringify(pubKeyData); - const idx = keyId(key).slice(-12); - const outFile = args.out || `${EDWARDS25519SHA512BATCH}-${idx}.json`; - const pubOutFile = args.pubout || `${EDWARDS25519SHA512BATCH}-${idx}.pub.json`; - await Deno.writeTextFile(outFile, result); - console.log(green("wrote:"), outFile, blue("(secret)")); - await Deno.writeTextFile(pubOutFile, pubResult); - console.log(green("wrote:"), pubOutFile, blue("(public)")); +var addSubscriptionToIndex = appendToIndexFactory("_private_webpush_index"); +var deleteSubscriptionFromIndex = removeFromIndexFactory("_private_webpush_index"); +var saveSubscription = (server, subscriptionId) => { + return esm_default("chelonia.db/set", `_private_webpush_${subscriptionId}`, JSON.stringify({ + settings: server.pushSubscriptions[subscriptionId].settings, + subscriptionInfo: server.pushSubscriptions[subscriptionId], + channelIDs: [...server.pushSubscriptions[subscriptionId].subscriptions] + })).catch((e2) => { + console.error(e2, "Error saving subscription", subscriptionId); + throw e2; + }); }; -var module7 = { - builder: (yargs) => { - return yargs.option("out", { - describe: "File name for the secret key", - requiresArg: true, - string: true - }).option("pubout", { - describe: "File name for the public key", - requiresArg: true, - string: true - }); - }, - command: "keygen", - describe: "", - postHandler: (argv) => { - return keygen2(argv); - } +var addChannelToSubscription = (server, subscriptionId, channelID) => { + server.pushSubscriptions[subscriptionId].subscriptions.add(channelID); + return saveSubscription(server, subscriptionId); }; -init_esm7(); -init_functions(); -function isSigningKeyDescriptor(obj) { - return obj !== null && typeof obj === "object" && typeof obj.privkey === "string"; -} -async function manifest(args) { - await revokeNet(); - const { signingKey: keyFileRaw, contractBundle: contractFileRaw } = args; - if (typeof keyFileRaw !== "string" || typeof contractFileRaw !== "string") { - exit("Missing or invalid key or contract file"); - } - const keyFile = keyFileRaw; - const contractFile = contractFileRaw; - const parsedFilepath = parse7(contractFile); - const { name: contractFileName, base: contractBasename, dir: contractDir } = parsedFilepath; - const name = args.name || contractFileName; - const version3 = args.contractVersion || "x"; - const slim = args.slim; - const outFile = args.out || join8(contractDir, `${contractFileName}.${version3}.manifest.json`); - if (!keyFile) exit("Missing signing key file"); - const signingKeyDescriptorRaw = await readJsonFile(keyFile); - if (!isSigningKeyDescriptor(signingKeyDescriptorRaw)) { - exit("Invalid signing key file: missing or invalid privkey", true); +var deleteChannelFromSubscription = (server, subscriptionId, channelID) => { + server.pushSubscriptions[subscriptionId].subscriptions.delete(channelID); + return saveSubscription(server, subscriptionId); +}; +var removeSubscription = async (subscriptionId) => { + try { + const server = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const subscription = server.pushSubscriptions[subscriptionId]; + if (subscription) { + delete server.pushSubscriptions[subscriptionId]; + if (server.subscribersByChannelID) { + subscription.subscriptions.forEach((channelID) => { + server.subscribersByChannelID[channelID]?.delete(subscription); + }); + } + } else { + } + await esm_default("chelonia.db/delete", `_private_webpush_${subscriptionId}`); + await deleteSubscriptionFromIndex(subscriptionId); + } catch (e2) { + console.error(e2, "Error removing subscription", subscriptionId); } - const signingKeyDescriptor = signingKeyDescriptorRaw; - const signingKey = deserializeKey(signingKeyDescriptor.privkey); - const publicKeys = Array.from(new Set( - [serializeKey(signingKey, false)].concat(...await Promise.all(args.key?.map( - async (kf) => { - if (typeof kf !== "string" && typeof kf !== "number") { - exit(`Invalid key file reference: ${String(kf)}`); - } - const descriptor = await readJsonFile(String(kf)); - const key = deserializeKey(descriptor.pubkey); - if (key.type !== EDWARDS25519SHA512BATCH) { - exit(`Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.`); - } - return serializeKey(key, false); +}; +var subscriptionInfoWrapper = (subscriptionId, subscriptionInfo, extra) => { + subscriptionInfo.endpoint = new URL(subscriptionInfo.endpoint); + Object.defineProperties(subscriptionInfo, { + "id": { + get() { + return subscriptionId; } - ) || [])) - )); - const body = { - name, - version: version3, - contract: { - hash: await hash22({ ...args, filename: contractFile }, multicodes.SHELTER_CONTRACT_TEXT, true), - file: contractBasename }, - signingKeys: publicKeys - }; - if (typeof slim === "string" && slim !== "") { - body.contractSlim = { - file: basename8(slim), - hash: await hash22({ ...args, filename: slim }, multicodes.SHELTER_CONTRACT_TEXT, true) - }; - } - const serializedBody = JSON.stringify(body); - const head = { manifestVersion: "1.0.0" }; - const serializedHead = JSON.stringify(head); - const manifest2 = JSON.stringify({ - head: serializedHead, - body: serializedBody, - signature: { - keyId: keyId(signingKey), - value: sign(signingKey, serializedBody + serializedHead) + // These encryption keys are used for encrypting push notification bodies + // and are unrelated to VAPID, which is used for provenance. + "encryptionKeys": { + get: /* @__PURE__ */ (() => { + let count = 0; + let resultPromise; + let salt; + let uaPublic; + return function() { + if ((count | 0) === 0) { + if (!salt) { + salt = Buffer15.from(this.keys.auth, "base64url"); + } + if (!uaPublic) { + uaPublic = Buffer15.from(this.keys.p256dh, "base64url"); + } + resultPromise = rfc8291Ikm_default(uaPublic, salt); + count = 1; + } else { + count++; + } + return resultPromise; + }; + })() + }, + "settings": { + value: extra.settings || {} + }, + "sockets": { + value: /* @__PURE__ */ new Set() + }, + "subscriptions": { + value: new Set(extra.channelIDs) } }); - if (args.out === "-") { - console.log(manifest2); - } else { - Deno.writeTextFileSync(outFile, manifest2); - console.log(green("wrote:"), outFile); - } -} -var module8 = { - builder: (yargs) => { - return yargs.option("key", { - coerce: (v2) => Array.isArray(v2) ? v2 : [v2], - describe: "Additional public key", - requiresArg: true, - string: true - }).alias("k", "key").option("out", { - describe: "Manifest file name", - requiresArg: true, - string: true - }).option("name", { - describe: "Contract name", - requiresArg: true, - string: true - }).alias("n", "name").option("slim", { - describe: "Slim contract bundle", - requiresArg: true, - string: true - }).alias("s", "slim").option("contract-version", { - describe: "Contract version", - requiresArg: true, - string: true - }).alias("V", "contract-version").positional("signingKey", { - describe: "Signing key file", - demandOption: true, - type: "string" - }).positional("contractBundle", { - describe: "Contract bundle", - demandOption: true, - type: "string" - }); - }, - command: "manifest [-k|--key ] [-k|--key ...] [--out ] [-s|--slim ] [-V|--contract-version ] ", - describe: "Produce a signed manifest from a contract.\nIf unspecified, is set to 'x'.", - postHandler: (argv) => { - return manifest(argv); - } + Object.freeze(subscriptionInfo); + return subscriptionInfo; }; -init_esm(); -init_database(); -var import_npm_nconf3 = __toESM(require_nconf()); -var globImport_serve_database_ts = __glob({ - "./serve/database-fs.ts": () => Promise.resolve().then(() => (init_database_fs(), database_fs_exports)), - "./serve/database-redis.ts": () => Promise.resolve().then(() => (init_database_redis(), database_redis_exports)), - "./serve/database-router.test.ts": () => Promise.resolve().then(() => (init_database_router_test(), database_router_test_exports)), - "./serve/database-router.ts": () => Promise.resolve().then(() => (init_database_router(), database_router_exports)), - "./serve/database-sqlite.ts": () => Promise.resolve().then(() => (init_database_sqlite(), database_sqlite_exports)) -}); -async function migrate(args) { - const { to } = args; - if (args.fromConfig) { - const fromConfig = parse8(await readFile2(args.fromConfig, { encoding: "utf-8", flag: "r" })); - const backend = import_npm_nconf3.default.get("database:backend"); - const fromBackend = fromConfig?.database?.backend; - if (fromBackend !== backend) { - console.warn(`--from-config has backend ${fromBackend} but --from is ${backend}`); +var encryptPayload = async (subscription, data) => { + const readableStream = new Response(data).body; + if (!readableStream) throw new Error("Failed to create readable stream"); + const [asPublic, IKM] = await subscription.encryptionKeys; + return K(x2, readableStream, 32768, asPublic, IKM).then(async (bodyStream) => { + const chunks = []; + const reader = bodyStream.getReader(); + for (; ; ) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(new Uint8Array(value)); + } + return Buffer15.concat(chunks); + }); +}; +var postEvent = async (subscription, event) => { + const authorization = await vapidAuthorization(subscription.endpoint); + const body = event ? await encryptPayload(subscription, event) : void 0; + const req = await fetch(subscription.endpoint, { + method: "POST", + headers: [ + ["authorization", authorization], + ...body ? [ + ["content-encoding", "aes128gcm"], + [ + "content-type", + "application/octet-stream" + ] + ] : [], + // ['push-receipt', ''], + ["ttl", "60"] + ], + body + }); + if (!req.ok) { + const endpointHost = new URL(subscription.endpoint).host; + console.info( + await req.text().then((response) => ({ response })).catch((e2) => `ERR: ${e2?.message}`), + `Error ${req.status} sending push notification to '${subscription.id}' via ${endpointHost}` + ); + if ([401, 404, 410].includes(req.status)) { + removeSubscription(subscription.id); + throw new Error(`Error sending push: ${req.status}`); } - const fromConfigOpts = fromConfig?.database?.backendOptions?.[backend] || {}; - import_npm_nconf3.default.set(`database:backendOptions:${backend}`, fromConfigOpts); - } - try { - await initDB({ skipDbPreloading: true }); - } catch (e2) { - console.error("Error setting up database"); - exit(e2); - throw e2; - } - let backendTo; - try { - let toConfigOpts; - if (args.toConfig) { - const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); - const toBackend = toConfig?.database?.backend; - if (toBackend !== to) { - console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); - } - toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; - } else { - toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; + if (req.status === 413) { + throw new Error("Payload too large"); } - const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; - backendTo = new Ctor(toConfigOpts); - await backendTo.init(); - } catch (error2) { - exit(error2); - throw error2; } - const numKeys2 = await esm_default("chelonia.db/keyCount"); - let numMigratedKeys = 0; - let numVisitedKeys = 0; - const reportStatus = () => { - console.log(`${green("Migrated:")} ${numMigratedKeys} entries`); - }; - const checkAndExit = (() => { - let interruptCount = 0; - let shouldExit = 0; - const handleSignal2 = (signal, code2) => { - process3.on(signal, () => { - shouldExit = 128 + code2; - if (++interruptCount < 3) { - console.error(`Received signal ${signal} (${code2}). Finishing current operation.`); - } else { - console.error(`Received signal ${signal} (${code2}). Force quitting.`); - reportStatus(); - exit(shouldExit); - } - }); - }; - const checkAndExit2 = async () => { - if (shouldExit) { - await backendTo.close(); - reportStatus(); - exit(shouldExit); +}; +var pushServerActionhandlers = { + [PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY]() { + const socket = this; + socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); + }, + async [PUSH_SERVER_ACTION_TYPE.STORE_SUBSCRIPTION](payload) { + const socket = this; + const { server } = socket; + const { applicationServerKey, settings, subscriptionInfo } = payload; + if (applicationServerKey) { + const ourVapidPublicKey = getVapidPublicKey(); + const theirVapidPublicKey = Buffer15.from(applicationServerKey, "base64").toString("base64url"); + if (ourVapidPublicKey !== theirVapidPublicKey) { + socket.send(createMessage(REQUEST_TYPE.PUSH_ACTION, { type: PUSH_SERVER_ACTION_TYPE.SEND_PUBLIC_KEY, data: getVapidPublicKey() })); + console.warn({ ourVapidPublicKey, theirVapidPublicKey }, "Refusing to store subscription because the associated public VAPID key does not match ours"); + return; } - }; - [ - ["SIGHUP", 1], - ["SIGINT", 2], - ["SIGQUIT", 3], - ["SIGTERM", 15], - ["SIGUSR1", 10], - ["SIGUSR2", 11] - ].forEach(([signal, code2]) => handleSignal2(signal, code2)); - return checkAndExit2; - })(); - let lastReportedPercentage = 0; - for await (const key of esm_default("chelonia.db/iterKeys")) { - numVisitedKeys++; - if (!isValidKey(key)) { - console.debug("Skipping invalid key", key); - continue; } - let value; + let subscriptionId = null; + let host = ""; + let subscriptionWrapper = null; try { - value = await esm_default("chelonia.db/get", `any:${key}`); + subscriptionId = await getSubscriptionId(subscriptionInfo); + subscriptionWrapper = server.pushSubscriptions[subscriptionId]; + if (!subscriptionWrapper) { + console.debug(`saving new push subscription '${subscriptionId}':`, subscriptionInfo); + server.pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { settings }); + subscriptionWrapper = server.pushSubscriptions[subscriptionId]; + host = subscriptionWrapper.endpoint.host; + await addSubscriptionToIndex(subscriptionId); + await saveSubscription(server, subscriptionId); + await postEvent(subscriptionWrapper, JSON.stringify({ type: "initial" })); + } else { + host = subscriptionWrapper.endpoint.host; + if (subscriptionWrapper.sockets.size === 0) { + subscriptionWrapper.subscriptions.forEach((channelID) => { + if (!server.subscribersByChannelID[channelID]) return; + server.subscribersByChannelID[channelID].delete(subscriptionWrapper); + }); + } + } + if (socket.pushSubscriptionId) { + if (socket.pushSubscriptionId === subscriptionId) return; + await removeSubscription(socket.pushSubscriptionId); + } + socket.pushSubscriptionId = subscriptionId; + subscriptionWrapper.subscriptions.forEach((channelID) => { + server.subscribersByChannelID[channelID]?.delete(subscriptionWrapper); + }); + subscriptionWrapper.sockets.add(socket); + socket.subscriptions?.forEach((channelID) => { + subscriptionWrapper.subscriptions.add(channelID); + }); + await saveSubscription(server, subscriptionId); } catch (e2) { - reportStatus(); - console.error(`Error reading from source database key '${key}'`, e2); - await backendTo.close(); - exit(1); + console.error(e2, `[${socket.ip}] Failed to store subscription '${subscriptionId || "??"}' (${host}), removing it!`); + subscriptionId && removeSubscription(subscriptionId); throw e2; } - await checkAndExit(); - if (value === void 0) { - console.debug("Skipping empty key", key); - continue; - } - try { - await backendTo.writeData(key, value); - } catch (e2) { - reportStatus(); - console.error(`Error writing to target database key '${key}'`, e2); - await backendTo.close(); - exit(1); - throw e2; + }, + [PUSH_SERVER_ACTION_TYPE.DELETE_SUBSCRIPTION]() { + const socket = this; + const { pushSubscriptionId: subscriptionId } = socket; + if (subscriptionId) { + return removeSubscription(subscriptionId); } - await checkAndExit(); - ++numMigratedKeys; - const percentage = Math.floor(numVisitedKeys / numKeys2 * 100); - if (percentage - lastReportedPercentage >= 10) { - lastReportedPercentage = percentage; - console.log(`Migrating... ${percentage}% done`); + } +}; +var import_npm_chalk2 = __toESM(require_source()); +var import_stream2 = __toESM(require_stream(), 1); +var import_receiver = __toESM(require_receiver(), 1); +var import_sender = __toESM(require_sender(), 1); +var import_websocket = __toESM(require_websocket(), 1); +var import_websocket_server = __toESM(require_websocket_server(), 1); +var wrapper_default = import_websocket.default; +var isPushSubscriptionInfo = (x3) => { + return has(x3, "endpoint"); +}; +var { bold } = import_npm_chalk2.default; +var { PING, PONG, PUB, SUB, UNSUB, KV_FILTER } = NOTIFICATION_TYPE; +var { ERROR, OK } = RESPONSE_TYPE; +var defaultOptions3 = { + logPingRounds: process8.env.NODE_ENV !== "production" && !process8.env.CI, + logPongMessages: false, + maxPayload: 6 * 1024 * 1024, + pingInterval: 3e4 +}; +var tag2 = "[pubsub]"; +var generateSocketID = /* @__PURE__ */ (() => { + let counter = 0; + return (debugID) => String(counter++) + (debugID ? "-" + debugID : ""); +})(); +var log = logger_default.info.bind(logger_default, tag2); +log.bold = (...args) => logger_default.debug(bold(tag2, ...args)); +log.debug = logger_default.debug.bind(logger_default, tag2); +log.error = (error2, ...args) => logger_default.error(error2, bold.red(tag2, ...args)); +function createErrorResponse(data) { + return JSON.stringify({ type: ERROR, data }); +} +function createPushErrorResponse(data) { + return JSON.stringify({ + type: ERROR, + data: { + ...data, + type: REQUEST_TYPE.PUSH_ACTION } + }); +} +function createNotification(type, data) { + return JSON.stringify({ type, data }); +} +function createOkResponse(data) { + return JSON.stringify({ type: OK, data }); +} +function createServer(httpServer, options2 = {}) { + const server = new import_websocket_server.default({ + ...defaultOptions3, + ...options2, + ...{ clientTracking: true }, + server: httpServer + }); + server.channels = /* @__PURE__ */ new Set(); + server.customServerEventHandlers = { ...options2.serverHandlers }; + server.customSocketEventHandlers = { ...options2.socketHandlers }; + server.customMessageHandlers = { ...options2.messageHandlers }; + server.pingIntervalID = void 0; + server.subscribersByChannelID = /* @__PURE__ */ Object.create(null); + server.pushSubscriptions = /* @__PURE__ */ Object.create(null); + const handlers = Object.keys(defaultServerHandlers); + handlers.forEach((name) => { + server.on(name, (...args) => { + try { + ; + defaultServerHandlers[name].apply(server, args); + server.customServerEventHandlers[name]?.apply(server, args); + } catch (error2) { + server.emit("error", error2); + } + }); + }); + if (server.options.pingInterval > 0) { + server.pingIntervalID = setInterval(() => { + if (server.clients.size && server.options.logPingRounds) { + log.debug("Pinging clients"); + } + server.clients.forEach((client) => { + if (isPushSubscriptionInfo(client)) return; + if (client.pinged && !client.activeSinceLastPing) { + log(`Disconnecting irresponsive client ${client.id}`); + return client.terminate(); + } + if (client.readyState === wrapper_default.OPEN) { + client.send(createMessage(PING, Date.now()), () => { + client.activeSinceLastPing = false; + client.pinged = true; + }); + } + }); + }, server.options.pingInterval); } - reportStatus(); - await backendTo.close(); + return Object.assign(server, publicMethods2); } -var module9 = { - builder: (yargs) => { - return yargs.option("from", { - describe: "Source backend", - demandOption: true, - requiresArg: true, - string: true - }).alias("database:backend", "from").option("from-config", { - describe: "Source backend configuration", - requiresArg: true, - string: true - }).option("to", { - describe: "Destination backend", - demandOption: true, - requiresArg: true, - string: true - }).option("to-config", { - describe: "Destination backend configuration", - requiresArg: true, - string: true - }).strict(false).strictCommands(true); +var defaultServerHandlers = { + close() { + clearInterval(this.pingIntervalID); + log("Server closed"); }, - command: "migrate", - describe: "Reads all key-value pairs from a given database and creates or updates another database accordingly.\n\n- The output database will be created if necessary.\n- The source database won't be modified nor deleted.\n- Invalid key-value pairs entries will be skipped.\n- Requires read and write access to the source.\n", - postHandler: (argv) => { - return migrate(argv); + /** + * Emitted when a connection handshake completes. + * + * @see https://github.com/websockets/ws/blob/master/doc/ws.md#event-connection + * @param {ws.WebSocket} socket - The client socket that connected. + * @param {http.IncomingMessage} request - The underlying Node http GET request. + */ + connection(socket, request) { + const server = this; + const url2 = request.url; + const urlSearch = url2?.includes("?") ? url2.slice(url2.lastIndexOf("?")) : ""; + const debugID = new URLSearchParams(urlSearch).get("debugID") || ""; + const send = socket.send.bind(socket); + socket.id = generateSocketID(debugID); + socket.activeSinceLastPing = true; + socket.pinged = false; + socket.server = server; + socket.subscriptions = /* @__PURE__ */ new Set(); + socket.kvFilter = /* @__PURE__ */ new Map(); + socket.ip = request.headers["x-real-ip"] || request.headers["x-forwarded-for"]?.split(",")[0].trim() || request.socket.remoteAddress; + socket.send = function(data) { + if (typeof data === "object" && data !== null && typeof data[Symbol.toPrimitive] === "function") { + return send(data[Symbol.toPrimitive]()); + } + return send(data); + }; + log.bold(`Socket ${socket.id} connected. Total: ${this.clients.size}`); + ["close", "error", "message", "ping", "pong"].forEach((eventName) => { + socket.on(eventName, (...args) => { + if (eventName !== "message") { + log.debug(`Event '${eventName}' on socket ${socket.id}`, ...args.map((arg) => String(arg))); + } + try { + ; + defaultSocketEventHandlers[eventName]?.call(socket, ...args); + socket.server.customSocketEventHandlers[eventName]?.call(socket, ...args); + } catch (error2) { + socket.server.emit("error", error2); + socket.terminate(); + } + }); + }); + }, + error(error2) { + log.error(error2, "Server error"); + }, + headers() { + }, + listening() { + log("Server listening"); } }; -var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; -var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; -var projectRoot; -var cheloniaConfig; -function sanitizeContractName(contractName) { - return contractName.replace(RESERVED_FILE_CHARS_REPLACE, "_").replace(/\.\./g, "__"); -} -async function pin(args) { - const version3 = args["manifest-version"]; - const manifestPath = args.manifest; - projectRoot = args["dir"] || process4.cwd(); - try { - if (!manifestPath) { - await loadCheloniaConfig(); - return; +var defaultSocketEventHandlers = { + close() { + const socket = this; + const { server } = this; + for (const channelID of socket.subscriptions) { + server.subscribersByChannelID[channelID].delete(socket); } - console.log(cyan(`\u{1F4CC} Requesting pin to version: ${version3}`)); - console.log(gray(`Manifest: ${manifestPath}`)); - await loadCheloniaConfig(); - const fullManifestPath = join62(projectRoot, manifestPath); - if (!existsSync(fullManifestPath)) { - exit(`Manifest file not found: ${manifestPath}`); + socket.subscriptions.clear(); + }, + message(data) { + const socket = this; + const { server } = this; + const text = data.toString(); + let msg = { type: "" }; + try { + msg = messageParser(text); + } catch (error2) { + log.error(error2, `Malformed message: ${error2.message}`); + server.rejectMessageAndTerminateSocket(msg, socket); + return; } - const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - if (RESERVED_FILE_CHARS.test(manifestVersion) || manifestVersion.startsWith(".") || manifestVersion.endsWith(".")) { - exit(`Invalid manifest version: ${manifestVersion}`); + if (msg.type !== "pong" || server.options.logPongMessages) { + log.debug(`Received '${msg.type}' on socket ${socket.id}`, text); } - console.log(blue(`Contract name: ${fullContractName}`)); - console.log(blue(`Manifest version: ${manifestVersion}`)); - if (version3) { - if (version3 !== manifestVersion) { - console.error(red(`\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})`)); - console.error(yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)); - exit("Version mismatch between CLI and manifest"); + socket.activeSinceLastPing = true; + const defaultHandler = defaultMessageHandlers2[msg.type]; + const customHandler = server.customMessageHandlers[msg.type]; + if (defaultHandler || customHandler) { + try { + ; + defaultHandler?.call(socket, msg); + customHandler?.call(socket, msg); + } catch (error2) { + log.error(error2, "onMessage"); + server.rejectMessageAndTerminateSocket(msg, socket); } - console.log(green(`\u2705 Version validation passed: ${version3}`)); + } else { + log.error(`Unhandled message type: ${msg.type}`); + server.rejectMessageAndTerminateSocket(msg, socket); } - const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; - if (currentPinnedVersion === manifestVersion) { - console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); + } +}; +var defaultMessageHandlers2 = { + [PONG]() { + const socket = this; + socket.activeSinceLastPing = true; + }, + [PUB](msg) { + const { server } = this; + const subscribers = server.subscribersByChannelID[msg.channelID]; + server.broadcast(msg, { to: subscribers ?? [] }); + }, + [SUB]({ channelID, kvFilter }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); return; } - if (currentPinnedVersion) { - console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + if (!socket.subscriptions.has(channelID)) { + socket.subscriptions.add(channelID); + if (Array.isArray(kvFilter)) { + socket.kvFilter.set(channelID, new Set(kvFilter)); + } + if (!server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); + } + server.subscribersByChannelID[channelID].add(socket); } else { - console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); + log.debug("Already subscribed to", channelID); } - const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); - if (existsSync(contractVersionDir)) { - if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); + socket.send(createOkResponse({ type: SUB, channelID, kvFilter })); + }, + [KV_FILTER]({ channelID, kvFilter }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: SUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); + return; + } + if (socket.subscriptions.has(channelID)) { + if (Array.isArray(kvFilter)) { + socket.kvFilter.set(channelID, new Set(kvFilter)); + } else { + socket.kvFilter.delete(channelID); } - console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); } else { - await createVersionDirectory(contractName, manifestVersion); + log.debug("[KV_FILTER] Not subscribed to", channelID); } - await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); - console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); - } catch (error2) { - exit(error2); + socket.send(createOkResponse({ type: KV_FILTER, channelID, kvFilter })); + }, + [UNSUB]({ channelID }) { + const socket = this; + const { server } = this; + if (!server.channels.has(channelID)) { + socket.send(createErrorResponse( + { type: UNSUB, channelID, reason: `Unknown channel id: ${channelID}` } + )); + } + if (socket.subscriptions.has(channelID)) { + socket.subscriptions.delete(channelID); + socket.kvFilter.delete(channelID); + if (server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID].delete(socket); + } + } + socket.send(createOkResponse({ type: UNSUB, channelID })); } -} -async function parseManifest(manifestPath) { - const manifestContent = await readFile3(manifestPath, "utf8"); - const manifest2 = JSON.parse(manifestContent); - const body = JSON.parse(manifest2.body); - const fullContractName = body.name; - const manifestVersion = body.version; - const mainFile = body.contract.file; - const slimFile = body.contractSlim?.file; - if (!fullContractName || !mainFile || !manifestVersion) { - console.error(red("\u274C Invalid manifest: missing contract name, main file, or version")); - exit("Invalid manifest: missing contract name, main file, or version"); +}; +var publicMethods2 = { + /** + * Broadcasts a message, ignoring clients which are not open. + * + * @param message + * @param to - The intended recipients of the message. Defaults to every open client socket. + * @param except - A recipient to exclude. Optional. + */ + broadcast(message, { to, except, wsOnly } = {}) { + const server = this; + const msg = typeof message === "string" ? message : JSON.stringify(message); + let shortMsg; + const shortenPayload = () => { + if (!shortMsg && (typeof message === "object" && message.type === NOTIFICATION_TYPE.ENTRY && message.data)) { + delete message.data; + shortMsg = JSON.stringify(message); + } + return shortMsg; + }; + for (const client of to || server.clients) { + if (!wsOnly && isPushSubscriptionInfo(client)) { + if (msg.length > 4096 - 86 - 17) { + if (!shortenPayload()) { + console.info("Skipping too large of a payload for", client.id); + continue; + } + } + postEvent(client, shortMsg || msg).catch((e2) => { + if (e2?.message === "Payload too large") { + if (shortMsg || !shortenPayload()) { + console.info("Skipping too large of a payload for", client.id); + return; + } + postEvent(client, shortMsg).catch((e3) => { + console.error(e3, "Error posting push notification"); + }); + return; + } + console.error(e2, "Error posting push notification"); + }); + continue; + } + if (client.readyState === wrapper_default.OPEN && client !== except) { + client.send(msg); + } + } + }, + // Enumerates the subscribers of a given channel. + *enumerateSubscribers(channelID, kvKey) { + const server = this; + if (channelID in server.subscribersByChannelID) { + const subscribers = server.subscribersByChannelID[channelID]; + if (!kvKey) { + yield* subscribers; + } else { + for (const subscriber of subscribers) { + const kvFilter = subscriber.kvFilter?.get(channelID); + if (!kvFilter || kvFilter.has(kvKey)) yield subscriber; + } + } + } + }, + rejectMessageAndTerminateSocket(request, socket) { + socket.send(createErrorResponse({ ...request }), () => socket.terminate()); } - const contractName = sanitizeContractName(fullContractName); - return { - contractName, - manifestVersion, - fullContractName, - contractFiles: { - main: mainFile, - slim: slimFile +}; +var import_npm_nconf5 = __toESM(require_nconf()); +var currentApp = null; +var currentHttpServer = null; +var currentOwnerSizeTotalWorker = void 0; +var currentCreditsWorker = void 0; +var currentManifest = void 0; +var currentPushHeartbeatIntervalID = void 0; +var appendToOrphanedNamesIndex = appendToIndexFactory("_private_orphaned_names_index"); +var serverSelectorsInstalled = false; +function installServerSelectorsOnce() { + if (serverSelectorsInstalled) return; + serverSelectorsInstalled = true; + esm_default("sbp/selectors/register", { + "backend/server/persistState": async function(deserializedHEAD) { + const contractID = deserializedHEAD.contractID; + const cheloniaState = esm_default("chelonia/rootState"); + if (!cheloniaState.contracts[contractID] || cheloniaState.contracts[contractID].height < deserializedHEAD.head.height) { + return; + } + if (cheloniaState.contracts[contractID].HEAD === deserializedHEAD.hash) { + const state = { + contractState: cheloniaState[contractID], + cheloniaContractInfo: cheloniaState.contracts[contractID] + }; + await esm_default("chelonia.db/set", "_private_cheloniaState_" + contractID, JSON.stringify(state)); + } + if (contractID === deserializedHEAD.hash) { + await esm_default("backend/server/appendToContractIndex", contractID); + } + if (cheloniaState.contracts[contractID].previousKeyOp === deserializedHEAD.hash) { + await appendToIndexFactory(`_private_keyop_idx_${contractID}_${deserializedHEAD.head.height - deserializedHEAD.head.height % KEYOP_SEGMENT_LENGTH}`)(String(deserializedHEAD.head.height)); + } + }, + "backend/server/appendToContractIndex": appendToIndexFactory("_private_cheloniaState_index"), + "backend/server/broadcastKV": async function(contractID, key, entry) { + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const pubsubMessage = createKvMessage(contractID, key, entry); + const subscribers = pubsub.enumerateSubscribers(contractID, key); + console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting KV change on ${contractID} to key ${key}`)); + await pubsub.broadcast(pubsubMessage, { to: subscribers, wsOnly: true }); + }, + "backend/server/broadcastEntry": async function(deserializedHEAD, entry) { + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const contractID = deserializedHEAD.contractID; + const contractType = esm_default("chelonia/rootState").contracts[contractID]?.type; + const pubsubMessage = createMessage(NOTIFICATION_TYPE.ENTRY, entry, { contractID, contractType }); + const subscribers = pubsub.enumerateSubscribers(contractID); + console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting ${deserializedHEAD.description()}`)); + await pubsub.broadcast(pubsubMessage, { to: subscribers }); + }, + "backend/server/broadcastDeletion": async function(contractID) { + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const pubsubMessage = createMessage(NOTIFICATION_TYPE.DELETION, contractID); + const subscribers = pubsub.enumerateSubscribers(contractID); + console.debug(import_npm_chalk3.default.blue.bold(`[pubsub] Broadcasting deletion of ${contractID}`)); + await pubsub.broadcast(pubsubMessage, { to: subscribers }); + }, + "backend/server/handleEntry": async function(deserializedHEAD, entry) { + const contractID = deserializedHEAD.contractID; + if (deserializedHEAD.head.op === SPMessage.OP_CONTRACT) { + esm_default("okTurtles.data/get", PUBSUB_INSTANCE).channels.add(contractID); + } + await esm_default("chelonia/private/in/enqueueHandleEvent", contractID, entry); + await esm_default("backend/server/persistState", deserializedHEAD, entry); + esm_default("backend/server/broadcastEntry", deserializedHEAD, entry).catch((e2) => console.error(e2, "Error broadcasting entry", contractID, deserializedHEAD.hash)); + }, + "backend/server/saveOwner": async function(ownerID, resourceID) { + await esm_default("chelonia/queueInvocation", ownerID, async () => { + const owner = await esm_default("chelonia.db/get", ownerID); + if (!owner) { + throw new Error("Owner resource does not exist"); + } + await esm_default("chelonia.db/set", `_private_owner_${resourceID}`, ownerID); + const resourcesKey = `_private_resources_${ownerID}`; + await appendToIndexFactory(resourcesKey)(resourceID); + esm_default("chelonia.persistentActions/enqueue", ["backend/server/addToIndirectResourcesIndex", resourceID]); + }); + }, + "backend/server/addToIndirectResourcesIndex": async function(resourceID) { + const ownerID = await esm_default("chelonia.db/get", `_private_owner_${resourceID}`); + let indirectOwnerID = ownerID; + while (indirectOwnerID = await esm_default("chelonia.db/get", `_private_owner_${indirectOwnerID}`)) { + await appendToIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(resourceID); + } + }, + "backend/server/removeFromIndirectResourcesIndex": async function(resourceID) { + const ownerID = await esm_default("chelonia.db/get", `_private_owner_${resourceID}`); + const resources = await esm_default("chelonia.db/get", `_private_resources_${resourceID}`); + const indirectResources = resources ? await esm_default("chelonia.db/get", `_private_indirectResources_${resourceID}`) : void 0; + const allSubresources = [ + resourceID, + ...resources ? resources.split("\0") : [], + ...indirectResources ? indirectResources.split("\0") : [] + ]; + let indirectOwnerID = ownerID; + while (indirectOwnerID = await esm_default("chelonia.db/get", `_private_owner_${indirectOwnerID}`)) { + await removeFromIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(allSubresources); + } + }, + "backend/server/registerBillableEntity": appendToIndexFactory("_private_billable_entities"), + "backend/server/updateSize": function(resourceID, size, ultimateOwnerID) { + const sizeKey = `_private_size_${resourceID}`; + return updateSize(resourceID, sizeKey, size).then(() => { + return currentOwnerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID, size, ultimateOwnerID }); + }); + }, + "backend/server/updateContractFilesTotalSize": function(resourceID, size) { + const sizeKey = `_private_contractFilesTotalSize_${resourceID}`; + return updateSize(resourceID, sizeKey, size, true); + }, + "backend/server/stop": async function() { + await stopServer(); + }, + async "backend/deleteFile"(cid, ultimateOwnerID, skipIfDeleted) { + const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); + const rawManifest = await esm_default("chelonia.db/get", cid); + const size = await esm_default("chelonia.db/get", `_private_size_${cid}`); + if (owner && !ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(owner); + if (rawManifest === "") { + if (skipIfDeleted) return; + throw new BackendErrorGone(); + } + if (!rawManifest) { + if (skipIfDeleted) return; + throw new BackendErrorNotFound(); + } + try { + const manifest2 = JSON.parse(rawManifest); + if (!manifest2 || typeof manifest2 !== "object") throw new BackendErrorBadData("manifest format is invalid"); + if (manifest2.version !== "1.0.0") throw new BackendErrorBadData("unsupported manifest version"); + if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new BackendErrorBadData("missing chunks"); + await Promise.all(manifest2.chunks.map(([, cid2]) => esm_default("chelonia.db/delete", cid2))); + } catch (e2) { + console.warn(e2, `Error parsing manifest for ${cid}. It's probably not a file manifest.`); + throw new BackendErrorNotFound(); + } + const resourcesKey = `_private_resources_${owner}`; + await removeFromIndexFactory(resourcesKey)(cid); + await esm_default("backend/server/removeFromIndirectResourcesIndex", cid); + await esm_default("chelonia.db/delete", `_private_owner_${cid}`); + await esm_default("chelonia.db/delete", `_private_size_${cid}`); + await esm_default("chelonia.db/delete", `_private_deletionTokenDgst_${cid}`); + await esm_default("chelonia.db/set", cid, ""); + await esm_default("backend/server/updateContractFilesTotalSize", owner, -Number(size)); + if (ultimateOwnerID && size) { + await currentOwnerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID: cid, size: -parseInt(size), ultimateOwnerID }); + } + }, + async "backend/deleteContract"(cid, ultimateOwnerID, skipIfDeleted) { + let contractsPendingDeletion = esm_default("okTurtles.data/get", "contractsPendingDeletion"); + if (!contractsPendingDeletion) { + contractsPendingDeletion = /* @__PURE__ */ new Set(); + esm_default("okTurtles.data/set", "contractsPendingDeletion", contractsPendingDeletion); + } + if (contractsPendingDeletion.has(cid)) { + return; + } + contractsPendingDeletion.add(cid); + return await esm_default("chelonia/queueInvocation", cid, async () => { + const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); + if (!ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(cid); + const rawManifest = await esm_default("chelonia.db/get", cid); + const size = await esm_default("chelonia.db/get", `_private_size_${cid}`); + if (rawManifest === "") { + if (skipIfDeleted) return; + throw new BackendErrorGone(); + } + if (!rawManifest) { + if (skipIfDeleted) return; + throw new BackendErrorNotFound(); + } + const resourcesKey = `_private_resources_${cid}`; + const resources = await esm_default("chelonia.db/get", resourcesKey); + if (resources) { + await Promise.allSettled(resources.split("\0").map((resourceCid) => { + const parsed = parseCID(resourceCid); + if (parsed.code === multicodes.SHELTER_CONTRACT_DATA) { + return esm_default("chelonia.persistentActions/enqueue", ["backend/deleteContract", resourceCid, ultimateOwnerID, true]); + } else if (parsed.code === multicodes.SHELTER_FILE_MANIFEST) { + return esm_default("chelonia.persistentActions/enqueue", ["backend/deleteFile", resourceCid, ultimateOwnerID, true]); + } else { + console.warn({ cid, resourceCid, code: parsed.code }, "Resource should be deleted but it is of an unknown type"); + } + return void 0; + })); + } + await esm_default("chelonia.db/delete", resourcesKey); + const latestHEADinfo = await esm_default("chelonia/db/latestHEADinfo", cid); + if (latestHEADinfo) { + for (let i2 = latestHEADinfo.height; i2 > 0; i2--) { + const eventKey = `_private_hidx=${cid}#${i2}`; + const event = await esm_default("chelonia.db/get", eventKey); + if (event) { + await esm_default("chelonia.db/delete", JSON.parse(event).hash); + await esm_default("chelonia.db/delete", eventKey); + } + if (i2 % KEYOP_SEGMENT_LENGTH === 0) { + await esm_default("chelonia.db/delete", `_private_keyop_idx_${cid}_${i2}`); + } + } + await esm_default("chelonia/db/deleteLatestHEADinfo", cid); + } + const kvIndexKey = `_private_kvIdx_${cid}`; + const kvKeys = await esm_default("chelonia.db/get", kvIndexKey); + if (kvKeys) { + await Promise.all(kvKeys.split("\0").map((key) => { + return esm_default("chelonia.db/delete", `_private_kv_${cid}_${key}`); + })); + } + await esm_default("chelonia.db/delete", kvIndexKey); + await esm_default("backend/server/removeFromIndirectResourcesIndex", cid); + await esm_default("chelonia.db/delete", `_private_indirectResources_${cid}`); + await esm_default("chelonia.db/get", `_private_cid2name_${cid}`).then((name) => { + if (!name) return; + return Promise.all([ + esm_default("chelonia.db/delete", `_private_cid2name_${cid}`), + appendToOrphanedNamesIndex(name) + ]); + }); + await esm_default("chelonia.db/delete", `_private_rid_${cid}`); + await esm_default("chelonia.db/delete", `_private_owner_${cid}`); + await esm_default("chelonia.db/delete", `_private_size_${cid}`); + await esm_default("chelonia.db/delete", `_private_contractFilesTotalSize_${cid}`); + await esm_default("chelonia.db/delete", `_private_deletionTokenDgst_${cid}`); + await removeFromIndexFactory(`_private_resources_${owner}`)(cid); + await esm_default("chelonia.db/delete", `_private_hidx=${cid}#0`); + await esm_default("chelonia.db/delete", `_private_keyop_idx_${cid}_0`); + await esm_default("chelonia.db/set", cid, ""); + esm_default("chelonia/private/removeImmediately", cid); + if (size) { + await currentOwnerSizeTotalWorker?.rpcSbp("worker/updateSizeSideEffects", { resourceID: cid, size: -parseInt(size), ultimateOwnerID }); + } + await esm_default("chelonia.db/delete", `_private_cheloniaState_${cid}`); + await removeFromIndexFactory("_private_cheloniaState_index")(cid); + await removeFromIndexFactory("_private_billable_entities")(cid); + esm_default("backend/server/broadcastDeletion", cid).catch((e2) => { + console.error(e2, "Error broadcasting contract deletion", cid); + }); + }).finally(() => { + contractsPendingDeletion.delete(cid); + }).catch((e2) => { + console.error(e2, "Error in contract deletion cleanup"); + throw e2; + }); } - }; -} -async function createVersionDirectory(contractName, version3) { - const versionDir = join62(projectRoot, "contracts", contractName, version3); - console.log(blue(`\u{1F4C1} Creating directory: contracts/${contractName}/${version3}/`)); - await mkdir3(versionDir, { recursive: true }); + }); } -async function copyContractFiles(contractFiles, manifestPath, contractName, version3, args) { - const sourceDir = dirname42(join62(projectRoot, manifestPath)); - const targetDir = join62(projectRoot, "contracts", contractName, version3); - console.log(gray(`\u{1F4CB} Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ""}, manifest`)); - const mainSource = join62(sourceDir, contractFiles.main); - const mainTarget = join62(targetDir, contractFiles.main); - await copyFileIfNeeded(mainSource, mainTarget, contractFiles.main, args); - if (contractFiles.slim) { - const slimSource = join62(sourceDir, contractFiles.slim); - const slimTarget = join62(targetDir, contractFiles.slim); - try { - await copyFileIfNeeded(slimSource, slimTarget, contractFiles.slim, args); - } catch (error2) { - const errorMessage = error2 instanceof Error ? error2.message : String(error2); - console.error(yellow(`\u26A0\uFE0F Could not copy slim file: ${errorMessage}`)); +async function startServer() { + const appDir = import_npm_nconf5.default.get("server:appDir") || process9.cwd(); + const ARCHIVE_MODE = import_npm_nconf5.default.get("server:archiveMode"); + const host = import_npm_nconf5.default.get("server:host") || "0.0.0.0"; + const port = import_npm_nconf5.default.get("server:port") ?? 8e3; + if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { + console.error("The size calculation worker must run more frequently than the credits worker for accurate billing"); + throw new Error("The size calculation worker must run more frequently than the credits worker for accurate billing"); + } + try { + currentManifest = (await import(pathToFileURL(join72(appDir, "chelonia.json")).toString(), { + with: { type: "json" } + })).default; + } catch { + console.warn("`chelonia.json` unparsable or not found. Version information will be unavailable."); + } + currentOwnerSizeTotalWorker = ARCHIVE_MODE || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/ownerSizeTotalWorker.js"); + currentCreditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL ? void 0 : createWorker_default("./serve/creditsWorker.js"); + currentApp = new Hono2(); + currentApp.use("*", cors({ origin: "*" })); + currentApp.use("*", async (c, next) => { + await next(); + c.header("X-Frame-Options", "DENY"); + }); + if (process9.env.NODE_ENV === "development" && !process9.env.CI) { + currentApp.use("*", async (c, next) => { + await next(); + const ip = c.req.header("x-real-ip") || "unknown"; + console.debug(import_npm_chalk3.default`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`); + }); + } + currentHttpServer = createAdaptorServer({ fetch: currentApp.fetch }); + installServerSelectorsOnce(); + esm_default("okTurtles.data/set", SERVER_INSTANCE, currentApp); + esm_default("okTurtles.data/set", PUBSUB_INSTANCE, createServer(currentHttpServer, { + serverHandlers: { + connection(socket) { + const manifest2 = currentManifest; + const appVersion = typeof manifest2?.appVersion === "string" ? manifest2.appVersion : null; + const contracts = manifest2?.contracts; + const versionInfo = { + appVersion, + contractsVersion: contracts ? Object.fromEntries( + Object.entries(contracts).map(([k, v2]) => [k, v2.version]) + ) : null + }; + socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)); + } + }, + socketHandlers: { + // The `close()` handler signals the server that the WS has been closed and + // that subsequent messages to subscribed channels should now be sent to its + // associated web push subscription, if it exists. + close() { + const socket = this; + const { server } = this; + const subscriptionId = socket.pushSubscriptionId; + if (!subscriptionId) return; + if (!server.pushSubscriptions[subscriptionId]) return; + server.pushSubscriptions[subscriptionId].sockets.delete(socket); + delete socket.pushSubscriptionId; + if (server.pushSubscriptions[subscriptionId].sockets.size === 0) { + server.pushSubscriptions[subscriptionId].subscriptions.forEach((channelID) => { + if (!server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); + } + server.subscribersByChannelID[channelID].add(server.pushSubscriptions[subscriptionId]); + }); + } + } + }, + messageHandlers: { + [REQUEST_TYPE.PUSH_ACTION]: async function({ data }) { + const socket = this; + const { action, payload } = data; + if (!action) { + socket.send(createPushErrorResponse({ message: "'action' field is required" })); + } + const handler = pushServerActionhandlers[action]; + if (handler) { + try { + await handler.call(socket, payload); + } catch (error2) { + const message = error2?.message || `push server failed to perform [${action}] action`; + console.warn(error2, `[${socket.ip}] Action '${action}' for '${REQUEST_TYPE.PUSH_ACTION}' handler failed: ${message}`); + socket.send(createPushErrorResponse({ actionType: action, message })); + } + } else { + socket.send(createPushErrorResponse({ message: `No handler for the '${action}' action` })); + } + }, + // This handler adds subscribed channels to the web push subscription + // associated with the WS, so that when the WS is closed we can continue + // sending messages as web push notifications. + [NOTIFICATION_TYPE.SUB]({ channelID }) { + const socket = this; + const { server } = this; + if (!socket.pushSubscriptionId) return; + if (!server.pushSubscriptions[socket.pushSubscriptionId]) { + delete socket.pushSubscriptionId; + return; + } + addChannelToSubscription(server, socket.pushSubscriptionId, channelID); + }, + // This handler removes subscribed channels from the web push subscription + // associated with the WS, so that when the WS is closed we don't send + // messages as web push notifications. + [NOTIFICATION_TYPE.UNSUB]({ channelID }) { + const socket = this; + const { server } = this; + if (!socket.pushSubscriptionId) return; + if (!server.pushSubscriptions[socket.pushSubscriptionId]) { + delete socket.pushSubscriptionId; + return; + } + deleteChannelFromSubscription(server, socket.pushSubscriptionId, channelID); + } } + })); + await initDB(); + await currentOwnerSizeTotalWorker?.ready; + await currentCreditsWorker?.ready; + await esm_default("chelonia/configure", SERVER); + esm_default("chelonia.persistentActions/configure", { + databaseKey: "_private_persistent_actions" + }); + const savedStateIndex = await esm_default("chelonia.db/get", "_private_cheloniaState_index"); + if (savedStateIndex) { + const recoveredState = /* @__PURE__ */ Object.create(null); + recoveredState.contracts = /* @__PURE__ */ Object.create(null); + const channels = esm_default("okTurtles.data/get", PUBSUB_INSTANCE).channels; + await Promise.all(savedStateIndex.split("\0").map(async (contractID) => { + const cpSerialized = await esm_default("chelonia.db/get", `_private_cheloniaState_${contractID}`); + if (!cpSerialized) { + console.warn(`[server] missing state for contractID ${contractID} - skipping setup for this contract`); + return; + } + const cp = JSON.parse(cpSerialized); + recoveredState[contractID] = cp.contractState; + recoveredState.contracts[contractID] = cp.cheloniaContractInfo; + channels.add(contractID); + })); + Object.assign(esm_default("chelonia/rootState"), recoveredState); + } + const savedWebPushIndex = await esm_default("chelonia.db/get", "_private_webpush_index"); + if (savedWebPushIndex) { + const { pushSubscriptions, subscribersByChannelID } = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + await Promise.all(savedWebPushIndex.split("\0").map(async (subscriptionId) => { + const subscriptionSerialized = await esm_default("chelonia.db/get", `_private_webpush_${subscriptionId}`); + if (!subscriptionSerialized) { + console.warn(`[server] missing state for subscriptionId '${subscriptionId}' - skipping setup for this subscription`); + return; + } + const { settings, subscriptionInfo, channelIDs } = JSON.parse(subscriptionSerialized); + pushSubscriptions[subscriptionId] = subscriptionInfoWrapper(subscriptionId, subscriptionInfo, { channelIDs, settings }); + channelIDs.forEach((channelID) => { + if (!subscribersByChannelID[channelID]) subscribersByChannelID[channelID] = /* @__PURE__ */ new Set(); + subscribersByChannelID[channelID].add(pushSubscriptions[subscriptionId]); + }); + })); } - const manifestSource = join62(projectRoot, manifestPath); - const manifestTarget = join62(targetDir, basename42(manifestPath)); - await copyFileIfNeeded(manifestSource, manifestTarget, basename42(manifestPath), args); + esm_default("chelonia.persistentActions/load").catch((e2) => { + console.error(e2, "Error loading persistent actions"); + }); + registerRoutes(currentApp); + const map = /* @__PURE__ */ new WeakMap(); + currentPushHeartbeatIntervalID = setInterval(() => { + const now = Date.now(); + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + const notification = JSON.stringify({ type: "recurring" }); + Object.values(pubsub?.pushSubscriptions || {}).filter( + (pushSubscription) => !!pushSubscription.settings.heartbeatInterval && pushSubscription.sockets.size === 0 + ).forEach((pushSubscription) => { + const last = map.get(pushSubscription) ?? Number.NEGATIVE_INFINITY; + if (now - last < pushSubscription.settings.heartbeatInterval) return; + postEvent(pushSubscription, notification).then(() => { + map.set(pushSubscription, now); + }).catch((e2) => { + console.warn(e2, "Error sending recurring message to web push client", pushSubscription.id); + }); + }); + }, 1 * 60 * 60 * 1e3); + const uri = await new Promise((resolve82, reject) => { + currentHttpServer.listen(port, host, () => { + const addr = currentHttpServer.address(); + const uri2 = `http://${addr.address}:${addr.port}`; + console.info("Backend server running at:", uri2); + esm_default("okTurtles.events/emit", SERVER_RUNNING, { info: { uri: uri2 } }); + resolve82(uri2); + }).once("error", reject); + }); + return { uri }; } -async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { - const targetExists = existsSync(targetPath); - if (!targetExists) { - console.log(blue(`\u{1F4C4} Copying: ${fileName} (new file)`)); - await copyFile(sourcePath, targetPath); - return; - } - if (targetExists && !args.overwrite) { - console.log(yellow(`\u23ED\uFE0F Skipping: ${fileName} (already exists, use --overwrite to replace)`)); - return; +async function stopServer() { + if (currentPushHeartbeatIntervalID !== void 0) { + clearInterval(currentPushHeartbeatIntervalID); + currentPushHeartbeatIntervalID = void 0; + } + if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { + await esm_default("backend/server/stopRateLimiters"); + } + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + if (pubsub) { + pubsub.clients.forEach((client) => client.terminate()); + pubsub.close(); + esm_default("okTurtles.data/delete", PUBSUB_INSTANCE); + } + if (currentHttpServer) { + await new Promise((resolve82, reject) => { + currentHttpServer.close((err) => { + if (err) { + reject(err); + } else { + resolve82(); + } + }); + }); + currentHttpServer = null; } - console.log(blue(`\u{1F4C4} Copying: ${fileName} (overwriting)`)); - await copyFile(sourcePath, targetPath); + await Promise.all([ + currentOwnerSizeTotalWorker?.terminate(), + currentCreditsWorker?.terminate() + ]); + currentOwnerSizeTotalWorker = void 0; + currentCreditsWorker = void 0; + await closeDB(); + currentApp = null; + currentManifest = void 0; } -async function loadCheloniaConfig() { - const configPath = join62(projectRoot, "chelonia.json"); - cheloniaConfig = { contracts: {} }; - if (existsSync(configPath)) { - try { - const configContent = await readFile3(configPath, "utf8"); - cheloniaConfig = JSON.parse(configContent); - console.log(blue("\u{1F4C4} Loaded existing chelonia.json")); - } catch (error2) { - console.warn(yellow(`Warning: Could not parse chelonia.json: ${error2}`)); +var app = new Proxy({}, { + get(_target, prop) { + if (currentApp) { + return Reflect.get(currentApp, prop); } - } else { - console.log(blue("\u{1F4C4} No existing chelonia.json found")); + return void 0; } - if (!cheloniaConfig.contracts) { - cheloniaConfig.contracts = {}; +}); +console.info("NODE_ENV =", process10.env.NODE_ENV); +var dontLog = { + "backend/server/broadcastEntry": true, + "backend/server/broadcastDeletion": true, + "backend/server/broadcastKV": true +}; +function logSBP(_domain, selector, data) { + if (!dontLog[selector]) { + if (selector === "backend/server/handleEntry") { + console.debug(import_npm_chalk4.default.bold(`[sbp] ${selector}`), data[0].description()); + } else { + console.debug(import_npm_chalk4.default.bold(`[sbp] ${selector}`), data); + } } } -async function updateCheloniaConfig(fullContractName, contractName, version3, manifestPath) { - const manifestFileName = basename42(manifestPath); - const pinnedManifestPath = `contracts/${contractName}/${version3}/${manifestFileName}`; - cheloniaConfig.contracts[fullContractName] = { - version: version3, - path: pinnedManifestPath +["backend"].forEach((domain) => esm_default("sbp/filters/domain/add", domain, logSBP)); +[].forEach((sel) => esm_default("sbp/filters/selector/add", sel, logSBP)); +var signalHandlersInstalled = false; +var signalHandlers = []; +var globalExceptionHandlersInstalled = false; +function installGlobalExceptionHandlers() { + if (globalExceptionHandlersInstalled) return; + globalExceptionHandlersInstalled = true; + process10.on("uncaughtException", (err) => { + console.error(err, "[server] Unhandled exception"); + process10.exit(1); + }); + process10.on("unhandledRejection", (reason) => { + console.error(reason, "[server] Unhandled promise rejection:", reason); + process10.exit(1); + }); +} +function installSignalHandlers() { + if (signalHandlersInstalled) return; + signalHandlersInstalled = true; + const handleSignal = (signal, code2) => { + const handler = () => { + console.error(`Exiting upon receiving ${signal} (${code2})`); + exit2(128 + code2); + }; + signalHandlers.push([signal, handler]); + process10.on(signal, handler); }; - const configPath = join62(projectRoot, "chelonia.json"); - const configContent = JSON.stringify(cheloniaConfig, null, 2) + "\n"; - await writeFile2(configPath, configContent, "utf8"); - console.log(green("\u2705 Saved chelonia.json")); + [ + ["SIGHUP", 1], + ["SIGINT", 2], + ["SIGQUIT", 3], + ["SIGTERM", 15], + ["SIGUSR1", 10], + ["SIGUSR2", 11] + ].forEach(([signal, code2]) => handleSignal(signal, code2)); } -var module10 = { - builder: (yargs) => { - return yargs.option("overwrite", { - describe: "Overwrite existing files", - requiresArg: false, - boolean: true - }).alias("o", "overwrite").option("dir", { - default: false, - describe: "Output directory", - requiresArg: false, - string: true - }).alias("d", "dir").positional("manifest", { - describe: "Manifest file path", - demandOption: true, - type: "string" - }).positional("manifest-version", { - describe: "Manifest version", - demandOption: false, - type: "string" +function removeSignalHandlers() { + for (const [signal, handler] of signalHandlers) { + process10.removeListener(signal, handler); + } + signalHandlers.length = 0; + signalHandlersInstalled = false; +} +var exit2 = (code2) => { + esm_default("okTurtles.events/once", SERVER_EXITING, () => { + esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { + process10.send?.({}); + process10.nextTick(() => process10.exit(code2)); }); - }, - command: "pin []", - describe: "Pin a manifest version", - postHandler: (argv) => { - return pin(argv); + }); + esm_default("okTurtles.events/emit", SERVER_EXITING); +}; +async function startServer2(options2 = {}) { + const { installSignalHandlers: shouldInstallSignalHandlers = true } = options2; + if (shouldInstallSignalHandlers) { + installGlobalExceptionHandlers(); + installSignalHandlers(); + } + esm_default("okTurtles.events/once", SERVER_EXITING, () => { + esm_default("okTurtles.data/apply", PUBSUB_INSTANCE, function(pubsub) { + esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { + return new Promise((resolve82) => { + pubsub.on("close", async function() { + try { + removeSignalHandlers(); + await esm_default("chelonia.persistentActions/unload"); + await stopServer2(); + console.info("Server down"); + } catch (err) { + console.error(err, "Error during shutdown"); + } finally { + resolve82(); + } + }); + pubsub.close(); + pubsub.clients.forEach((client) => client.terminate()); + }); + }); + }); + }); + return await new Promise((resolve82, reject) => { + esm_default("okTurtles.events/on", SERVER_RUNNING, function onRunning(info) { + esm_default("okTurtles.events/off", SERVER_RUNNING, onRunning); + console.info(import_npm_chalk4.default.bold("backend startup sequence complete.")); + resolve82({ uri: info.info.uri }); + }); + startServer().catch(reject); + }); +} +async function stopServer2() { + await stopServer(); +} +var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; +var getMimeType = (filename, mimes = baseMimes) => { + const regexp = /\.([a-zA-Z0-9]+?)$/; + const match2 = filename.match(regexp); + if (!match2) { + return; + } + let mimeType = mimes[match2[1].toLowerCase()]; + if (mimeType && mimeType.startsWith("text")) { + mimeType += "; charset=utf-8"; } + return mimeType; }; -init_esm(); -init_esm5(); +var _baseMimes = { + aac: "audio/aac", + avi: "video/x-msvideo", + avif: "image/avif", + av1: "video/av1", + bin: "application/octet-stream", + bmp: "image/bmp", + css: "text/css", + csv: "text/csv", + eot: "application/vnd.ms-fontobject", + epub: "application/epub+zip", + gif: "image/gif", + gz: "application/gzip", + htm: "text/html", + html: "text/html", + ico: "image/x-icon", + ics: "text/calendar", + jpeg: "image/jpeg", + jpg: "image/jpeg", + js: "text/javascript", + json: "application/json", + jsonld: "application/ld+json", + map: "application/json", + mid: "audio/x-midi", + midi: "audio/x-midi", + mjs: "text/javascript", + mp3: "audio/mpeg", + mp4: "video/mp4", + mpeg: "video/mpeg", + oga: "audio/ogg", + ogv: "video/ogg", + ogx: "application/ogg", + opus: "audio/opus", + otf: "font/otf", + pdf: "application/pdf", + png: "image/png", + rtf: "application/rtf", + svg: "image/svg+xml", + tif: "image/tiff", + tiff: "image/tiff", + ts: "video/mp2t", + ttf: "font/ttf", + txt: "text/plain", + wasm: "application/wasm", + webm: "video/webm", + weba: "audio/webm", + webmanifest: "application/manifest+json", + webp: "image/webp", + woff: "font/woff", + woff2: "font/woff2", + xhtml: "application/xhtml+xml", + xml: "application/xml", + zip: "application/zip", + "3gp": "video/3gpp", + "3g2": "video/3gpp2", + gltf: "model/gltf+json", + glb: "model/gltf-binary" +}; +var baseMimes = _baseMimes; +var defaultJoin = (...paths) => { + let result = paths.filter((p) => p !== "").join("/"); + result = result.replace(/(?<=\/)\/+/g, ""); + const segments = result.split("/"); + const resolved = []; + for (const segment of segments) { + if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { + resolved.pop(); + } else if (segment !== ".") { + resolved.push(segment); + } + } + return resolved.join("/") || "."; +}; +var ENCODINGS = { + br: ".br", + zstd: ".zst", + gzip: ".gz" +}; +var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); +var DEFAULT_DOCUMENT = "index.html"; +var serveStatic = (options2) => { + const root = options2.root ?? "./"; + const optionPath = options2.path; + const join10 = options2.join ?? defaultJoin; + return async (c, next) => { + if (c.finalized) { + return next(); + } + let filename; + if (options2.path) { + filename = options2.path; + } else { + try { + filename = tryDecodeURI(c.req.path); + if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { + throw new Error(); + } + } catch { + await options2.onNotFound?.(c.req.path, c); + return next(); + } + } + let path8 = join10( + root, + !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename + ); + if (options2.isDir && await options2.isDir(path8)) { + path8 = join10(path8, DEFAULT_DOCUMENT); + } + const getContent = options2.getContent; + let content = await getContent(path8, c); + if (content instanceof Response) { + return c.newResponse(content.body, content); + } + if (content) { + const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); + c.header("Content-Type", mimeType || "application/octet-stream"); + if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { + const acceptEncodingSet = new Set( + c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) + ); + for (const encoding of ENCODINGS_ORDERED_KEYS) { + if (!acceptEncodingSet.has(encoding)) { + continue; + } + const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); + if (compressedContent) { + content = compressedContent; + c.header("Content-Encoding", encoding); + c.header("Vary", "Accept-Encoding", { append: true }); + break; + } + } + } + await options2.onFound?.(path8, c); + return c.body(content); + } + await options2.onNotFound?.(path8, c); + await next(); + return; + }; +}; +var { open, lstatSync, errors } = Deno; +var serveStatic2 = (options2) => { + return async function serveStatic22(c, next) { + const getContent = async (path8) => { + try { + if (isDir(path8)) { + return null; + } + const file = await open(path8); + return file.readable; + } catch (e2) { + if (!(e2 instanceof errors.NotFound)) { + console.warn(`${e2}`); + } + return null; + } + }; + const isDir = (path8) => { + let isDir2; + try { + const stat = lstatSync(path8); + isDir2 = stat.isDirectory; + } catch { + } + return isDir2; + }; + return serveStatic({ + ...options2, + getContent, + join: join82, + isDir + })(c, next); + }; +}; +var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; +var SSG_DISABLED_RESPONSE = (() => { + try { + return new Response("SSG is disabled", { + status: 404, + headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } + }); + } catch { + return null; + } +})(); +var WSContext = class { + #init; + constructor(init2) { + this.#init = init2; + this.raw = init2.raw; + this.url = init2.url ? new URL(init2.url) : null; + this.protocol = init2.protocol ?? null; + } + send(source, options2) { + this.#init.send(source, options2 ?? {}); + } + raw; + binaryType = "arraybuffer"; + get readyState() { + return this.#init.readyState; + } + url; + protocol; + close(code2, reason) { + this.#init.close(code2, reason); + } +}; +var defineWebSocketHelper = (handler) => { + return (...args) => { + if (typeof args[0] === "function") { + const [createEvents, options2] = args; + return async function upgradeWebSocket2(c, next) { + const events = await createEvents(c); + const result = await handler(c, events, options2); + if (result) { + return result; + } + await next(); + }; + } else { + const [c, events, options2] = args; + return (async () => { + const upgraded = await handler(c, events, options2); + if (!upgraded) { + throw new Error("Failed to upgrade WebSocket"); + } + return upgraded; + })(); + } + }; +}; +var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { + if (c.req.header("upgrade") !== "websocket") { + return; + } + const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); + const wsContext = new WSContext({ + close: (code2, reason) => socket.close(code2, reason), + get protocol() { + return socket.protocol; + }, + raw: socket, + get readyState() { + return socket.readyState; + }, + url: socket.url ? new URL(socket.url) : null, + send: (source) => socket.send(source) + }); + socket.onopen = (evt) => events.onOpen?.(evt, wsContext); + socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); + socket.onclose = (evt) => events.onClose?.(evt, wsContext); + socket.onerror = (evt) => events.onError?.(evt, wsContext); + return response; +}); +var import_npm_nconf6 = __toESM(require_nconf()); +var getDashboardPath = () => { + const baseDir = import.meta.dirname || path6.join(process11.cwd(), "build"); + const dashboardPath = path6.resolve(baseDir, "dist-dashboard"); + return dashboardPath; +}; +async function startDashboard() { + const port = import_npm_nconf6.default.get("server:dashboardPort"); + const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; + const dashboardRoot = getDashboardPath(); + const app2 = new Hono2(); + app2.get("/assets/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); + app2.get("/dashboard", serveStatic2({ path: path6.join(dashboardRoot, "index.html") })); + app2.get("/dashboard/", serveStatic2({ path: path6.join(dashboardRoot, "index.html") })); + app2.get("/*", async (c) => { + const staticResponse = await serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })(c, async () => { + }); + if (staticResponse) { + return staticResponse; + } + const indexResponse = await serveStatic2({ path: path6.join(dashboardRoot, "index.html") })(c, async () => { + }); + return indexResponse || c.text("Not Found", 404); + }); + await new Promise((resolve82) => { + Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app2.fetch); + }); +} async function watch(args) { const dir = args["manifests-dir"]; const manifests = await findManifestFiles(dir); @@ -76208,12 +75306,10 @@ async function watch(args) { })(); } async function startDashboardServer() { - const dashboardServer = await Promise.resolve().then(() => (init_dashboard_server(), dashboard_server_exports)); - await dashboardServer.startDashboard(); + await startDashboard(); } async function startApplicationServer() { - const startServer = await Promise.resolve().then(() => (init_serve(), serve_exports)); - await startServer.default(); + await startServer2(); } async function serve(args) { try { @@ -76278,7 +75374,7 @@ var module11 = { return serve(argv); } }; -init_esm7(); +init_esm6(); init_functions(); function isExternalKeyDescriptor(obj) { return obj !== null && typeof obj === "object" && typeof obj.pubkey === "string"; @@ -80505,14 +79601,16 @@ function isYargsInstance(y) { } var Yargs2 = YargsWithShim(esm_default7); var yargs_default = Yargs2; -var postHandler = () => { +var handlerState = { + postHandler: () => { + } }; var parseArgs = () => { const handlerWrapper = (commandModule) => { return { ...commandModule, handler: (argv) => { - postHandler = () => commandModule.postHandler(argv); + handlerState.postHandler = () => commandModule.postHandler(argv); if (commandModule.handler) { return commandModule.handler(argv); } @@ -80522,7 +79620,9 @@ var parseArgs = () => { const commandModules = Object.values(commands_exports).map( (c) => handlerWrapper(c) ); - return yargs_default(hideBin(process13.argv)).version("3.2.1").strict().command(commandModules).demandCommand().help(); + const yargsInstance = yargs_default(hideBin(process13.argv)).version("3.2.1").strict().command(commandModules).demandCommand().help(); + yargsInstance.parse(); + return yargsInstance; }; var parseArgs_default = parseArgs; var parseConfig = () => { @@ -80561,10 +79661,9 @@ var parseConfig = () => { }); }; var parseConfig_default = parseConfig; -init_events2(); parseConfig_default(); try { - await postHandler(); + await handlerState.postHandler(); } finally { esm_default("okTurtles.events/emit", SERVER_EXITING); } diff --git a/src/main.ts b/src/main.ts index 55455ac..0d5c793 100755 --- a/src/main.ts +++ b/src/main.ts @@ -2,15 +2,15 @@ // Deno APIs: // https://doc.deno.land/deno/stable -// https://doc.deno.land/https://deno.land/std/ +// https://doc.deno.land/deno~land/std/ // Deno examples: -// https://doc.deno.land/https://deno.land/std@0.141.0/examples +// https://doc.deno.land/deno~land/std@0.141.0/examples // https://examples.deno.land/ // Third-party modules: // https://deno.land/x import sbp from 'npm:@sbp/sbp' -import parseConfig, { postHandler } from './parseConfig.ts' +import parseConfig, { handlerState } from './parseConfig.ts' import { SERVER_EXITING } from './serve/events.ts' parseConfig() @@ -18,7 +18,7 @@ parseConfig() try { // `postHandler` is set by `parseArgs` (called by `parseConfig`) // Run the selected subcommand - await postHandler() + await handlerState.postHandler() } finally { // Indicate that we're done, which is useful for cleaning up, closing DB // connections, etc. diff --git a/src/parseArgs.ts b/src/parseArgs.ts index bd13d3e..8e292cf 100644 --- a/src/parseArgs.ts +++ b/src/parseArgs.ts @@ -5,14 +5,17 @@ import * as commands from './commands.ts' import yargs, { type ArgumentsCamelCase, type CommandModule as YCommandModule } from 'npm:yargs' import { hideBin } from 'npm:yargs/helpers' -let postHandler: () => void | Promise = () => {} +// Use an object to hold the handler to ensure live binding works +const handlerState: { postHandler: () => void | Promise } = { + postHandler: () => {} +} const parseArgs = () => { const handlerWrapper = (commandModule: commands.CommandModule): YCommandModule => { return { ...commandModule, handler: (argv: ArgumentsCamelCase) => { - postHandler = () => commandModule.postHandler(argv) + handlerState.postHandler = () => commandModule.postHandler(argv) if (commandModule.handler) { return commandModule.handler(argv) } @@ -25,13 +28,18 @@ const parseArgs = () => { (c) => handlerWrapper(c as commands.CommandModule) ) - return yargs(hideBin(process.argv)) + const yargsInstance = yargs(hideBin(process.argv)) .version(import.meta.VERSION) .strict() .command(commandModules) .demandCommand() .help() + + // Explicitly parse to trigger command handlers + yargsInstance.parse() + + return yargsInstance } export default parseArgs -export { postHandler } +export { handlerState } diff --git a/src/parseConfig.ts b/src/parseConfig.ts index 6fa850f..1819bdd 100644 --- a/src/parseConfig.ts +++ b/src/parseConfig.ts @@ -1,7 +1,7 @@ // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' import { parse, stringify } from 'npm:smol-toml' -import parseArgs from './parseArgs.ts' +import parseArgs, { handlerState } from './parseArgs.ts' const parseConfig = () => { nconf @@ -44,4 +44,4 @@ const parseConfig = () => { } export default parseConfig -export { postHandler } from './parseArgs.ts' +export { handlerState } diff --git a/src/serve.ts b/src/serve.ts index d739341..9bcf4ab 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -5,6 +5,8 @@ import { debounce } from 'npm:turtledash' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { deploy } from './deploy.ts' import { findManifestFiles } from './utils.ts' +import { startServer } from './serve/index.ts' +import { startDashboard } from './serve/dashboard-server.ts' type Params = { port: number, 'dashboard-port': number, directory: string, dev: boolean, 'manifests-dir': string } @@ -67,16 +69,12 @@ async function watch (args: ArgumentsCamelCase): Promise { // Dashboard server function async function startDashboardServer (): Promise { - // Import and start the dashboard server - const dashboardServer = await import('./serve/dashboard-server.ts') - await dashboardServer.startDashboard() + await startDashboard() } // Application server function async function startApplicationServer (): Promise { - // Import and start the application server - const startServer = await import('./serve/index.ts') - await startServer.default() + await startServer() } export async function serve (args: ArgumentsCamelCase) { diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index c18516e..149a6a1 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -6,7 +6,11 @@ import { serveStatic } from 'npm:hono/deno' import nconf from 'npm:nconf' const getDashboardPath = () => { - return path.resolve(import.meta.dirname || process.cwd(), 'dist-dashboard') + // When running from build/main.js, the dashboard is in build/dist-dashboard + // import.meta.dirname points to the build/ directory in that case + const baseDir = import.meta.dirname || path.join(process.cwd(), 'build') + const dashboardPath = path.resolve(baseDir, 'dist-dashboard') + return dashboardPath } export async function startDashboard (): Promise { @@ -25,11 +29,12 @@ export async function startDashboard (): Promise { app.get('/*', async (c) => { const staticResponse = await serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })(c, async () => {}) // If static file exists and was served successfully, return it - if (staticResponse && staticResponse.status !== 404) { + if (staticResponse) { return staticResponse } // File not found, serve index.html for SPA routing - return serveStatic({ path: path.join(dashboardRoot, 'index.html') })(c, async () => {}) + const indexResponse = await serveStatic({ path: path.join(dashboardRoot, 'index.html') })(c, async () => {}) + return indexResponse || c.text('Not Found', 404) }) await new Promise((resolve) => { diff --git a/src/serve/database.ts b/src/serve/database.ts index b093656..2f0b6f2 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -8,7 +8,6 @@ import { strToB64 } from 'npm:@chelonia/lib/functions' import sbp from 'npm:@sbp/sbp' import LRU from 'npm:lru-cache' import { BackendErrorConflict, BackendErrorGone, BackendErrorNotFound } from './errors.ts' -import { SERVER_EXITING } from './events.ts' import { initVapid } from './vapid.ts' import { initZkpp } from './zkppSalt.ts' // @deno-types="npm:@types/nconf" @@ -18,163 +17,177 @@ import { KEYOP_SEGMENT_LENGTH, appendToNamesIndex, namespaceKey } from './db-uti const production = process.env.NODE_ENV === 'production' -// Streams stored contract log entries since the given entry hash (inclusive!). -export default sbp('sbp/selectors/register', { - 'backend/db/streamEntriesAfter': async function (contractID: string, height: number, requestedLimit?: number, options: { keyOps?: boolean } = {}): Promise { - const batchMaxSize = nconf.get('server:maxEventsBatchSize') ?? 500 - const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize) - const latestHEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) - if (latestHEADinfo === '') { - throw new BackendErrorGone(`contractID ${contractID} has been deleted!`) - } - if (!latestHEADinfo) { - throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`) - } - // Number of entries pushed. - let counter = 0 - let currentHeight = height - let currentHash, serverMeta - let prefix = '' - // `nextKeyOp` is used to advance `currentHeight` when fetching keyOps, and - // more complex behaviour than simple 'increment by 1' is needed. - // It returns three possible values: `true`, indicating `currentHeight` has - // been set to the next `currentHeight`; `false`, indicating the end of - // the stream; and `null`, indicating the result is indeterminate and - // `nextKeyOp` should be called again (this is because key ops are indexed - // based on their height in segments of 10k height entries). - // `nextKeyOp` will do the following: if `currentHeight` points to a key op, - // it will leave `currentHeight` unchanged; otherwise, if `currentHeight` - // does _not_ point to a key op, `currentHeight` will be set to the smallest - // height larger than the current `currentHeight` value which is a key op. - const nextKeyOp = (() => { - let index: string[] | undefined +// Module-scope state for the active backend instance and LRU cache. +// The overwritten `chelonia.db/*` selectors close over these so that +// a second `initDB()` call (after `closeDB()`) rebinds them to a fresh +// backend + cache without needing to re-overwrite the selectors. +let currentBackend: DatabaseBackend | null = null +let currentCache: LRU | null = null - return async () => { - if (!index) { - index = (await sbp('chelonia.db/get', `_private_keyop_idx_${contractID}_${currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH}`))?.split('\x00') - } - const value = index?.find((h, i) => { - if (Number(h) >= currentHeight) { - // Remove values that no longer are relevant from the index - index = index!.slice(i + 1) - return true - } else { - return false +let baseSelectorsInstalled = false +function installBaseSelectorsOnce () { + if (baseSelectorsInstalled) return + baseSelectorsInstalled = true + sbp('sbp/selectors/register', { + 'backend/db/streamEntriesAfter': async function (contractID: string, height: number, requestedLimit?: number, options: { keyOps?: boolean } = {}): Promise { + const batchMaxSize = nconf.get('server:maxEventsBatchSize') ?? 500 + const limit = Math.min(requestedLimit ?? Number.POSITIVE_INFINITY, batchMaxSize) + const latestHEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) + if (latestHEADinfo === '') { + throw new BackendErrorGone(`contractID ${contractID} has been deleted!`) + } + if (!latestHEADinfo) { + throw new BackendErrorNotFound(`contractID ${contractID} doesn't exist!`) + } + // Number of entries pushed. + let counter = 0 + let currentHeight = height + let currentHash, serverMeta + let prefix = '' + // `nextKeyOp` is used to advance `currentHeight` when fetching keyOps, and + // more complex behaviour than simple 'increment by 1' is needed. + // It returns three possible values: `true`, indicating `currentHeight` has + // been set to the next `currentHeight`; `false`, indicating the end of + // the stream; and `null`, indicating the result is indeterminate and + // `nextKeyOp` should be called again (this is because key ops are indexed + // based on their height in segments of 10k height entries). + // `nextKeyOp` will do the following: if `currentHeight` points to a key op, + // it will leave `currentHeight` unchanged; otherwise, if `currentHeight` + // does _not_ point to a key op, `currentHeight` will be set to the smallest + // height larger than the current `currentHeight` value which is a key op. + const nextKeyOp = (() => { + let index: string[] | undefined + + return async () => { + if (!index) { + index = (await sbp('chelonia.db/get', `_private_keyop_idx_${contractID}_${currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH}`))?.split('\x00') } - }) - if (value != null) { - const newHeight = Number(value) - currentHeight = newHeight - } else { - // We've exhausted the current index; we'll return `null` and advance - // height by KEYOP_SEGMENT_LENGTH so that we can read the next index - // upon the next invocation (or, if we've reached the end of the - // contract, we return `false`). - currentHeight = currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH + KEYOP_SEGMENT_LENGTH - index = undefined - if (currentHeight > latestHEADinfo.height) { - return false + const value = index?.find((h, i) => { + if (Number(h) >= currentHeight) { + // Remove values that no longer are relevant from the index + index = index!.slice(i + 1) + return true + } else { + return false + } + }) + if (value != null) { + const newHeight = Number(value) + currentHeight = newHeight } else { - return null + // We've exhausted the current index; we'll return `null` and advance + // height by KEYOP_SEGMENT_LENGTH so that we can read the next index + // upon the next invocation (or, if we've reached the end of the + // contract, we return `false`). + currentHeight = currentHeight - currentHeight % KEYOP_SEGMENT_LENGTH + KEYOP_SEGMENT_LENGTH + index = undefined + if (currentHeight > latestHEADinfo.height) { + return false + } else { + return null + } } + return true + } + })() + // `fetchMeta` fetches metadata information for entries based on height. + // Crucially, it fetches the entry hash (i.e., height -> hash lookup), which + // is needed for returning the correct data. + // The return value isn't currently used but is left as it may be useful in + // the future if this code is refactored. `false` indicates that no metadata + // could be found (indicating the end of a contract --or some kind of data + // corruption) and that the stream has ended. `true` indicates that the + // function executed successfully and the stream continues. + // Currently, the return value is not used because we're relying on the + // truthiness of `serverMeta` as a subtitute. + const fetchMeta = async () => { + if (currentHeight > latestHEADinfo.height) { + return false + } + const meta = await sbp('chelonia/db/getEntryMeta', contractID, currentHeight) + if (!meta) { + return false } - return true - } - })() - // `fetchMeta` fetches metadata information for entries based on height. - // Crucially, it fetches the entry hash (i.e., height -> hash lookup), which - // is needed for returning the correct data. - // The return value isn't currently used but is left as it may be useful in - // the future if this code is refactored. `false` indicates that no metadata - // could be found (indicating the end of a contract --or some kind of data - // corruption) and that the stream has ended. `true` indicates that the - // function executed successfully and the stream continues. - // Currently, the return value is not used because we're relying on the - // truthiness of `serverMeta` as a subtitute. - const fetchMeta = async () => { - if (currentHeight > latestHEADinfo.height) { - return false - } - const meta = await sbp('chelonia/db/getEntryMeta', contractID, currentHeight) - if (!meta) { - return false - } - const { hash: newCurrentHash, ...newServerMeta } = meta - currentHash = newCurrentHash - serverMeta = newServerMeta + const { hash: newCurrentHash, ...newServerMeta } = meta + currentHash = newCurrentHash + serverMeta = newServerMeta - return true - } - // NOTE: if this ever stops working you can also try Readable.from(): - // https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options - const stream = Readable.from((async function * () { - yield '[' - await fetchMeta() - while (serverMeta && counter < limit) { - try { - const entry = await sbp('chelonia/db/getEntry', currentHash) - // If the entry doesn't exist, we may have reached the end - if (!entry) break - const currentPrefix = prefix - prefix = ',' - counter++ - yield `${currentPrefix}"${strToB64( - JSON.stringify({ serverMeta, message: entry.serialize() }) - )}"` - // Note for future improvement: implement a generator function for - // advancing height, which would make this logic more general by - // having just something like `await height.next()` instead of this - // avancement here and separate logic for each special case (like the - // `if` below for key ops). - currentHeight++ - currentHash = undefined - serverMeta = undefined - // queries with 'keyOps' always return the requested height, whether - // or not a keyOp. - if (options.keyOps) { - // Advance `currentHeight` until the next key op - // `nextKeyOp` relies on the height advancing after an ideration and - while ((await nextKeyOp()) === null); + return true + } + // NOTE: if this ever stops working you can also try Readable.from(): + // https://nodejs.org/api/stream.html#stream_stream_readable_from_iterable_options + const stream = Readable.from((async function * () { + yield '[' + await fetchMeta() + while (serverMeta && counter < limit) { + try { + const entry = await sbp('chelonia/db/getEntry', currentHash) + // If the entry doesn't exist, we may have reached the end + if (!entry) break + const currentPrefix = prefix + prefix = ',' + counter++ + yield `${currentPrefix}"${strToB64( + JSON.stringify({ serverMeta, message: entry.serialize() }) + )}"` + // Note for future improvement: implement a generator function for + // advancing height, which would make this logic more general by + // having just something like `await height.next()` instead of this + // avancement here and separate logic for each special case (like the + // `if` below for key ops). + currentHeight++ + currentHash = undefined + serverMeta = undefined + // queries with 'keyOps' always return the requested height, whether + // or not a keyOp. + if (options.keyOps) { + // Advance `currentHeight` until the next key op + // `nextKeyOp` relies on the height advancing after an ideration and + while ((await nextKeyOp()) === null); + } + await fetchMeta() + } catch (e) { + console.error(e, '[backend] streamEntriesAfter: read()') + break } - await fetchMeta() - } catch (e) { - console.error(e, '[backend] streamEntriesAfter: read()') - break } + yield ']' + })(), { encoding: 'utf-8', objectMode: false }) + + // Add headers to stream (TypeScript workaround) + ;(stream as { headers?: Record }).headers = { + 'shelter-headinfo-head': latestHEADinfo.HEAD, + 'shelter-headinfo-height': latestHEADinfo.height } - yield ']' - })(), { encoding: 'utf-8', objectMode: false }) + return stream + }, + // ======================= + // wrapper methods to add / lookup names + // ======================= + 'backend/db/registerName': async function (name: string, value: string): Promise<{ name: string, value: string }> { + const exists = await sbp('backend/db/lookupName', name) + if (exists) { + throw new BackendErrorConflict('exists') + } + await sbp('chelonia.db/set', namespaceKey(name), value) + await sbp('chelonia.db/set', `_private_cid2name_${value}`, name) + await appendToNamesIndex(name) - // Add headers to stream (TypeScript workaround) - ;(stream as { headers?: Record }).headers = { - 'shelter-headinfo-head': latestHEADinfo.HEAD, - 'shelter-headinfo-height': latestHEADinfo.height - } - return stream - }, - // ======================= - // wrapper methods to add / lookup names - // ======================= - 'backend/db/registerName': async function (name: string, value: string): Promise<{ name: string, value: string }> { - const exists = await sbp('backend/db/lookupName', name) - if (exists) { - throw new BackendErrorConflict('exists') + return { name, value } + }, + 'backend/db/lookupName': async function (name: string): Promise { + const value = await sbp('chelonia.db/get', namespaceKey(name)) + return value } - await sbp('chelonia.db/set', namespaceKey(name), value) - await sbp('chelonia.db/set', `_private_cid2name_${value}`, name) - await appendToNamesIndex(name) + }) +} - return { name, value } - }, - 'backend/db/lookupName': async function (name: string): Promise { - const value = await sbp('chelonia.db/get', namespaceKey(name)) - return value - } -}) +export default installBaseSelectorsOnce let initedDB: false | true | 'preloaded' = false export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } = {}) => { + installBaseSelectorsOnce() if (!initedDB) { // If persistence must be enabled: // - load and initialize the selected storage backend @@ -187,27 +200,19 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean if (persistence && persistence !== 'mem') { const Ctor = (await import(`./database-${persistence}.ts`)).default - // Destructuring is safe because these methods have been bound using rebindMethods(). - const { init, readData, writeData, deleteData, iterKeys, keyCount, close } = new Ctor(options[persistence]) as DatabaseBackend - await init() - sbp('okTurtles.events/once', SERVER_EXITING, () => { - sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, async () => { - try { - await close() - } catch (e) { - console.error(e, `Error closing DB ${persistence}`) - } - }) - }) + const instance = new Ctor(options[persistence]) as DatabaseBackend + await instance.init() + currentBackend = instance // https://github.com/isaacs/node-lru-cache#usage - const cache = new LRU({ + currentCache = new LRU({ max: nconf.get('database:lruNumItems') ?? 10000 }) const prefixes = Object.keys(prefixHandlers) sbp('sbp/selectors/overwrite', { 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { + const cache = currentCache! if (!bypassCache) { const lookupValue = cache.get(prefixableKey) if (lookupValue !== undefined) { @@ -215,7 +220,7 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } } const [prefix, key] = parsePrefixableKey(prefixableKey) - let value = await readData(key) + let value = await currentBackend!.readData(key) if (value === undefined) { return } @@ -227,12 +232,12 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') checkKey(key) if (key.startsWith('_private_immutable')) { - const existingValue = await readData(key) + const existingValue = await currentBackend!.readData(key) if (existingValue !== undefined) { throw new Error('Cannot set already set immutable key') } } - await writeData(key, value) + await currentBackend!.writeData(key, value) // `get` uses `prefixableKey` as key, which now that the value is updated // is stale. We delete all prefixed key variants from the cache to // avoid serving stale data. Note that because of prefixes, `cache.set` @@ -242,6 +247,7 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean // Which one was faster depended on the browser, with no clear overall // winner, but `.forEach` was faster on Chrome, which uses the same // engine as Node.JS (V8). + const cache = currentCache! prefixes.forEach(prefix => { cache.delete(prefix + key) }) @@ -252,22 +258,22 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean if (key.startsWith('_private_immutable')) { throw new Error('Cannot delete immutable key') } - await deleteData(key) + await currentBackend!.deleteData(key) // `get` uses `prefixableKey` as key, which now that the value is updated // is stale. We delete all prefixed key variants from the cache to // avoid serving stale data. + const cache = currentCache! prefixes.forEach(prefix => { cache.delete(prefix + key) }) }, 'chelonia.db/iterKeys': () => { - return iterKeys() + return currentBackend!.iterKeys() }, 'chelonia.db/keyCount': () => { - return keyCount() + return currentBackend!.keyCount() } }) - sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) } initedDB = true } @@ -328,4 +334,18 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean initedDB = 'preloaded' } +export async function closeDB (): Promise { + if (currentBackend) { + try { + await currentBackend.close() + } catch (e) { + console.error(e, 'Error closing DB') + } + currentBackend = null + } + currentCache?.clear() + currentCache = null + initedDB = false +} + export * from './db-utils.ts' diff --git a/src/serve/index.ts b/src/serve/index.ts index 75ee0b4..0f48383 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -6,6 +6,7 @@ import sbp from 'npm:@sbp/sbp' import chalk from 'npm:chalk' import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' import { PUBSUB_INSTANCE } from './instance-keys.ts' +import { startServer as startServerImpl, stopServer as stopServerImpl } from './server.ts' import './logger.ts' console.info('NODE_ENV =', process.env.NODE_ENV) @@ -30,49 +31,63 @@ function logSBP (_domain: string, selector: string, data: Array) { // any specific selectors outside of backend namespace to log ;[].forEach(sel => sbp('sbp/filters/selector/add', sel, logSBP)) -export default () => (new Promise((resolve, reject) => { - sbp('okTurtles.events/on', SERVER_RUNNING, function () { - console.info(chalk.bold('backend startup sequence complete.')) - resolve() +// Signal handlers are installed only once per process +let signalHandlersInstalled = false +const signalHandlers: Array<[string, () => void]> = [] + +// Global exception handlers are installed only once per process +let globalExceptionHandlersInstalled = false + +// Helper to install global exception handlers (once per process) +function installGlobalExceptionHandlers (): void { + if (globalExceptionHandlersInstalled) return + globalExceptionHandlersInstalled = true + + process.on('uncaughtException', (err: Error) => { + console.error(err, '[server] Unhandled exception') + process.exit(1) }) - // call this after we've registered listener for SERVER_RUNNING - import('./server.ts').catch(reject) -})) -sbp('okTurtles.events/once', SERVER_EXITING, () => { - sbp('okTurtles.data/apply', PUBSUB_INSTANCE, function (pubsub: { on: (event: string, callback: () => void) => void; close: () => void; clients: { forEach: (callback: (client: { terminate: () => void }) => void) => void } }) { - sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { - return new Promise((resolve) => { - pubsub.on('close', async function () { - try { - removeSignalHandlers() - await sbp('chelonia.persistentActions/unload') - await sbp('backend/server/stop') - console.info('Server down') - } catch (err) { - console.error(err, 'Error during shutdown') - } finally { - resolve() - } - }) - pubsub.close() - // Since `ws` v8.0, `WebSocketServer.close()` no longer closes remaining connections. - // See https://github.com/websockets/ws/commit/df7de574a07115e2321fdb5fc9b2d0fea55d27e8 - pubsub.clients.forEach((client: { terminate: () => void }) => client.terminate()) - }) - }) + process.on('unhandledRejection', (reason: unknown) => { + console.error(reason, '[server] Unhandled promise rejection:', reason) + process.exit(1) }) -}) +} -process.on('uncaughtException', (err: Error) => { - console.error(err, '[server] Unhandled exception') - process.exit(1) -}) +// Helper to install signal handlers +function installSignalHandlers (): void { + if (signalHandlersInstalled) return + signalHandlersInstalled = true -process.on('unhandledRejection', (reason: unknown) => { - console.error(reason, '[server] Unhandled promise rejection:', reason) - process.exit(1) -}) + const handleSignal = (signal: string, code: number) => { + const handler = () => { + console.error(`Exiting upon receiving ${signal} (${code})`) + // Exit codes follow the 128 + signal code convention. + // See + exit(128 + code) + } + signalHandlers.push([signal, handler]) + process.on(signal, handler) + } + + // Codes from + ;([ + ['SIGHUP', 1], + ['SIGINT', 2], + ['SIGQUIT', 3], + ['SIGTERM', 15], + ['SIGUSR1', 10], + ['SIGUSR2', 11] + ] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) +} + +export function removeSignalHandlers (): void { + for (const [signal, handler] of signalHandlers) { + process.removeListener(signal, handler) + } + signalHandlers.length = 0 + signalHandlersInstalled = false +} const exit = (code: number) => { // Make sure `process.exit` is called after all existing SERVER_EXITING @@ -88,32 +103,60 @@ const exit = (code: number) => { sbp('okTurtles.events/emit', SERVER_EXITING) } -const signalHandlers: Array<[string, () => void]> = [] +export interface StartServerOptions { + installSignalHandlers?: boolean +} -const handleSignal = (signal: string, code: number) => { - const handler = () => { - console.error(`Exiting upon receiving ${signal} (${code})`) - // Exit codes follow the 128 + signal code convention. - // See - exit(128 + code) +export async function startServer (options: StartServerOptions = {}): Promise<{ uri: string }> { + const { installSignalHandlers: shouldInstallSignalHandlers = true } = options + + // Install global exception handlers once per process (only if signal handlers are enabled) + if (shouldInstallSignalHandlers) { + installGlobalExceptionHandlers() + installSignalHandlers() } - signalHandlers.push([signal, handler]) - process.on(signal, handler) + + // Register a SERVER_EXITING handler for this startServer call + // This handler self-removes when it fires + sbp('okTurtles.events/once', SERVER_EXITING, () => { + sbp('okTurtles.data/apply', PUBSUB_INSTANCE, function (pubsub: { on: (event: string, callback: () => void) => void; close: () => void; clients: { forEach: (callback: (client: { terminate: () => void }) => void) => void } }) { + sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { + return new Promise((resolve) => { + pubsub.on('close', async function () { + try { + removeSignalHandlers() + await sbp('chelonia.persistentActions/unload') + await stopServer() + console.info('Server down') + } catch (err) { + console.error(err, 'Error during shutdown') + } finally { + resolve() + } + }) + pubsub.close() + // Since `ws` v8.0, `WebSocketServer.close()` no longer closes remaining connections. + // See https://github.com/websockets/ws/commit/df7de574a07115e2321fdb5fc9b2d0fea55d27e8 + pubsub.clients.forEach((client: { terminate: () => void }) => client.terminate()) + }) + }) + }) + }) + + // Start the server and wait for it to be running + return await new Promise((resolve, reject) => { + sbp('okTurtles.events/on', SERVER_RUNNING, function onRunning (info: { info: { uri: string } }) { + sbp('okTurtles.events/off', SERVER_RUNNING, onRunning) + console.info(chalk.bold('backend startup sequence complete.')) + resolve({ uri: info.info.uri }) + }) + startServerImpl().catch(reject) + }) } -// Codes from -;([ - ['SIGHUP', 1], - ['SIGINT', 2], - ['SIGQUIT', 3], - ['SIGTERM', 15], - ['SIGUSR1', 10], - ['SIGUSR2', 11] -] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) - -export function removeSignalHandlers () { - for (const [signal, handler] of signalHandlers) { - process.removeListener(signal, handler) - } - signalHandlers.length = 0 +export async function stopServer (): Promise { + await stopServerImpl() } + +// Backwards compatibility: default export is startServer +export default startServer diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts index 9a4de5d..445f661 100644 --- a/src/serve/routes-test-helpers.ts +++ b/src/serve/routes-test-helpers.ts @@ -10,7 +10,7 @@ import { blake32Hash, createCID, multicodes } from 'npm:@chelonia/lib/functions' import { EDWARDS25519SHA512BATCH, keygen, keyId, serializeKey, sign } from 'npm:@chelonia/crypto' import { AUTHSALT, CONTRACTSALT, CS, SALT_LENGTH_IN_OCTETS } from 'npm:@chelonia/lib/zkppConstants' import tweetnacl from 'npm:tweetnacl' -import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' +import { startServer, stopServer } from './index.ts' export { blake32Hash, createCID, multicodes } from 'npm:@chelonia/lib/functions' export { EDWARDS25519SHA512BATCH, keygen, keyId, serializeKey, sign } from 'npm:@chelonia/crypto' @@ -129,28 +129,10 @@ export async function startTestServer (): Promise { } }) - const serverAddress = await new Promise((resolve, reject) => { - const unregister = sbp('okTurtles.events/once', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { - resolve(hapi.info.uri) - }) - import('./index.ts').then(({ default: start }) => { - return start() - }).catch((e) => { - unregister() - reject(e) - }) - }) - - return serverAddress + const { uri } = await startServer({ installSignalHandlers: false }) + return uri } export async function stopTestServer (): Promise { - await new Promise((resolve) => { - sbp('okTurtles.events/once', SERVER_EXITING, () => { - sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { - resolve() - }) - }) - sbp('okTurtles.events/emit', SERVER_EXITING) - }) + await stopServer() } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index d40a9bc..8a5afb3 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -15,7 +15,6 @@ import { isIP } from 'node:net' import path from 'node:path' import process from 'node:process' import { appendToIndexFactory, lookupUltimateOwner } from './database.ts' -import { SERVER_INSTANCE } from './instance-keys.ts' import logger from './logger.ts' import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' // @deno-types="npm:@types/nconf" @@ -138,48 +137,6 @@ function zValidatorFormOrJson ( } } -const FILE_UPLOAD_MAX_BYTES = nconf.get('server:fileUploadMaxBytes') || 30 * MEGABYTE -const SIGNUP_LIMIT_MIN = nconf.get('server:signup:limit:minute') || 2 -const SIGNUP_LIMIT_HOUR = nconf.get('server:signup:limit:hour') || 10 -const SIGNUP_LIMIT_DAY = nconf.get('server:signup:limit:day') || 50 -const SIGNUP_LIMIT_DISABLED = process.env.NODE_ENV !== 'production' || nconf.get('server:signup:limit:disabled') -const ARCHIVE_MODE = nconf.get('server:archiveMode') - -const limiterPerMinute = new Bottleneck.Group({ - strategy: Bottleneck.strategy.LEAK, - highWater: 0, - reservoir: SIGNUP_LIMIT_MIN, - reservoirRefreshInterval: 60 * SECOND, - reservoirRefreshAmount: SIGNUP_LIMIT_MIN -}) -const limiterPerHour = new Bottleneck.Group({ - strategy: Bottleneck.strategy.LEAK, - highWater: 0, - reservoir: SIGNUP_LIMIT_HOUR, - reservoirRefreshInterval: 60 * 60 * SECOND, - reservoirRefreshAmount: SIGNUP_LIMIT_HOUR -}) -const limiterPerDay = new Bottleneck.Group({ - strategy: Bottleneck.strategy.LEAK, - highWater: 0, - reservoir: SIGNUP_LIMIT_DAY, - reservoirRefreshInterval: 24 * 60 * 60 * SECOND, - reservoirRefreshAmount: SIGNUP_LIMIT_DAY -}) - -sbp('sbp/selectors/register', { - 'backend/server/stopRateLimiters': async function () { - const limiters = [limiterPerMinute, limiterPerHour, limiterPerDay] - await Promise.allSettled(limiters.map(l => l.disconnect())) - // Bottleneck v2 Group.disconnect() only disconnects the Redis connection (if any). - // The internal `setInterval` from `_startAutoCleanup()` is not cleaned up, causing - // async leaks on shutdown. We must clear it via the private `interval` property. - for (const limiter of limiters) { - clearInterval((limiter as unknown as { interval: ReturnType }).interval) - } - } -}) - const cidLookupTable = { [multicodes.SHELTER_CONTRACT_MANIFEST]: 'application/vnd.shelter.contractmanifest+json', [multicodes.SHELTER_CONTRACT_TEXT]: 'application/vnd.shelter.contracttext', @@ -260,14 +217,36 @@ const ctEq = (expected: string, actual: string): boolean => { return r === 0 } -const isCheloniaDashboard = process.env.IS_CHELONIA_DASHBOARD_DEV -const appDir = nconf.get('server:appDir') || '.' -const dashboardDir = import.meta.dirname || './build/dist-dashboard' -export const staticServeConfig = { - routePath: isCheloniaDashboard ? '/dashboard/{path*}' : '/app/{path*}', - distAssets: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'assets')), - distIndexHtml: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'index.html')), - redirect: isCheloniaDashboard ? '/dashboard/' : '/app/' +let currentLimiters: Bottleneck.Group[] = [] +let rateLimitersInstalled = false + +function installRateLimiterSelectorsOnce (): void { + if (rateLimitersInstalled) return + rateLimitersInstalled = true + sbp('sbp/selectors/register', { + 'backend/server/stopRateLimiters': async function () { + const limiters = currentLimiters + await Promise.allSettled(limiters.map(l => l.disconnect())) + // Bottleneck v2 Group.disconnect() only disconnects the Redis connection (if any). + // The internal `setInterval` from `_startAutoCleanup()` is not cleaned up, causing + // async leaks on shutdown. We must clear it via the private `interval` property. + for (const limiter of limiters) { + clearInterval((limiter as unknown as { interval: ReturnType }).interval) + } + } + }) +} + +export function getStaticServeConfig () { + const isCheloniaDashboard = process.env.IS_CHELONIA_DASHBOARD_DEV + const appDir = nconf.get('server:appDir') || '.' + const dashboardDir = import.meta.dirname || './build/dist-dashboard' + return { + routePath: isCheloniaDashboard ? '/dashboard/{path*}' : '/app/{path*}', + distAssets: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'assets')), + distIndexHtml: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'index.html')), + redirect: isCheloniaDashboard ? '/dashboard/' : '/app/' + } } const errorMapper = (e: Error): never => { @@ -335,201 +314,240 @@ function serveAsset (c: Context, subpath: string, assetsDir: string): Promise notFoundNoCache(c)) } -// Get the Hono app via SERVER_INSTANCE -const app: Hono = sbp('okTurtles.data/get', SERVER_INSTANCE) - -// RESTful API routes - -// NOTE: We could get rid of this RESTful API and just rely on pubsub.js to do this -// —BUT HTTP2 might be better than websockets and so we keep this around. -// See related TODO in pubsub.js and the reddit discussion link. -app.post('/event', - bodyLimit({ maxSize: MEGABYTE }), - authMiddleware('chel-shelter', 'optional'), - zValidator('header', eventHeaderSchema), - async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE - // X-Real-IP HEADER! OTHERWISE THIS IS EASILY SPOOFED! - const ip = getClientIP(c) - try { - const payload = await c.req.text() - if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) - const validatedHeaders = c.req.valid('header') - const deserializedHEAD = SPMessage.deserializeHEAD(payload) +export function registerRoutes (app: Hono): void { + // Clean up any previous rate limiters (their intervals leak if stopRateLimiters + // wasn't called, e.g. when the SERVER_EXITING handler was consumed already) + for (const limiter of currentLimiters) { + limiter.disconnect() + clearInterval((limiter as unknown as { interval: ReturnType }).interval) + } + + const FILE_UPLOAD_MAX_BYTES = nconf.get('server:fileUploadMaxBytes') || 30 * MEGABYTE + const SIGNUP_LIMIT_MIN = nconf.get('server:signup:limit:minute') || 2 + const SIGNUP_LIMIT_HOUR = nconf.get('server:signup:limit:hour') || 10 + const SIGNUP_LIMIT_DAY = nconf.get('server:signup:limit:day') || 50 + const SIGNUP_LIMIT_DISABLED = process.env.NODE_ENV !== 'production' || nconf.get('server:signup:limit:disabled') + const ARCHIVE_MODE = nconf.get('server:archiveMode') + + const limiterPerMinute = new Bottleneck.Group({ + strategy: Bottleneck.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_MIN, + reservoirRefreshInterval: 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_MIN + }) + const limiterPerHour = new Bottleneck.Group({ + strategy: Bottleneck.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_HOUR, + reservoirRefreshInterval: 60 * 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_HOUR + }) + const limiterPerDay = new Bottleneck.Group({ + strategy: Bottleneck.strategy.LEAK, + highWater: 0, + reservoir: SIGNUP_LIMIT_DAY, + reservoirRefreshInterval: 24 * 60 * 60 * SECOND, + reservoirRefreshAmount: SIGNUP_LIMIT_DAY + }) + currentLimiters = [limiterPerMinute, limiterPerHour, limiterPerDay] + installRateLimiterSelectorsOnce() + + const isCheloniaDashboard = process.env.IS_CHELONIA_DASHBOARD_DEV + const staticServeConfig = getStaticServeConfig() + + // RESTful API routes + + // NOTE: We could get rid of this RESTful API and just rely on pubsub.js to do this + // —BUT HTTP2 might be better than websockets and so we keep this around. + // See related TODO in pubsub.js and the reddit discussion link. + app.post('/event', + bodyLimit({ maxSize: MEGABYTE }), + authMiddleware('chel-shelter', 'optional'), + zValidator('header', eventHeaderSchema), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE + // X-Real-IP HEADER! OTHERWISE THIS IS EASILY SPOOFED! + const ip = getClientIP(c) try { - const parsed = maybeParseCID(deserializedHEAD.head.manifest) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { - throw new HTTPException(422, { message: 'Invalid manifest' }) - } - const credentials = c.get('credentials') as AuthCredentials | undefined - // Only allow identity contracts to be created without attribution - if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { - const manifest = await sbp('chelonia.db/get', deserializedHEAD.head.manifest) - const parsedManifest = JSON.parse(manifest) - const { name } = JSON.parse(parsedManifest.body) - if (name !== 'gi.contracts/identity') { - throw new HTTPException(401, { message: 'This contract type requires ownership information' }) - } - if (nconf.get('server:signup:disabled')) { - throw new HTTPException(403, { message: 'Registration disabled' }) + const payload = await c.req.text() + if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) + const validatedHeaders = c.req.valid('header') + const deserializedHEAD = SPMessage.deserializeHEAD(payload) + try { + const parsed = maybeParseCID(deserializedHEAD.head.manifest) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_MANIFEST) { + throw new HTTPException(422, { message: 'Invalid manifest' }) } - // rate limit signups in production - if (!SIGNUP_LIMIT_DISABLED) { - try { + const credentials = c.get('credentials') as AuthCredentials | undefined + // Only allow identity contracts to be created without attribution + if (!credentials?.billableContractID && deserializedHEAD.isFirstMessage) { + const manifest = await sbp('chelonia.db/get', deserializedHEAD.head.manifest) + const parsedManifest = JSON.parse(manifest) + const { name } = JSON.parse(parsedManifest.body) + if (name !== 'gi.contracts/identity') { + throw new HTTPException(401, { message: 'This contract type requires ownership information' }) + } + if (nconf.get('server:signup:disabled')) { + throw new HTTPException(403, { message: 'Registration disabled' }) + } + // rate limit signups in production + if (!SIGNUP_LIMIT_DISABLED) { + try { // See discussion: https://github.com/okTurtles/group-income/pull/2280#pullrequestreview-2219347378 - const keyedIp = limiterKey(ip) - await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()) - await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()) - await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()) - } catch { - console.warn('rate limit hit for IP:', ip) - throw new HTTPException(429, { message: 'Rate limit exceeded' }) + const keyedIp = limiterKey(ip) + await limiterPerMinute.key(keyedIp).schedule(() => Promise.resolve()) + await limiterPerHour.key(keyedIp).schedule(() => Promise.resolve()) + await limiterPerDay.key(keyedIp).schedule(() => Promise.resolve()) + } catch { + console.warn('rate limit hit for IP:', ip) + throw new HTTPException(429, { message: 'Rate limit exceeded' }) + } } } - } - const saltUpdateToken = validatedHeaders['shelter-salt-update-token'] - let updateSalts - if (saltUpdateToken) { + const saltUpdateToken = validatedHeaders['shelter-salt-update-token'] + let updateSalts + if (saltUpdateToken) { // If we've got a salt update token (i.e., a password change), // validate the token - updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken) - } - await sbp('backend/server/handleEntry', deserializedHEAD, payload) - // If it's a salt update, do it now after handling the message. This way - // we make it less likely that someone will end up locked out from their - // identity contract. - await updateSalts?.(deserializedHEAD.hash) - if (deserializedHEAD.isFirstMessage) { - // Store attribution information - if (credentials?.billableContractID) { - await sbp('backend/server/saveOwner', credentials.billableContractID, deserializedHEAD.contractID) - // A billable entity has been created - } else { - await sbp('backend/server/registerBillableEntity', deserializedHEAD.contractID) + updateSalts = await redeemSaltUpdateToken(deserializedHEAD.contractID, saltUpdateToken) } - // If this is the first message in a contract and the - // `shelter-namespace-registration` header is present, proceed with also - // registering a name for the new contract - const name = validatedHeaders['shelter-namespace-registration'] - if (name) { - // Name registation is enabled only for identity contracts - const cheloniaState = sbp('chelonia/rootState') - if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === 'gi.contracts/identity') { - try { - await sbp('backend/db/registerName', name, deserializedHEAD.contractID) - } catch (registerErr: unknown) { - if ((registerErr as Error).name === 'BackendErrorConflict') { - throw new HTTPException(409, { message: 'Name already exists' }) + await sbp('backend/server/handleEntry', deserializedHEAD, payload) + // If it's a salt update, do it now after handling the message. This way + // we make it less likely that someone will end up locked out from their + // identity contract. + await updateSalts?.(deserializedHEAD.hash) + if (deserializedHEAD.isFirstMessage) { + // Store attribution information + if (credentials?.billableContractID) { + await sbp('backend/server/saveOwner', credentials.billableContractID, deserializedHEAD.contractID) + // A billable entity has been created + } else { + await sbp('backend/server/registerBillableEntity', deserializedHEAD.contractID) + } + // If this is the first message in a contract and the + // `shelter-namespace-registration` header is present, proceed with also + // registering a name for the new contract + const name = validatedHeaders['shelter-namespace-registration'] + if (name) { + // Name registation is enabled only for identity contracts + const cheloniaState = sbp('chelonia/rootState') + if (cheloniaState.contracts[deserializedHEAD.contractID]?.type === 'gi.contracts/identity') { + try { + await sbp('backend/db/registerName', name, deserializedHEAD.contractID) + } catch (registerErr: unknown) { + if ((registerErr as Error).name === 'BackendErrorConflict') { + throw new HTTPException(409, { message: 'Name already exists' }) + } + throw registerErr } - throw registerErr - } - const saltRegistrationToken = validatedHeaders['shelter-salt-registration-token'] - console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`) - if (saltRegistrationToken) { + const saltRegistrationToken = validatedHeaders['shelter-salt-registration-token'] + console.info(`new user: ${name}=${deserializedHEAD.contractID} (${ip})`) + if (saltRegistrationToken) { // If we've got a salt registration token, redeem it - await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken) + await redeemSaltRegistrationToken(name, deserializedHEAD.contractID, saltRegistrationToken) + } } } + const deletionTokenDgst = validatedHeaders['shelter-deletion-token-digest'] + if (deletionTokenDgst) { + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst) + } } - const deletionTokenDgst = validatedHeaders['shelter-deletion-token-digest'] - if (deletionTokenDgst) { - await sbp('chelonia.db/set', `_private_deletionTokenDgst_${deserializedHEAD.contractID}`, deletionTokenDgst) + // Store size information + await sbp('backend/server/updateSize', deserializedHEAD.contractID, Buffer.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : undefined) + } catch (err: unknown) { + if (err instanceof HTTPException) throw err + console.error(err, chalk.bold.yellow((err as Error).name)) + if ((err as Error).name === 'ChelErrorDBBadPreviousHEAD' || (err as Error).name === 'ChelErrorAlreadyProcessed') { + const HEADinfo = await sbp('chelonia/db/latestHEADinfo', deserializedHEAD.contractID) ?? { HEAD: null, height: 0 } + return c.json({ message: (err as Error).message, data: { HEADinfo } }, 409, { + 'shelter-headinfo-head': HEADinfo.HEAD, + 'shelter-headinfo-height': String(HEADinfo.height) + }) + } else if ((err as Error).name === 'ChelErrorSignatureError') { + throw new HTTPException(422, { message: 'Invalid signature' }) + } else if ((err as Error).name === 'ChelErrorSignatureKeyUnauthorized') { + throw new HTTPException(403, { message: 'Unauthorized signing key' }) } + throw err // rethrow error } - // Store size information - await sbp('backend/server/updateSize', deserializedHEAD.contractID, Buffer.byteLength(payload), deserializedHEAD.isFirstMessage && !credentials?.billableContractID ? deserializedHEAD.contractID : undefined) - } catch (err: unknown) { + return c.text(deserializedHEAD.hash) + } catch (err) { if (err instanceof HTTPException) throw err - console.error(err, chalk.bold.yellow((err as Error).name)) - if ((err as Error).name === 'ChelErrorDBBadPreviousHEAD' || (err as Error).name === 'ChelErrorAlreadyProcessed') { - const HEADinfo = await sbp('chelonia/db/latestHEADinfo', deserializedHEAD.contractID) ?? { HEAD: null, height: 0 } - return c.json({ message: (err as Error).message, data: { HEADinfo } }, 409, { - 'shelter-headinfo-head': HEADinfo.HEAD, - 'shelter-headinfo-height': String(HEADinfo.height) - }) - } else if ((err as Error).name === 'ChelErrorSignatureError') { - throw new HTTPException(422, { message: 'Invalid signature' }) - } else if ((err as Error).name === 'ChelErrorSignatureKeyUnauthorized') { - throw new HTTPException(403, { message: 'Unauthorized signing key' }) - } - throw err // rethrow error + ;(err as unknown as { ip: string }).ip = ip + logger.error(err, 'POST /event', (err as Error).message) + throw err } - return c.text(deserializedHEAD.hash) - } catch (err) { - if (err instanceof HTTPException) throw err - ;(err as unknown as { ip: string }).ip = ip - logger.error(err, 'POST /event', (err as Error).message) - throw err - } - }) + }) -app.get('/eventsAfter/:contractID/:since/:limit?', - zValidator('param', eventsAfterParamSchema), - async function (c) { - const { contractID, since, limit } = c.req.valid('param') + app.get('/eventsAfter/:contractID/:since/:limit?', + zValidator('param', eventsAfterParamSchema), + async function (c) { + const { contractID, since, limit } = c.req.valid('param') - const keyOps = c.req.query('keyOps') - const ip = getClientIP(c) - try { - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400) - } + const keyOps = c.req.query('keyOps') + const ip = getClientIP(c) + try { + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } - const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: keyOps === 'true' }) as Readable - // "On an HTTP server, make sure to manually close your streams if a request is aborted." - // From: http://knexjs.org/#Interfaces-Streams - // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams - // Use the request abort signal to destroy the stream when the client disconnects - c.req.raw.signal.addEventListener('abort', () => stream.destroy()) - // Convert the Node Readable stream to a web ReadableStream for the Response - const streamHeaders = (stream as { headers?: Record }).headers || {} - const webStream = Readable.toWeb(stream) as ReadableStream - return new Response(webStream, { - headers: { 'content-type': 'application/octet-stream', ...streamHeaders } - }) - } catch (err) { - if (err instanceof HTTPException) throw err - ;(err as unknown as { ip: string }).ip = ip - logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) - errorMapper(err as Error) - } - }) + const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: keyOps === 'true' }) as Readable + // "On an HTTP server, make sure to manually close your streams if a request is aborted." + // From: http://knexjs.org/#Interfaces-Streams + // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams + // Use the request abort signal to destroy the stream when the client disconnects + c.req.raw.signal.addEventListener('abort', () => stream.destroy()) + // Convert the Node Readable stream to a web ReadableStream for the Response + const streamHeaders = (stream as { headers?: Record }).headers || {} + const webStream = Readable.toWeb(stream) as ReadableStream + return new Response(webStream, { + headers: { 'content-type': 'application/octet-stream', ...streamHeaders } + }) + } catch (err) { + if (err instanceof HTTPException) throw err + ;(err as unknown as { ip: string }).ip = ip + logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) + errorMapper(err as Error) + } + }) -// This endpoint returns to anyone in possession of a contract's SAK all of the -// resources that that contract owns (without recursion). This is useful for -// APIs and for some UI actions (e.g., to warn users about resources that would -// be (cascade) deleted following a delete) -app.get('/ownResources', - authMiddleware('chel-shelter', 'required'), - async function (c) { - const billableContractID = (c.get('credentials') as AuthCredentials).billableContractID - const resources = (await sbp('chelonia.db/get', `_private_resources_${billableContractID}`))?.split('\x00') - - return c.json(resources || []) - }) + // This endpoint returns to anyone in possession of a contract's SAK all of the + // resources that that contract owns (without recursion). This is useful for + // APIs and for some UI actions (e.g., to warn users about resources that would + // be (cascade) deleted following a delete) + app.get('/ownResources', + authMiddleware('chel-shelter', 'required'), + async function (c) { + const billableContractID = (c.get('credentials') as AuthCredentials).billableContractID + const resources = (await sbp('chelonia.db/get', `_private_resources_${billableContractID}`))?.split('\x00') + + return c.json(resources || []) + }) -if (process.env.NODE_ENV === 'development') { - const levelToColor = { - error: chalk.bold.red, - warn: chalk.yellow, - log: chalk.green, - info: chalk.green, - debug: chalk.blue + if (process.env.NODE_ENV === 'development') { + const levelToColor = { + error: chalk.bold.red, + warn: chalk.yellow, + log: chalk.green, + info: chalk.green, + debug: chalk.blue + } + app.post('/log', async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const body = await c.req.json() as { level: string, value: string } + if (!body.level || !body.value) throw new HTTPException(400, { message: 'level and value are required' }) + const ip = getClientIP(c) + const log = (levelToColor as Record string>)[body.level] + console.debug(chalk.bold.yellow(`REMOTE LOG (${ip}): `) + log(`[${body.level}] ${body.value}`)) + return c.body(null, 200) + }) } - app.post('/log', async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const body = await c.req.json() as { level: string, value: string } - if (!body.level || !body.value) throw new HTTPException(400, { message: 'level and value are required' }) - const ip = getClientIP(c) - const log = (levelToColor as Record string>)[body.level] - console.debug(chalk.bold.yellow(`REMOTE LOG (${ip}): `) + log(`[${body.level}] ${body.value}`)) - return c.body(null, 200) - }) -} -/* + /* // The following endpoint is disabled because name registrations are handled // through the `shelter-namespace-registration` header when registering a // new contract @@ -547,601 +565,602 @@ app.post('/name', async function (c) { }) */ -app.get('/name/:name', zValidator('param', nameParamSchema), async function (c) { - const { name } = c.req.valid('param') - try { - const lookupResult = await sbp('backend/db/lookupName', name) - return lookupResult - ? c.text(lookupResult) - : notFoundNoCache(c) - } catch (err) { - logger.error(err, `GET /name/${name}`, (err as Error).message) - throw err - } -}) - -app.get('/latestHEADinfo/:contractID', zValidator('param', cidParamSchema), async function (c) { - const { contractID } = c.req.valid('param') - try { - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) - - const HEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) - if (HEADinfo === '') { - throw new HTTPException(410) - } - if (!HEADinfo) { - console.warn(`[backend] latestHEADinfo not found for ${contractID}`) - return notFoundNoCache(c) + app.get('/name/:name', zValidator('param', nameParamSchema), async function (c) { + const { name } = c.req.valid('param') + try { + const lookupResult = await sbp('backend/db/lookupName', name) + return lookupResult + ? c.text(lookupResult) + : notFoundNoCache(c) + } catch (err) { + logger.error(err, `GET /name/${name}`, (err as Error).message) + throw err } - return c.json(HEADinfo, 200, { 'Cache-Control': 'no-store' }) - } catch (err) { - if (err instanceof HTTPException) throw err - logger.error(err, `GET /latestHEADinfo/${contractID}`, (err as Error).message) - throw err - } -}) - -app.get('/time', function (c) { - return c.text(new Date().toISOString(), 200, { - 'Cache-Control': 'no-store' }) -}) -// TODO: if the browser deletes our cache then not everyone -// has a complete copy of the data and can act as a -// new coordinating server... I don't like that. - -// API endpoint to check for streams support -app.post('/streams-test', async function (c) { - const raw = await c.req.arrayBuffer() - const buf = Buffer.from(raw) - if (buf.byteLength === 2 && buf.toString() === 'ok') { - return c.body(null, 204) - } else { - throw new HTTPException(400) - } -}) - -// Development file upload route. The difference between this and /file is that -// this endpoint bypasses checks in /file for well-formedness, and it also -// doesn't set or read accounting information. -// If accepted, the file will be stored in Chelonia DB. -if (process.env.NODE_ENV === 'development') { - app.post('/dev-file', bodyLimit({ maxSize: 6 * MEGABYTE }), async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + app.get('/latestHEADinfo/:contractID', zValidator('param', cidParamSchema), async function (c) { + const { contractID } = c.req.valid('param') try { - console.log('FILE UPLOAD!') - const formData = await c.req.parseBody({ all: true }) - const hash = formData['hash'] as string - const data = formData['data'] as string - if (!hash) throw new HTTPException(400, { message: 'missing hash' }) - if (!data) throw new HTTPException(400, { message: 'missing data' }) - - const parsed = maybeParseCID(hash) - if (!parsed) throw new HTTPException(400, { message: 'invalid hash' }) + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) - const ourHash = createCID(data, parsed.code) - if (ourHash !== hash) { - console.error(`hash(${hash}) != ourHash(${ourHash})`) - throw new HTTPException(400, { message: 'bad hash!' }) + const HEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) + if (HEADinfo === '') { + throw new HTTPException(410) } - await sbp('chelonia.db/set', hash, data) - return c.text('/file/' + hash) + if (!HEADinfo) { + console.warn(`[backend] latestHEADinfo not found for ${contractID}`) + return notFoundNoCache(c) + } + return c.json(HEADinfo, 200, { 'Cache-Control': 'no-store' }) } catch (err) { if (err instanceof HTTPException) throw err - logger.error(err) - throw new HTTPException(500, { message: 'File upload failed' }) + logger.error(err, `GET /latestHEADinfo/${contractID}`, (err as Error).message) + throw err } }) -} -// File upload route. -// If accepted, the file will be stored in Chelonia DB. -app.post('/file', - bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), - authMiddleware('chel-shelter', 'required'), - async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - try { - console.info('FILE UPLOAD!') - const credentials = c.get('credentials') as AuthCredentials - if (!credentials?.billableContractID) { - throw new HTTPException(401, { message: 'Uploading files requires ownership information' }) - } + app.get('/time', function (c) { + return c.text(new Date().toISOString(), 200, { + 'Cache-Control': 'no-store' + }) + }) - const contentType = c.req.header('content-type') || '' - if (!contentType.includes('multipart/form-data')) { - throw new HTTPException(400, { message: 'Expected multipart/form-data' }) - } + // TODO: if the browser deletes our cache then not everyone + // has a complete copy of the data and can act as a + // new coordinating server... I don't like that. - const formData = await c.req.formData() - const manifestFile = formData.get('manifest') as File | null - if (!manifestFile) throw new HTTPException(400, { message: 'missing manifest' }) - if (manifestFile.name !== 'manifest.json') throw new HTTPException(400, { message: 'wrong manifest filename' }) - const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()) + // API endpoint to check for streams support + app.post('/streams-test', async function (c) { + const raw = await c.req.arrayBuffer() + const buf = Buffer.from(raw) + if (buf.byteLength === 2 && buf.toString() === 'ok') { + return c.body(null, 204) + } else { + throw new HTTPException(400) + } + }) - const manifest = (() => { - try { - return JSON.parse(Buffer.from(manifestPayload).toString()) - } catch { - throw new HTTPException(422, { message: 'Error parsing manifest' }) + // Development file upload route. The difference between this and /file is that + // this endpoint bypasses checks in /file for well-formedness, and it also + // doesn't set or read accounting information. + // If accepted, the file will be stored in Chelonia DB. + if (process.env.NODE_ENV === 'development') { + app.post('/dev-file', bodyLimit({ maxSize: 6 * MEGABYTE }), async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + try { + console.log('FILE UPLOAD!') + const formData = await c.req.parseBody({ all: true }) + const hash = formData['hash'] as string + const data = formData['data'] as string + if (!hash) throw new HTTPException(400, { message: 'missing hash' }) + if (!data) throw new HTTPException(400, { message: 'missing data' }) + + const parsed = maybeParseCID(hash) + if (!parsed) throw new HTTPException(400, { message: 'invalid hash' }) + + const ourHash = createCID(data, parsed.code) + if (ourHash !== hash) { + console.error(`hash(${hash}) != ourHash(${ourHash})`) + throw new HTTPException(400, { message: 'bad hash!' }) } - })() - if (typeof manifest !== 'object') throw new HTTPException(422, { message: 'manifest format is invalid' }) - if (manifest.version !== '1.0.0') throw new HTTPException(422, { message: 'unsupported manifest version' }) - if (manifest.cipher !== 'aes256gcm') throw new HTTPException(422, { message: 'unsupported cipher' }) - if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new HTTPException(422, { message: 'missing chunks' }) - - // Collect all chunk files from form data (numbered keys: 0, 1, 2, ...) - const chunkFiles: File[] = [] - for (let i = 0; ; i++) { - const chunkFile = formData.get(String(i)) as File | null - if (!chunkFile) break - chunkFiles.push(chunkFile) + await sbp('chelonia.db/set', hash, data) + return c.text('/file/' + hash) + } catch (err) { + if (err instanceof HTTPException) throw err + logger.error(err) + throw new HTTPException(500, { message: 'File upload failed' }) } + }) + } + + // File upload route. + // If accepted, the file will be stored in Chelonia DB. + app.post('/file', + bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), + authMiddleware('chel-shelter', 'required'), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + try { + console.info('FILE UPLOAD!') + const credentials = c.get('credentials') as AuthCredentials + if (!credentials?.billableContractID) { + throw new HTTPException(401, { message: 'Uploading files requires ownership information' }) + } - // Now that the manifest format looks right, validate the chunks - let ourSize = 0 - const chunks: [string, Uint8Array][] = await Promise.all(manifest.chunks.map(async (chunk: [number, string], i: number) => { + const contentType = c.req.header('content-type') || '' + if (!contentType.includes('multipart/form-data')) { + throw new HTTPException(400, { message: 'Expected multipart/form-data' }) + } + + const formData = await c.req.formData() + const manifestFile = formData.get('manifest') as File | null + if (!manifestFile) throw new HTTPException(400, { message: 'missing manifest' }) + if (manifestFile.name !== 'manifest.json') throw new HTTPException(400, { message: 'wrong manifest filename' }) + const manifestPayload = new Uint8Array(await manifestFile.arrayBuffer()) + + const manifest = (() => { + try { + return JSON.parse(Buffer.from(manifestPayload).toString()) + } catch { + throw new HTTPException(422, { message: 'Error parsing manifest' }) + } + })() + if (typeof manifest !== 'object') throw new HTTPException(422, { message: 'manifest format is invalid' }) + if (manifest.version !== '1.0.0') throw new HTTPException(422, { message: 'unsupported manifest version' }) + if (manifest.cipher !== 'aes256gcm') throw new HTTPException(422, { message: 'unsupported cipher' }) + if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new HTTPException(422, { message: 'missing chunks' }) + + // Collect all chunk files from form data (numbered keys: 0, 1, 2, ...) + const chunkFiles: File[] = [] + for (let i = 0; ; i++) { + const chunkFile = formData.get(String(i)) as File | null + if (!chunkFile) break + chunkFiles.push(chunkFile) + } + + // Now that the manifest format looks right, validate the chunks + let ourSize = 0 + const chunks: [string, Uint8Array][] = await Promise.all(manifest.chunks.map(async (chunk: [number, string], i: number) => { // Validate the chunk information - if ( - !Array.isArray(chunk) || + if ( + !Array.isArray(chunk) || chunk.length !== 2 || typeof chunk[0] !== 'number' || typeof chunk[1] !== 'string' || !Number.isSafeInteger(chunk[0]) || chunk[0] <= 0 - ) { - throw new HTTPException(422, { message: 'bad chunk description' }) - } - if (!chunkFiles[i]) { - throw new HTTPException(400, { message: 'chunk missing in submitted data' }) - } - const chunkPayload = new Uint8Array(await chunkFiles[i].arrayBuffer()) - const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK) - if (chunkPayload.byteLength !== chunk[0]) { - throw new HTTPException(400, { message: 'bad chunk size' }) - } - if (ourHash !== chunk[1]) { - throw new HTTPException(400, { message: 'bad chunk hash' }) + ) { + throw new HTTPException(422, { message: 'bad chunk description' }) + } + if (!chunkFiles[i]) { + throw new HTTPException(400, { message: 'chunk missing in submitted data' }) + } + const chunkPayload = new Uint8Array(await chunkFiles[i].arrayBuffer()) + const ourHash = createCID(chunkPayload, multicodes.SHELTER_FILE_CHUNK) + if (chunkPayload.byteLength !== chunk[0]) { + throw new HTTPException(400, { message: 'bad chunk size' }) + } + if (ourHash !== chunk[1]) { + throw new HTTPException(400, { message: 'bad chunk hash' }) + } + // We're done validating the chunk + ourSize += chunk[0] + return [ourHash, chunkPayload] as [string, Uint8Array] + })) + // Finally, verify the size is correct + if (ourSize !== manifest.size) throw new HTTPException(400, { message: 'Mismatched total size' }) + + const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST) + + // Check that we're not overwriting data. At best this is a useless operation + // since there is no need to write things that exist. However, overwriting + // data would also make it ambiguous in terms of ownership. For example, + // someone could upload a file F1 using some existing chunks (from a + // different file F2) and then request to delete their file F1, which would + // result in corrupting F2. + // Ensure that the manifest doesn't exist + if (await sbp('chelonia.db/get', manifestHash)) { + throw new Error(`Manifest ${manifestHash} already exists`) } - // We're done validating the chunk - ourSize += chunk[0] - return [ourHash, chunkPayload] as [string, Uint8Array] - })) - // Finally, verify the size is correct - if (ourSize !== manifest.size) throw new HTTPException(400, { message: 'Mismatched total size' }) - - const manifestHash = createCID(manifestPayload, multicodes.SHELTER_FILE_MANIFEST) - - // Check that we're not overwriting data. At best this is a useless operation - // since there is no need to write things that exist. However, overwriting - // data would also make it ambiguous in terms of ownership. For example, - // someone could upload a file F1 using some existing chunks (from a - // different file F2) and then request to delete their file F1, which would - // result in corrupting F2. - // Ensure that the manifest doesn't exist - if (await sbp('chelonia.db/get', manifestHash)) { - throw new Error(`Manifest ${manifestHash} already exists`) - } - // Ensure that the chunks do not exist - await Promise.all(chunks.map(async ([cid]) => { - const exists = !!(await sbp('chelonia.db/get', cid)) - if (exists) { - throw new Error(`Chunk ${cid} already exists`) + // Ensure that the chunks do not exist + await Promise.all(chunks.map(async ([cid]) => { + const exists = !!(await sbp('chelonia.db/get', cid)) + if (exists) { + throw new Error(`Chunk ${cid} already exists`) + } + })) + // Now, store all chunks and the manifest + await Promise.all(chunks.map(([cid, data]) => sbp('chelonia.db/set', cid, data))) + await sbp('chelonia.db/set', manifestHash, manifestPayload) + // Store attribution information + await sbp('backend/server/saveOwner', credentials.billableContractID, manifestHash) + // Store size information + const size = manifest.size + manifestPayload.byteLength + await sbp('backend/server/updateSize', manifestHash, size) + await sbp('backend/server/updateContractFilesTotalSize', credentials.billableContractID, size) + // Store deletion token + const deletionTokenDgst = c.req.header('shelter-deletion-token-digest') + if (deletionTokenDgst) { + await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst) } - })) - // Now, store all chunks and the manifest - await Promise.all(chunks.map(([cid, data]) => sbp('chelonia.db/set', cid, data))) - await sbp('chelonia.db/set', manifestHash, manifestPayload) - // Store attribution information - await sbp('backend/server/saveOwner', credentials.billableContractID, manifestHash) - // Store size information - const size = manifest.size + manifestPayload.byteLength - await sbp('backend/server/updateSize', manifestHash, size) - await sbp('backend/server/updateContractFilesTotalSize', credentials.billableContractID, size) - // Store deletion token - const deletionTokenDgst = c.req.header('shelter-deletion-token-digest') - if (deletionTokenDgst) { - await sbp('chelonia.db/set', `_private_deletionTokenDgst_${manifestHash}`, deletionTokenDgst) + return c.text(manifestHash) + } catch (err) { + if (err instanceof HTTPException) throw err + logger.error(err, 'POST /file', (err as Error).message) + throw err } - return c.text(manifestHash) - } catch (err) { - if (err instanceof HTTPException) throw err - logger.error(err, 'POST /file', (err as Error).message) - throw err - } - }) - -// Serve data from Chelonia DB. -// Note that a `Last-Modified` header isn't included in the response. -app.get('/file/:hash', zValidator('param', cidHashParamSchema), async function (c) { - const { hash } = c.req.valid('param') - - const parsed = maybeParseCID(hash) - if (!parsed) { - throw new HTTPException(400) - } - - const blobOrString = await sbp('chelonia.db/get', `any:${hash}`) - if (blobOrString?.length === 0) { - throw new HTTPException(410) - } else if (!blobOrString) { - return notFoundNoCache(c) - } - - const type = cidLookupTable[parsed.code] || 'application/octet-stream' - - return c.body(blobOrString, 200, { - 'ETag': `"${hash}"`, - 'Cache-Control': 'public,max-age=31536000,immutable', - // CSP to disable everything -- this only affects direct navigation to the - // `/file` URL. - // The CSP below prevents any sort of resource loading or script execution - // on direct navigation. The `nosniff` header instructs the browser to - // honour the provided content-type. - 'Content-Security-Policy': 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox', - 'X-Content-Type-Options': 'nosniff', - 'Content-Type': type - }) -}) + }) -app.post('/deleteFile/:hash', - authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), - zValidator('param', cidHashParamSchema), - async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + // Serve data from Chelonia DB. + // Note that a `Last-Modified` header isn't included in the response. + app.get('/file/:hash', zValidator('param', cidHashParamSchema), async function (c) { const { hash } = c.req.valid('param') - const strategy = c.get('authStrategy') + const parsed = maybeParseCID(hash) - if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { + if (!parsed) { throw new HTTPException(400) } - const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) - if (!owner) { - throw new HTTPException(404) + const blobOrString = await sbp('chelonia.db/get', `any:${hash}`) + if (blobOrString?.length === 0) { + throw new HTTPException(410) + } else if (!blobOrString) { + return notFoundNoCache(c) } - const credentials = c.get('credentials') as AuthCredentials - switch (strategy) { - case 'chel-shelter': { - const ultimateOwner = await lookupUltimateOwner(owner) - // Check that the user making the request is the ultimate owner (i.e., - // that they have permission to delete this file) - if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { - throw new HTTPException(401, { message: 'Invalid shelter auth' }) - } - break + const type = cidLookupTable[parsed.code] || 'application/octet-stream' + + return c.body(blobOrString, 200, { + 'ETag': `"${hash}"`, + 'Cache-Control': 'public,max-age=31536000,immutable', + // CSP to disable everything -- this only affects direct navigation to the + // `/file` URL. + // The CSP below prevents any sort of resource loading or script execution + // on direct navigation. The `nosniff` header instructs the browser to + // honour the provided content-type. + 'Content-Security-Policy': 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox', + 'X-Content-Type-Options': 'nosniff', + 'Content-Type': type + }) + }) + + app.post('/deleteFile/:hash', + authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + zValidator('param', cidHashParamSchema), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const { hash } = c.req.valid('param') + const strategy = c.get('authStrategy') + const parsed = maybeParseCID(hash) + if (parsed?.code !== multicodes.SHELTER_FILE_MANIFEST) { + throw new HTTPException(400) + } + + const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) + if (!owner) { + throw new HTTPException(404) } - case 'chel-bearer': { - const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) - if (!expectedTokenDgst) { - throw new HTTPException(404) + + const credentials = c.get('credentials') as AuthCredentials + switch (strategy) { + case 'chel-shelter': { + const ultimateOwner = await lookupUltimateOwner(owner) + // Check that the user making the request is the ultimate owner (i.e., + // that they have permission to delete this file) + if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { + throw new HTTPException(401, { message: 'Invalid shelter auth' }) + } + break } - const tokenDgst = blake32Hash(credentials.token as string) - // Constant-time comparison - // Check that the token provided matches the deletion token for this file - if (!ctEq(expectedTokenDgst, tokenDgst)) { - throw new HTTPException(401, { message: 'Invalid token' }) + case 'chel-bearer': { + const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) + if (!expectedTokenDgst) { + throw new HTTPException(404) + } + const tokenDgst = blake32Hash(credentials.token as string) + // Constant-time comparison + // Check that the token provided matches the deletion token for this file + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: 'Invalid token' }) + } + break } - break + default: + throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) } - default: - throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) - } - // Authentication passed, now proceed to delete the file and its associated - // keys - try { - await sbp('backend/deleteFile', hash, null, true) - return c.body(null, 200) - } catch (e) { - errorMapper(e as Error) - } - }) + // Authentication passed, now proceed to delete the file and its associated + // keys + try { + await sbp('backend/deleteFile', hash, null, true) + return c.body(null, 200) + } catch (e) { + errorMapper(e as Error) + } + }) -app.post('/deleteContract/:hash', - authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), - zValidator('param', cidHashParamSchema), - async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const { hash } = c.req.valid('param') - const strategy = c.get('authStrategy') - - const credentials = c.get('credentials') as AuthCredentials - switch (strategy) { - case 'chel-shelter': { - const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) - if (!owner) { - throw new HTTPException(404) - } + app.post('/deleteContract/:hash', + authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), + zValidator('param', cidHashParamSchema), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const { hash } = c.req.valid('param') + const strategy = c.get('authStrategy') - const ultimateOwner = await lookupUltimateOwner(owner) - // Check that the user making the request is the ultimate owner (i.e., - // that they have permission to delete this file) - if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { - throw new HTTPException(401, { message: 'Invalid shelter auth' }) - } - break - } - case 'chel-bearer': { - const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) - if (!expectedTokenDgst) { - throw new HTTPException(404) + const credentials = c.get('credentials') as AuthCredentials + switch (strategy) { + case 'chel-shelter': { + const owner = await sbp('chelonia.db/get', `_private_owner_${hash}`) + if (!owner) { + throw new HTTPException(404) + } + + const ultimateOwner = await lookupUltimateOwner(owner) + // Check that the user making the request is the ultimate owner (i.e., + // that they have permission to delete this file) + if (!ctEq(credentials.billableContractID as string, ultimateOwner)) { + throw new HTTPException(401, { message: 'Invalid shelter auth' }) + } + break } - const tokenDgst = blake32Hash(credentials.token as string) - // Constant-time comparison - // Check that the token provided matches the deletion token for this contract - if (!ctEq(expectedTokenDgst, tokenDgst)) { - throw new HTTPException(401, { message: 'Invalid token' }) + case 'chel-bearer': { + const expectedTokenDgst = await sbp('chelonia.db/get', `_private_deletionTokenDgst_${hash}`) + if (!expectedTokenDgst) { + throw new HTTPException(404) + } + const tokenDgst = blake32Hash(credentials.token as string) + // Constant-time comparison + // Check that the token provided matches the deletion token for this contract + if (!ctEq(expectedTokenDgst, tokenDgst)) { + throw new HTTPException(401, { message: 'Invalid token' }) + } + break } - break + default: + throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) } - default: - throw new HTTPException(401, { message: 'Missing or invalid auth strategy' }) - } - const username = await sbp('chelonia.db/get', `_private_cid2name_${hash}`) - // Authentication passed, now proceed to delete the contract and its associated - // keys - try { - const [id] = sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', hash, null, true]) - if (username) { - const ip = getClientIP(c) - console.info({ contractID: hash, username, ip, taskId: id }, 'Scheduled deletion on named contract') + const username = await sbp('chelonia.db/get', `_private_cid2name_${hash}`) + // Authentication passed, now proceed to delete the contract and its associated + // keys + try { + const [id] = sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', hash, null, true]) + if (username) { + const ip = getClientIP(c) + console.info({ contractID: hash, username, ip, taskId: id }, 'Scheduled deletion on named contract') + } + // We return the queue ID to allow users to track progress + // TODO: Tracking progress not yet implemented + return c.json({ id }, 202) + } catch (e) { + errorMapper(e as Error) } - // We return the queue ID to allow users to track progress - // TODO: Tracking progress not yet implemented - return c.json({ id }, 202) - } catch (e) { - errorMapper(e as Error) - } - }) - -app.post('/kv/:contractID/:key', - bodyLimit({ maxSize: 6 * MEGABYTE }), - authMiddleware('chel-shelter', 'required'), - zValidator('param', kvParamSchema), - async function (c) { - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const { contractID, key } = c.req.valid('param') + }) - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400) - } + app.post('/kv/:contractID/:key', + bodyLimit({ maxSize: 6 * MEGABYTE }), + authMiddleware('chel-shelter', 'required'), + zValidator('param', kvParamSchema), + async function (c) { + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + const { contractID, key } = c.req.valid('param') - const credentials = c.get('credentials') as AuthCredentials - if (!ctEq(credentials.billableContractID as string, contractID)) { - throw new HTTPException(401) - } + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } - const payloadBuffer = Buffer.from(await c.req.arrayBuffer()) + const credentials = c.get('credentials') as AuthCredentials + if (!ctEq(credentials.billableContractID as string, contractID)) { + throw new HTTPException(401) + } - // Use a queue to prevent race conditions (for example, writing to a contract - // that's being deleted or updated) - return sbp('chelonia/queueInvocation', contractID, async () => { - const existing = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) + const payloadBuffer = Buffer.from(await c.req.arrayBuffer()) - // Some protection against accidental overwriting by implementing the if-match - // header - const expectedEtag = c.req.header('if-match') - if (!expectedEtag) { - throw new HTTPException(400, { message: 'if-match is required' }) - } - // "Quote" string (to match ETag format) - const cid = existing ? createCID(existing, multicodes.RAW) : '' + // Use a queue to prevent race conditions (for example, writing to a contract + // that's being deleted or updated) + return sbp('chelonia/queueInvocation', contractID, async () => { + const existing = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) - if (expectedEtag === '*') { - // pass through - } else { - if (!expectedEtag.split(',').map((v: string) => v.trim()).includes(`"${cid}"`)) { - return new Response(existing || '', { - status: 412, - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"` - } - }) + // Some protection against accidental overwriting by implementing the if-match + // header + const expectedEtag = c.req.header('if-match') + if (!expectedEtag) { + throw new HTTPException(400, { message: 'if-match is required' }) + } + // "Quote" string (to match ETag format) + const cid = existing ? createCID(existing, multicodes.RAW) : '' + + if (expectedEtag === '*') { + // pass through + } else { + if (!expectedEtag.split(',').map((v: string) => v.trim()).includes(`"${cid}"`)) { + return new Response(existing || '', { + status: 412, + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` + } + }) + } } - } - try { - const serializedData = JSON.parse(payloadBuffer.toString()) - const { contracts } = sbp('chelonia/rootState') - // Check that the height is the latest value - if (contracts[contractID].height !== Number(serializedData.height)) { - return new Response(existing || '', { - status: 409, - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"` - } + try { + const serializedData = JSON.parse(payloadBuffer.toString()) + const { contracts } = sbp('chelonia/rootState') + // Check that the height is the latest value + if (contracts[contractID].height !== Number(serializedData.height)) { + return new Response(existing || '', { + status: 409, + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` + } + }) + } + // Check that the signature is valid + sbp('chelonia/parseEncryptedOrUnencryptedDetachedMessage', { + contractID, + serializedData, + meta: key }) + } catch (parseErr) { + if (parseErr instanceof Response) throw parseErr + throw new HTTPException(422) } - // Check that the signature is valid - sbp('chelonia/parseEncryptedOrUnencryptedDetachedMessage', { - contractID, - serializedData, - meta: key - }) - } catch (parseErr) { - if (parseErr instanceof Response) throw parseErr - throw new HTTPException(422) - } - const existingSize = existing ? Buffer.from(existing).byteLength : 0 - await sbp('chelonia.db/set', `_private_kv_${contractID}_${key}`, payloadBuffer) - await sbp('backend/server/updateSize', contractID, payloadBuffer.byteLength - existingSize) - await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key) - // No await on broadcast for faster responses - sbp('backend/server/broadcastKV', contractID, key, payloadBuffer.toString()).catch((e: Error) => console.error(e, 'Error broadcasting KV update', contractID, key)) + const existingSize = existing ? Buffer.from(existing).byteLength : 0 + await sbp('chelonia.db/set', `_private_kv_${contractID}_${key}`, payloadBuffer) + await sbp('backend/server/updateSize', contractID, payloadBuffer.byteLength - existingSize) + await appendToIndexFactory(`_private_kvIdx_${contractID}`)(key) + // No await on broadcast for faster responses + sbp('backend/server/broadcastKV', contractID, key, payloadBuffer.toString()).catch((e: Error) => console.error(e, 'Error broadcasting KV update', contractID, key)) - return c.body(null, 204) + return c.body(null, 204) + }) }) - }) -app.get('/kv/:contractID/:key', - authMiddleware('chel-shelter', 'required'), - zValidator('param', kvParamSchema), - async function (c) { - const { contractID, key } = c.req.valid('param') + app.get('/kv/:contractID/:key', + authMiddleware('chel-shelter', 'required'), + zValidator('param', kvParamSchema), + async function (c) { + const { contractID, key } = c.req.valid('param') - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { - throw new HTTPException(400) - } - - const credentials = c.get('credentials') as AuthCredentials - if (!ctEq(credentials.billableContractID as string, contractID)) { - throw new HTTPException(401) - } + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { + throw new HTTPException(400) + } - const result = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) - if (!result) { - return notFoundNoCache(c) - } + const credentials = c.get('credentials') as AuthCredentials + if (!ctEq(credentials.billableContractID as string, contractID)) { + throw new HTTPException(401) + } - const cid = createCID(result, multicodes.RAW) - return new Response(result, { - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"`, - 'Cache-Control': 'no-store' + const result = await sbp('chelonia.db/get', `_private_kv_${contractID}_${key}`) + if (!result) { + return notFoundNoCache(c) } + + const cid = createCID(result, multicodes.RAW) + return new Response(result, { + headers: { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"`, + 'Cache-Control': 'no-store' + } + }) }) - }) -app.get('/serverMessages', function (c) { - const messages = nconf.get('server:messages') - if (!messages) return c.json([]) - return c.json(messages, 200, { 'Cache-Control': 'no-store' }) -}) + app.get('/serverMessages', function (c) { + const messages = nconf.get('server:messages') + if (!messages) return c.json([]) + return c.json(messages, 200, { 'Cache-Control': 'no-store' }) + }) -// SPA routes + // SPA routes -app.get('/assets/:subpath{.+}', async function (c) { - const subpath = c.req.param('subpath') - return serveAsset(c, subpath, staticServeConfig.distAssets) -}) - -// Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) -if (isCheloniaDashboard) { - app.get('/dashboard/assets/:subpath{.+}', async function (c) { + app.get('/assets/:subpath{.+}', async function (c) { const subpath = c.req.param('subpath') return serveAsset(c, subpath, staticServeConfig.distAssets) }) -} -// SPA catch-all route -app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', async function (c) { - try { - const file = await Deno.readFile(staticServeConfig.distIndexHtml) - return c.body(file, 200, { 'Content-Type': 'text/html' }) - } catch { - return notFoundNoCache(c) + // Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) + if (isCheloniaDashboard) { + app.get('/dashboard/assets/:subpath{.+}', async function (c) { + const subpath = c.req.param('subpath') + return serveAsset(c, subpath, staticServeConfig.distAssets) + }) } -}) -app.get('/', function (c) { - return c.redirect(staticServeConfig.redirect) -}) + // SPA catch-all route + app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', async function (c) { + try { + const file = await Deno.readFile(staticServeConfig.distIndexHtml) + return c.body(file, 200, { 'Content-Type': 'text/html' }) + } catch { + return notFoundNoCache(c) + } + }) -app.post('/zkpp/register/:name', - zValidator('param', nameParamSchema), - zValidatorFormOrJson(zkppRegisterBodySchema), - async function (c) { - const { name } = c.req.valid('param') - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + app.get('/', function (c) { + return c.redirect(staticServeConfig.redirect) + }) - const payload = c.get('validatedBody') as z.infer + app.post('/zkpp/register/:name', + zValidator('param', nameParamSchema), + zValidatorFormOrJson(zkppRegisterBodySchema), + async function (c) { + const { name } = c.req.valid('param') + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - const lookupResult = await sbp('backend/db/lookupName', name) - if (lookupResult) { + const payload = c.get('validatedBody') as z.infer + + const lookupResult = await sbp('backend/db/lookupName', name) + if (lookupResult) { // If the username is already registered, abort - throw new HTTPException(409) - } - try { - if ('b' in payload) { - const result = registrationKey(name, payload.b) + throw new HTTPException(409) + } + try { + if ('b' in payload) { + const result = registrationKey(name, payload.b) - if (result) { - return c.json(result) - } - } else { - const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) + if (result) { + return c.json(result) + } + } else { + const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) - if (result) { - return c.json(result) + if (result) { + return c.json(result) + } } + } catch (e) { + if (e instanceof HTTPException) throw e + ;(e as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at POST /zkpp/register/:name: ' + (e as Error).message) } - } catch (e) { - if (e instanceof HTTPException) throw e - ;(e as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at POST /zkpp/register/:name: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) - }) + throw new HTTPException(500, { message: 'internal error' }) + }) -app.get('/zkpp/:contractID/auth_hash', - zValidator('param', zkppContractParamSchema), - zValidator('query', zkppAuthHashQuerySchema), - async function (c) { - const { contractID } = c.req.valid('param') - const { b } = c.req.valid('query') - try { - const challenge = await getChallenge(contractID, b) + app.get('/zkpp/:contractID/auth_hash', + zValidator('param', zkppContractParamSchema), + zValidator('query', zkppAuthHashQuerySchema), + async function (c) { + const { contractID } = c.req.valid('param') + const { b } = c.req.valid('query') + try { + const challenge = await getChallenge(contractID, b) - return challenge ? c.json(challenge) : notFoundNoCache(c) - } catch (e) { - ;(e as unknown as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at GET /zkpp/{contractID}/auth_hash: ' + (e as Error).message) - } + return challenge ? c.json(challenge) : notFoundNoCache(c) + } catch (e) { + ;(e as unknown as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at GET /zkpp/{contractID}/auth_hash: ' + (e as Error).message) + } - throw new HTTPException(500, { message: 'internal error' }) - }) + throw new HTTPException(500, { message: 'internal error' }) + }) -app.get('/zkpp/:contractID/contract_hash', - zValidator('param', zkppContractParamSchema), - zValidator('query', zkppContractHashQuerySchema), - async function (c) { - const { contractID } = c.req.valid('param') - const { r, s, sig, hc } = c.req.valid('query') - try { - const salt = await getContractSalt(contractID, r, s, sig, hc) + app.get('/zkpp/:contractID/contract_hash', + zValidator('param', zkppContractParamSchema), + zValidator('query', zkppContractHashQuerySchema), + async function (c) { + const { contractID } = c.req.valid('param') + const { r, s, sig, hc } = c.req.valid('query') + try { + const salt = await getContractSalt(contractID, r, s, sig, hc) - if (salt) { - return c.json(salt) + if (salt) { + return c.json(salt) + } + } catch (e) { + ;(e as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at GET /zkpp/{contractID}/contract_hash: ' + (e as Error).message) } - } catch (e) { - ;(e as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at GET /zkpp/{contractID}/contract_hash: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) - }) + throw new HTTPException(500, { message: 'internal error' }) + }) -app.post('/zkpp/:contractID/updatePasswordHash', - zValidator('param', zkppContractParamSchema), - zValidator('json', zkppUpdatePasswordBodySchema), - async function (c) { - const { contractID } = c.req.valid('param') - if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) - try { - const payload = c.req.valid('json') - const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) + app.post('/zkpp/:contractID/updatePasswordHash', + zValidator('param', zkppContractParamSchema), + zValidator('json', zkppUpdatePasswordBodySchema), + async function (c) { + const { contractID } = c.req.valid('param') + if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) + try { + const payload = c.req.valid('json') + const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) - if (result) { - return c.json(result) + if (result) { + return c.json(result) + } + } catch (e) { + if (e instanceof HTTPException) throw e + ;(e as unknown as { ip: string }).ip = getClientIP(c) + console.error(e, 'Error at POST /zkpp/{contractID}/updatePasswordHash: ' + (e as Error).message) } - } catch (e) { - if (e instanceof HTTPException) throw e - ;(e as unknown as { ip: string }).ip = getClientIP(c) - console.error(e, 'Error at POST /zkpp/{contractID}/updatePasswordHash: ' + (e as Error).message) - } - throw new HTTPException(500, { message: 'internal error' }) - }) + throw new HTTPException(500, { message: 'internal error' }) + }) +} diff --git a/src/serve/server.ts b/src/serve/server.ts index ac2db15..060e2e0 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -15,8 +15,9 @@ import type { ImportMeta } from '../types/build.d.ts' import createWorker from './createWorker.ts' import { join } from 'node:path' import process from 'node:process' +import { registerRoutes } from './routes.ts' import { CREDITS_WORKER_TASK_TIME_INTERVAL, OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL } from './constants.ts' -import { KEYOP_SEGMENT_LENGTH, appendToIndexFactory, initDB, lookupUltimateOwner, removeFromIndexFactory, updateSize } from './database.ts' +import { KEYOP_SEGMENT_LENGTH, appendToIndexFactory, closeDB, initDB, lookupUltimateOwner, removeFromIndexFactory, updateSize } from './database.ts' import { BackendErrorBadData, BackendErrorGone, BackendErrorNotFound } from './errors.ts' import { SERVER_RUNNING } from './events.ts' import { PUBSUB_INSTANCE, SERVER_INSTANCE } from './instance-keys.ts' @@ -35,492 +36,518 @@ import { pathToFileURL } from 'node:url' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' -const cheloniaAppManifest = await (async () => { - const appDir = nconf.get('server:appDir') || process.cwd() - try { - return (await import(pathToFileURL(join(appDir, 'chelonia.json')).toString(), { - with: { type: 'json' } - })).default - } catch { - console.warn('`chelonia.json` unparsable or not found. Version information will be unavailable.') - } -})() - -const ARCHIVE_MODE = nconf.get('server:archiveMode') - -if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { - process.stderr.write('The size calculation worker must run more frequently than the credits worker for accurate billing') - process.exit(1) -} - -// Initialize workers for size calculation and credits processing -const ownerSizeTotalWorker = ARCHIVE_MODE || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL - ? undefined - : createWorker((import.meta as ImportMeta).ownerSizeTotalWorker || './ownerSizeTotalWorker.ts') -const creditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL - ? undefined - : createWorker((import.meta as ImportMeta).creditsWorker || './creditsWorker.ts') - -// Create Hono app -export const app = new Hono() - -// Global middleware: CORS -app.use('*', cors({ origin: '*' })) - -// Global middleware: X-Frame-Options on every response -app.use('*', async (c, next) => { - await next() - c.header('X-Frame-Options', 'DENY') -}) - -// Dev logging middleware -if (process.env.NODE_ENV === 'development' && !process.env.CI) { - app.use('*', async (c, next) => { - await next() - const ip = c.req.header('x-real-ip') || 'unknown' - console.debug(chalk`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`) - }) -} - -// Create the Node http.Server (without listening yet) via @hono/node-server -const httpServer = createAdaptorServer({ fetch: app.fetch }) as Server - +// ============================================================================ +// Module-scope state for the current server run +// ============================================================================ +let currentApp: Hono | null = null +let currentHttpServer: Server | null = null +let currentOwnerSizeTotalWorker: ReturnType | undefined = undefined +let currentCreditsWorker: ReturnType | undefined = undefined +let currentManifest: Record | undefined = undefined +let currentPushHeartbeatIntervalID: ReturnType | undefined = undefined + +// Helper for appending to orphaned names index (stateless) const appendToOrphanedNamesIndex = appendToIndexFactory('_private_orphaned_names_index') -sbp('okTurtles.data/set', SERVER_INSTANCE, app) - -sbp('sbp/selectors/register', { - 'backend/server/persistState': async function (deserializedHEAD: unknown) { - const contractID = (deserializedHEAD as Record).contractID - const cheloniaState = sbp('chelonia/rootState') - // If the contract has been removed or the height hasn't been updated, - // there's nothing to persist. - // If `!cheloniaState.contracts[contractID]`, the contract's been removed - // and therefore we shouldn't save it. - // If `cheloniaState.contracts[contractID].height < deserializedHEAD.head.height`, - // it means that the message wasn't processed (we'd expect the height to - // be `>=` than the message's height if so), and therefore we also shouldn't - // save it. - if (!cheloniaState.contracts[contractID as string] || cheloniaState.contracts[contractID as string].height < (((deserializedHEAD as Record).head as Record).height as number)) { - return - } - // If the current HEAD is not what we expect, don't save (the state could - // have been updated by a later message). This ensures that we save the - // latest state and also reduces the number of write operations - if (cheloniaState.contracts[contractID as string].HEAD === (deserializedHEAD as Record).hash) { - // Extract the parts of the state relevant to this contract - const state = { - contractState: (cheloniaState as Record)[contractID as string], - cheloniaContractInfo: cheloniaState.contracts[contractID as string] +// ============================================================================ +// SBP selector registration (once per process) +// ============================================================================ +let serverSelectorsInstalled = false + +function installServerSelectorsOnce (): void { + if (serverSelectorsInstalled) return + serverSelectorsInstalled = true + + sbp('sbp/selectors/register', { + 'backend/server/persistState': async function (deserializedHEAD: unknown) { + const contractID = (deserializedHEAD as Record).contractID + const cheloniaState = sbp('chelonia/rootState') + // If the contract has been removed or the height hasn't been updated, + // there's nothing to persist. + // If `!cheloniaState.contracts[contractID]`, the contract's been removed + // and therefore we shouldn't save it. + // If `cheloniaState.contracts[contractID].height < deserializedHEAD.head.height`, + // it means that the message wasn't processed (we'd expect the height to + // be `>=` than the message's height if so), and therefore we also shouldn't + // save it. + if (!cheloniaState.contracts[contractID as string] || cheloniaState.contracts[contractID as string].height < (((deserializedHEAD as Record).head as Record).height as number)) { + return } - // Save the state under a 'contract partition' key, so that updating a - // contract doesn't require saving the entire state. - // Although it's not important for the server right now, this will fail to - // persist changes to the state for other contracts. - // For example, when watching foreign keys, this happens: whenever a - // foreign key for contract A is added to contract B, the private state - // for both contract A and B is updated (when both contracts are being - // monitored by Chelonia). However, here in this case, the updated state - // for contract A will not be saved immediately here, and it will only be - // saved if some other event happens later on contract A. - // TODO: If, in the future, processing a message affects other contracts - // in a way that is meaningful to the server, there'll need to be a way - // to detect these changes as well. One example could be, expanding on the - // previous scenario, if we decide that the server should enforce key - // rotations, so that updating a foreign key 'locks' that contract until - // the foreign key is rotated or deleted. For this to work reliably, we'd - // need to ensure that the state for both contract B and contract A are - // saved when the foreign key gets added to contract B. - await sbp('chelonia.db/set', '_private_cheloniaState_' + contractID, JSON.stringify(state)) - } - // If this is a new contract, we also need to add it to the index, which - // is used when starting up the server to know which keys to fetch. - // In the future, consider having a multi-level index, since the index can - // get pretty large. - if (contractID === (deserializedHEAD as Record).hash) { - // We want to ensure that the index is updated atomically (i.e., if there - // are multiple new contracts, all of them should be added), so a queue - // is needed for the load & store operation. - await sbp('backend/server/appendToContractIndex', contractID) - } - // If this was a key op, add it to a keyop index. To prevent the index from - // growing too large, the index is segmented for every KEYOP_SEGMENT_LENGTH - // height values - if (cheloniaState.contracts[contractID as string].previousKeyOp === (deserializedHEAD as Record).hash) { - await appendToIndexFactory(`_private_keyop_idx_${contractID}_${(((deserializedHEAD as Record).head as Record).height as number) - (((deserializedHEAD as Record).head as Record).height as number) % KEYOP_SEGMENT_LENGTH}`)(String(((deserializedHEAD as Record).head as Record).height)) - } - }, - 'backend/server/appendToContractIndex': appendToIndexFactory('_private_cheloniaState_index'), - 'backend/server/broadcastKV': async function (contractID: string, key: string, entry: string) { - const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS - const pubsubMessage = createKvMessage(contractID, key, entry) - const subscribers = pubsub.enumerateSubscribers(contractID, key) - console.debug(chalk.blue.bold(`[pubsub] Broadcasting KV change on ${contractID} to key ${key}`)) - await pubsub.broadcast(pubsubMessage, { to: subscribers, wsOnly: true }) - }, - 'backend/server/broadcastEntry': async function (deserializedHEAD: ReturnType, entry: string) { - const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS - const contractID = deserializedHEAD.contractID - const contractType = sbp('chelonia/rootState').contracts[contractID as string]?.type - const pubsubMessage = createMessage(NOTIFICATION_TYPE.ENTRY, entry, { contractID, contractType }) - const subscribers = pubsub.enumerateSubscribers(contractID) - console.debug(chalk.blue.bold(`[pubsub] Broadcasting ${deserializedHEAD.description()}`)) - await pubsub.broadcast(pubsubMessage, { to: subscribers }) - }, - 'backend/server/broadcastDeletion': async function (contractID: string) { - const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS - const pubsubMessage = createMessage(NOTIFICATION_TYPE.DELETION, contractID) - const subscribers = pubsub.enumerateSubscribers(contractID) - console.debug(chalk.blue.bold(`[pubsub] Broadcasting deletion of ${contractID}`)) - await pubsub.broadcast(pubsubMessage, { to: subscribers }) - }, - 'backend/server/handleEntry': async function (deserializedHEAD: ReturnType, entry: string) { - const contractID = deserializedHEAD.contractID - if (deserializedHEAD.head.op === SPMessage.OP_CONTRACT) { - sbp('okTurtles.data/get', PUBSUB_INSTANCE).channels.add(contractID) - } - await sbp('chelonia/private/in/enqueueHandleEvent', contractID, entry) - // Persist the Chelonia state after processing a message - await sbp('backend/server/persistState', deserializedHEAD, entry) - // No await on broadcast for faster responses - sbp('backend/server/broadcastEntry', deserializedHEAD, entry).catch((e: unknown) => console.error(e, 'Error broadcasting entry', contractID, deserializedHEAD.hash)) - }, - 'backend/server/saveOwner': async function (ownerID: string, resourceID: string) { - // Store the owner for the current resource - // Use a queue to check that the owner exists, preventing the creation of - // orphaned resources (e.g., because the owner was just deleted) - await sbp('chelonia/queueInvocation', ownerID, async () => { - const owner = await sbp('chelonia.db/get', ownerID) - if (!owner) { - throw new Error('Owner resource does not exist') + // If the current HEAD is not what we expect, don't save (the state could + // have been updated by a later message). This ensures that we save the + // latest state and also reduces the number of write operations + if (cheloniaState.contracts[contractID as string].HEAD === (deserializedHEAD as Record).hash) { + // Extract the parts of the state relevant to this contract + const state = { + contractState: (cheloniaState as Record)[contractID as string], + cheloniaContractInfo: cheloniaState.contracts[contractID as string] + } + // Save the state under a 'contract partition' key, so that updating a + // contract doesn't require saving the entire state. + // Although it's not important for the server right now, this will fail to + // persist changes to the state for other contracts. + // For example, when watching foreign keys, this happens: whenever a + // foreign key for contract A is added to contract B, the private state + // for both contract A and B is updated (when both contracts are being + // monitored by Chelonia). However, here in this case, the updated state + // for contract A will not be saved immediately here, and it will only be + // saved if some other event happens later on contract A. + // TODO: If, in the future, processing a message affects other contracts + // in a way that is meaningful to the server, there'll need to be a way + // to detect these changes as well. One example could be, expanding on the + // previous scenario, if we decide that the server should enforce key + // rotations, so that updating a foreign key 'locks' that contract until + // the foreign key is rotated or deleted. For this to work reliably, we'd + // need to ensure that the state for both contract B and contract A are + // saved when the foreign key gets added to contract B. + await sbp('chelonia.db/set', '_private_cheloniaState_' + contractID, JSON.stringify(state)) } - await sbp('chelonia.db/set', `_private_owner_${resourceID}`, ownerID) - const resourcesKey = `_private_resources_${ownerID}` - // Store the resource in the resource index key - // This is done in a queue to handle several simultaneous requests - // reading and writing to the same key - await appendToIndexFactory(resourcesKey)(resourceID) - // Done as a persistent action to return quickly. If one of the owners - // up the chain has many resources, the operation could take a while. - sbp('chelonia.persistentActions/enqueue', ['backend/server/addToIndirectResourcesIndex', resourceID]) - }) - }, - 'backend/server/addToIndirectResourcesIndex': async function (resourceID: string) { - const ownerID = await sbp('chelonia.db/get', `_private_owner_${resourceID}`) - let indirectOwnerID = ownerID - // If the owner of the owner doesn't exist, there are no indirect resources. - while ((indirectOwnerID = await sbp('chelonia.db/get', `_private_owner_${indirectOwnerID}`))) { - await appendToIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(resourceID) - } - }, - 'backend/server/removeFromIndirectResourcesIndex': async function (resourceID: string) { - const ownerID = await sbp('chelonia.db/get', `_private_owner_${resourceID}`) - const resources = await sbp('chelonia.db/get', `_private_resources_${resourceID}`) - const indirectResources = resources ? await sbp('chelonia.db/get', `_private_indirectResources_${resourceID}`) : undefined - const allSubresources = [ - resourceID, - ...(resources ? resources.split('\x00') : []), - ...(indirectResources ? indirectResources.split('\x00') : []) - ] - let indirectOwnerID = ownerID - while ((indirectOwnerID = await sbp('chelonia.db/get', `_private_owner_${indirectOwnerID}`))) { - await removeFromIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(allSubresources) - } - }, - 'backend/server/registerBillableEntity': appendToIndexFactory('_private_billable_entities'), - 'backend/server/updateSize': function (resourceID: string, size: number, ultimateOwnerID: string | null | undefined) { - const sizeKey = `_private_size_${resourceID}` - return updateSize(resourceID, sizeKey, size).then(() => { - // Because this is relevant key for size accounting, call updateSizeSideEffects - return ownerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID, size, ultimateOwnerID }) - }) - }, - 'backend/server/updateContractFilesTotalSize': function (resourceID: string, size: number) { - const sizeKey = `_private_contractFilesTotalSize_${resourceID}` - return updateSize(resourceID, sizeKey, size, true) - }, - 'backend/server/stop': async function () { - clearInterval(pushHeartbeatIntervalID) - if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { - await sbp('backend/server/stopRateLimiters') - } - await new Promise((resolve, reject) => { - httpServer.close((err) => { - if (err) { - reject(err) - } else { - resolve() + // If this is a new contract, we also need to add it to the index, which + // is used when starting up the server to know which keys to fetch. + // In the future, consider having a multi-level index, since the index can + // get pretty large. + if (contractID === (deserializedHEAD as Record).hash) { + // We want to ensure that the index is updated atomically (i.e., if there + // are multiple new contracts, all of them should be added), so a queue + // is needed for the load & store operation. + await sbp('backend/server/appendToContractIndex', contractID) + } + // If this was a key op, add it to a keyop index. To prevent the index from + // growing too large, the index is segmented for every KEYOP_SEGMENT_LENGTH + // height values + if (cheloniaState.contracts[contractID as string].previousKeyOp === (deserializedHEAD as Record).hash) { + await appendToIndexFactory(`_private_keyop_idx_${contractID}_${(((deserializedHEAD as Record).head as Record).height as number) - (((deserializedHEAD as Record).head as Record).height as number) % KEYOP_SEGMENT_LENGTH}`)(String(((deserializedHEAD as Record).head as Record).height)) + } + }, + 'backend/server/appendToContractIndex': appendToIndexFactory('_private_cheloniaState_index'), + 'backend/server/broadcastKV': async function (contractID: string, key: string, entry: string) { + const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS + const pubsubMessage = createKvMessage(contractID, key, entry) + const subscribers = pubsub.enumerateSubscribers(contractID, key) + console.debug(chalk.blue.bold(`[pubsub] Broadcasting KV change on ${contractID} to key ${key}`)) + await pubsub.broadcast(pubsubMessage, { to: subscribers, wsOnly: true }) + }, + 'backend/server/broadcastEntry': async function (deserializedHEAD: ReturnType, entry: string) { + const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS + const contractID = deserializedHEAD.contractID + const contractType = sbp('chelonia/rootState').contracts[contractID as string]?.type + const pubsubMessage = createMessage(NOTIFICATION_TYPE.ENTRY, entry, { contractID, contractType }) + const subscribers = pubsub.enumerateSubscribers(contractID) + console.debug(chalk.blue.bold(`[pubsub] Broadcasting ${deserializedHEAD.description()}`)) + await pubsub.broadcast(pubsubMessage, { to: subscribers }) + }, + 'backend/server/broadcastDeletion': async function (contractID: string) { + const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS + const pubsubMessage = createMessage(NOTIFICATION_TYPE.DELETION, contractID) + const subscribers = pubsub.enumerateSubscribers(contractID) + console.debug(chalk.blue.bold(`[pubsub] Broadcasting deletion of ${contractID}`)) + await pubsub.broadcast(pubsubMessage, { to: subscribers }) + }, + 'backend/server/handleEntry': async function (deserializedHEAD: ReturnType, entry: string) { + const contractID = deserializedHEAD.contractID + if (deserializedHEAD.head.op === SPMessage.OP_CONTRACT) { + sbp('okTurtles.data/get', PUBSUB_INSTANCE).channels.add(contractID) + } + await sbp('chelonia/private/in/enqueueHandleEvent', contractID, entry) + // Persist the Chelonia state after processing a message + await sbp('backend/server/persistState', deserializedHEAD, entry) + // No await on broadcast for faster responses + sbp('backend/server/broadcastEntry', deserializedHEAD, entry).catch((e: unknown) => console.error(e, 'Error broadcasting entry', contractID, deserializedHEAD.hash)) + }, + 'backend/server/saveOwner': async function (ownerID: string, resourceID: string) { + // Store the owner for the current resource + // Use a queue to check that the owner exists, preventing the creation of + // orphaned resources (e.g., because the owner was just deleted) + await sbp('chelonia/queueInvocation', ownerID, async () => { + const owner = await sbp('chelonia.db/get', ownerID) + if (!owner) { + throw new Error('Owner resource does not exist') } + await sbp('chelonia.db/set', `_private_owner_${resourceID}`, ownerID) + const resourcesKey = `_private_resources_${ownerID}` + // Store the resource in the resource index key + // This is done in a queue to handle several simultaneous requests + // reading and writing to the same key + await appendToIndexFactory(resourcesKey)(resourceID) + // Done as a persistent action to return quickly. If one of the owners + // up the chain has many resources, the operation could take a while. + sbp('chelonia.persistentActions/enqueue', ['backend/server/addToIndirectResourcesIndex', resourceID]) }) - }) - await Promise.all([ - ownerSizeTotalWorker?.terminate(), - creditsWorker?.terminate() - ]) - }, - async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { - const owner = await sbp('chelonia.db/get', `_private_owner_${cid}`) - const rawManifest = await sbp('chelonia.db/get', cid) - const size = await sbp('chelonia.db/get', `_private_size_${cid}`) - if (owner && !ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(owner) - // If running in a persistent queue, already deleted contract should not - // result in an error, because exceptions will result in the task being - // re-attempted - if (rawManifest === '') { if (skipIfDeleted) return; throw new BackendErrorGone() } - if (!rawManifest) { if (skipIfDeleted) return; throw new BackendErrorNotFound() } - - try { - const manifest = JSON.parse(rawManifest) - if (!manifest || typeof manifest !== 'object') throw new BackendErrorBadData('manifest format is invalid') - if (manifest.version !== '1.0.0') throw new BackendErrorBadData('unsupported manifest version') - if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new BackendErrorBadData('missing chunks') - // Delete all chunks - await Promise.all(manifest.chunks.map(([, cid]: [unknown, string]) => sbp('chelonia.db/delete', cid))) - } catch (e: unknown) { - console.warn(e, `Error parsing manifest for ${cid}. It's probably not a file manifest.`) - throw new BackendErrorNotFound() - } - // The keys to be deleted are not read from or updated, so they can be deleted - // without using a queue - const resourcesKey = `_private_resources_${owner}` - await removeFromIndexFactory(resourcesKey)(cid) - await sbp('backend/server/removeFromIndirectResourcesIndex', cid) - - await sbp('chelonia.db/delete', `_private_owner_${cid}`) - await sbp('chelonia.db/delete', `_private_size_${cid}`) - await sbp('chelonia.db/delete', `_private_deletionTokenDgst_${cid}`) - - await sbp('chelonia.db/set', cid, '') - await sbp('backend/server/updateContractFilesTotalSize', owner, -Number(size)) - - if (ultimateOwnerID && size) { - await ownerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID: cid, size: -parseInt(size), ultimateOwnerID }) - } - }, - async 'backend/deleteContract' (cid: string, ultimateOwnerID?: string | null, skipIfDeleted?: boolean | null): Promise { - let contractsPendingDeletion = sbp('okTurtles.data/get', 'contractsPendingDeletion') - if (!contractsPendingDeletion) { - contractsPendingDeletion = new Set() - sbp('okTurtles.data/set', 'contractsPendingDeletion', contractsPendingDeletion) - } - // Avoid deadlocks due to loops - if (contractsPendingDeletion.has(cid)) { - return - } - contractsPendingDeletion.add(cid) - - return await sbp('chelonia/queueInvocation', cid, async () => { + }, + 'backend/server/addToIndirectResourcesIndex': async function (resourceID: string) { + const ownerID = await sbp('chelonia.db/get', `_private_owner_${resourceID}`) + let indirectOwnerID = ownerID + // If the owner of the owner doesn't exist, there are no indirect resources. + while ((indirectOwnerID = await sbp('chelonia.db/get', `_private_owner_${indirectOwnerID}`))) { + await appendToIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(resourceID) + } + }, + 'backend/server/removeFromIndirectResourcesIndex': async function (resourceID: string) { + const ownerID = await sbp('chelonia.db/get', `_private_owner_${resourceID}`) + const resources = await sbp('chelonia.db/get', `_private_resources_${resourceID}`) + const indirectResources = resources ? await sbp('chelonia.db/get', `_private_indirectResources_${resourceID}`) : undefined + const allSubresources = [ + resourceID, + ...(resources ? resources.split('\x00') : []), + ...(indirectResources ? indirectResources.split('\x00') : []) + ] + let indirectOwnerID = ownerID + while ((indirectOwnerID = await sbp('chelonia.db/get', `_private_owner_${indirectOwnerID}`))) { + await removeFromIndexFactory(`_private_indirectResources_${indirectOwnerID}`)(allSubresources) + } + }, + 'backend/server/registerBillableEntity': appendToIndexFactory('_private_billable_entities'), + 'backend/server/updateSize': function (resourceID: string, size: number, ultimateOwnerID: string | null | undefined) { + const sizeKey = `_private_size_${resourceID}` + return updateSize(resourceID, sizeKey, size).then(() => { + // Because this is relevant key for size accounting, call updateSizeSideEffects + return currentOwnerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID, size, ultimateOwnerID }) + }) + }, + 'backend/server/updateContractFilesTotalSize': function (resourceID: string, size: number) { + const sizeKey = `_private_contractFilesTotalSize_${resourceID}` + return updateSize(resourceID, sizeKey, size, true) + }, + 'backend/server/stop': async function () { + await stopServer() + }, + async 'backend/deleteFile' (cid: string, ultimateOwnerID: string | null | undefined, skipIfDeleted: boolean | null | undefined): Promise { const owner = await sbp('chelonia.db/get', `_private_owner_${cid}`) - if (!ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(cid) const rawManifest = await sbp('chelonia.db/get', cid) const size = await sbp('chelonia.db/get', `_private_size_${cid}`) + if (owner && !ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(owner) // If running in a persistent queue, already deleted contract should not // result in an error, because exceptions will result in the task being // re-attempted if (rawManifest === '') { if (skipIfDeleted) return; throw new BackendErrorGone() } if (!rawManifest) { if (skipIfDeleted) return; throw new BackendErrorNotFound() } - // Cascade delete all resources owned by this contract, such as files - // (attachments) and other contracts. Removing a single contract could - // therefore result in a large number of contracts being deleted. For - // example, in Group Income, deleting an identity contract will delete: - // - All groups created by that contract - // - This includes files like the group avatar - // - And also all chatrooms - // - And all attachments in chatrooms - // - All DMs created by that contract - // - And all attachments - const resourcesKey = `_private_resources_${cid}` - const resources = await sbp('chelonia.db/get', resourcesKey) - if (resources) { - await Promise.allSettled(resources.split('\x00').map((resourceCid: string) => { - const parsed = parseCID(resourceCid) - - if (parsed.code === multicodes.SHELTER_CONTRACT_DATA) { - return sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', resourceCid, ultimateOwnerID, true]) - } else if (parsed.code === multicodes.SHELTER_FILE_MANIFEST) { - return sbp('chelonia.persistentActions/enqueue', ['backend/deleteFile', resourceCid, ultimateOwnerID, true]) - } else { - console.warn({ cid, resourceCid, code: parsed.code }, 'Resource should be deleted but it is of an unknown type') - } - - return undefined - })) - } - await sbp('chelonia.db/delete', resourcesKey) - - // Next, loop through all the events, except the very first one, - // in the contract and delete them, starting with the most recent ones. - // If the deletion process is interrupted, parts of the contract will - // still be able to be synced, but won't be to write to it (due to - // latestHEADinfo not being deleted). - const latestHEADinfo = await sbp('chelonia/db/latestHEADinfo', cid) - if (latestHEADinfo) { - for (let i = latestHEADinfo.height; i > 0; i--) { - const eventKey = `_private_hidx=${cid}#${i}` - const event = await sbp('chelonia.db/get', eventKey) - if (event) { - await sbp('chelonia.db/delete', JSON.parse(event).hash) - await sbp('chelonia.db/delete', eventKey) - } - if (i % KEYOP_SEGMENT_LENGTH === 0) { - await sbp('chelonia.db/delete', `_private_keyop_idx_${cid}_${i}`) - } - } - await sbp('chelonia/db/deleteLatestHEADinfo', cid) - } - - // Then, delete all KV-store values associated with this contract - const kvIndexKey = `_private_kvIdx_${cid}` - const kvKeys = await sbp('chelonia.db/get', kvIndexKey) - if (kvKeys) { - await Promise.all(kvKeys.split('\x00').map((key: string) => { - return sbp('chelonia.db/delete', `_private_kv_${cid}_${key}`) - })) + try { + const manifest = JSON.parse(rawManifest) + if (!manifest || typeof manifest !== 'object') throw new BackendErrorBadData('manifest format is invalid') + if (manifest.version !== '1.0.0') throw new BackendErrorBadData('unsupported manifest version') + if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new BackendErrorBadData('missing chunks') + // Delete all chunks + await Promise.all(manifest.chunks.map(([, cid]: [unknown, string]) => sbp('chelonia.db/delete', cid))) + } catch (e: unknown) { + console.warn(e, `Error parsing manifest for ${cid}. It's probably not a file manifest.`) + throw new BackendErrorNotFound() } - await sbp('chelonia.db/delete', kvIndexKey) + // The keys to be deleted are not read from or updated, so they can be deleted + // without using a queue + const resourcesKey = `_private_resources_${owner}` + await removeFromIndexFactory(resourcesKey)(cid) await sbp('backend/server/removeFromIndirectResourcesIndex', cid) - await sbp('chelonia.db/delete', `_private_indirectResources_${cid}`) - - await sbp('chelonia.db/get', `_private_cid2name_${cid}`).then((name: unknown) => { - if (!name) return - return Promise.all([ - sbp('chelonia.db/delete', `_private_cid2name_${cid}`), - appendToOrphanedNamesIndex(name as string) - ]) - }) - await sbp('chelonia.db/delete', `_private_rid_${cid}`) + await sbp('chelonia.db/delete', `_private_owner_${cid}`) await sbp('chelonia.db/delete', `_private_size_${cid}`) - await sbp('chelonia.db/delete', `_private_contractFilesTotalSize_${cid}`) await sbp('chelonia.db/delete', `_private_deletionTokenDgst_${cid}`) - await removeFromIndexFactory(`_private_resources_${owner}`)(cid) - // Delete the first event and its associated keys. These were not deleted - // in the loop above that deletes events one by one. - await sbp('chelonia.db/delete', `_private_hidx=${cid}#0`) - await sbp('chelonia.db/delete', `_private_keyop_idx_${cid}_0`) await sbp('chelonia.db/set', cid, '') - sbp('chelonia/private/removeImmediately', cid) + await sbp('backend/server/updateContractFilesTotalSize', owner, -Number(size)) - if (size) { - await ownerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID: cid, size: -parseInt(size), ultimateOwnerID }) + if (ultimateOwnerID && size) { + await currentOwnerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID: cid, size: -parseInt(size), ultimateOwnerID }) } - - await sbp('chelonia.db/delete', `_private_cheloniaState_${cid}`) - await removeFromIndexFactory('_private_cheloniaState_index')(cid) - // Note: `creditsWorker.js` could be updated to do this instead - await removeFromIndexFactory('_private_billable_entities')(cid) - sbp('backend/server/broadcastDeletion', cid).catch((e: unknown) => { - console.error(e, 'Error broadcasting contract deletion', cid) - }) - }).finally(() => { - contractsPendingDeletion.delete(cid) - }).catch((e: unknown) => { - console.error(e, 'Error in contract deletion cleanup') - throw e - }) - } -}) - -sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { - serverHandlers: { - connection (socket) { - const versionInfo = { - appVersion: cheloniaAppManifest?.appVersion || null, - contractsVersion: cheloniaAppManifest?.contracts ? Object.fromEntries( - Object.entries(cheloniaAppManifest?.contracts) - .map(([k, v]) => [k, (v as { version: string }).version]) - ) : null + }, + async 'backend/deleteContract' (cid: string, ultimateOwnerID?: string | null, skipIfDeleted?: boolean | null): Promise { + let contractsPendingDeletion = sbp('okTurtles.data/get', 'contractsPendingDeletion') + if (!contractsPendingDeletion) { + contractsPendingDeletion = new Set() + sbp('okTurtles.data/set', 'contractsPendingDeletion', contractsPendingDeletion) } - socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) - } - }, - socketHandlers: { - // The `close()` handler signals the server that the WS has been closed and - // that subsequent messages to subscribed channels should now be sent to its - // associated web push subscription, if it exists. - close () { - const socket = this - const { server } = this - const subscriptionId = socket.pushSubscriptionId - if (!subscriptionId) return - if (!server.pushSubscriptions[subscriptionId]) return - server.pushSubscriptions[subscriptionId].sockets.delete(socket) - delete socket.pushSubscriptionId - - if (server.pushSubscriptions[subscriptionId].sockets.size === 0) { - server.pushSubscriptions[subscriptionId].subscriptions.forEach((channelID) => { - if (!server.subscribersByChannelID[channelID]) { - server.subscribersByChannelID[channelID] = new Set() + // Avoid deadlocks due to loops + if (contractsPendingDeletion.has(cid)) { + return + } + contractsPendingDeletion.add(cid) + + return await sbp('chelonia/queueInvocation', cid, async () => { + const owner = await sbp('chelonia.db/get', `_private_owner_${cid}`) + if (!ultimateOwnerID) ultimateOwnerID = await lookupUltimateOwner(cid) + const rawManifest = await sbp('chelonia.db/get', cid) + const size = await sbp('chelonia.db/get', `_private_size_${cid}`) + // If running in a persistent queue, already deleted contract should not + // result in an error, because exceptions will result in the task being + // re-attempted + if (rawManifest === '') { if (skipIfDeleted) return; throw new BackendErrorGone() } + if (!rawManifest) { if (skipIfDeleted) return; throw new BackendErrorNotFound() } + + // Cascade delete all resources owned by this contract, such as files + // (attachments) and other contracts. Removing a single contract could + // therefore result in a large number of contracts being deleted. For + // example, in Group Income, deleting an identity contract will delete: + // - All groups created by that contract + // - This includes files like the group avatar + // - And also all chatrooms + // - And all attachments in chatrooms + // - All DMs created by that contract + // - And all attachments + const resourcesKey = `_private_resources_${cid}` + const resources = await sbp('chelonia.db/get', resourcesKey) + if (resources) { + await Promise.allSettled(resources.split('\x00').map((resourceCid: string) => { + const parsed = parseCID(resourceCid) + + if (parsed.code === multicodes.SHELTER_CONTRACT_DATA) { + return sbp('chelonia.persistentActions/enqueue', ['backend/deleteContract', resourceCid, ultimateOwnerID, true]) + } else if (parsed.code === multicodes.SHELTER_FILE_MANIFEST) { + return sbp('chelonia.persistentActions/enqueue', ['backend/deleteFile', resourceCid, ultimateOwnerID, true]) + } else { + console.warn({ cid, resourceCid, code: parsed.code }, 'Resource should be deleted but it is of an unknown type') + } + + return undefined + })) + } + await sbp('chelonia.db/delete', resourcesKey) + + // Next, loop through all the events, except the very first one, + // in the contract and delete them, starting with the most recent ones. + // If the deletion process is interrupted, parts of the contract will + // still be able to be synced, but won't be to write to it (due to + // latestHEADinfo not being deleted). + const latestHEADinfo = await sbp('chelonia/db/latestHEADinfo', cid) + if (latestHEADinfo) { + for (let i = latestHEADinfo.height; i > 0; i--) { + const eventKey = `_private_hidx=${cid}#${i}` + const event = await sbp('chelonia.db/get', eventKey) + if (event) { + await sbp('chelonia.db/delete', JSON.parse(event).hash) + await sbp('chelonia.db/delete', eventKey) + } + if (i % KEYOP_SEGMENT_LENGTH === 0) { + await sbp('chelonia.db/delete', `_private_keyop_idx_${cid}_${i}`) + } } - server.subscribersByChannelID[channelID].add(server.pushSubscriptions[subscriptionId]) + await sbp('chelonia/db/deleteLatestHEADinfo', cid) + } + + // Then, delete all KV-store values associated with this contract + const kvIndexKey = `_private_kvIdx_${cid}` + const kvKeys = await sbp('chelonia.db/get', kvIndexKey) + if (kvKeys) { + await Promise.all(kvKeys.split('\x00').map((key: string) => { + return sbp('chelonia.db/delete', `_private_kv_${cid}_${key}`) + })) + } + await sbp('chelonia.db/delete', kvIndexKey) + await sbp('backend/server/removeFromIndirectResourcesIndex', cid) + await sbp('chelonia.db/delete', `_private_indirectResources_${cid}`) + + await sbp('chelonia.db/get', `_private_cid2name_${cid}`).then((name: unknown) => { + if (!name) return + return Promise.all([ + sbp('chelonia.db/delete', `_private_cid2name_${cid}`), + appendToOrphanedNamesIndex(name as string) + ]) }) - } + await sbp('chelonia.db/delete', `_private_rid_${cid}`) + await sbp('chelonia.db/delete', `_private_owner_${cid}`) + await sbp('chelonia.db/delete', `_private_size_${cid}`) + await sbp('chelonia.db/delete', `_private_contractFilesTotalSize_${cid}`) + await sbp('chelonia.db/delete', `_private_deletionTokenDgst_${cid}`) + await removeFromIndexFactory(`_private_resources_${owner}`)(cid) + + // Delete the first event and its associated keys. These were not deleted + // in the loop above that deletes events one by one. + await sbp('chelonia.db/delete', `_private_hidx=${cid}#0`) + await sbp('chelonia.db/delete', `_private_keyop_idx_${cid}_0`) + await sbp('chelonia.db/set', cid, '') + sbp('chelonia/private/removeImmediately', cid) + + if (size) { + await currentOwnerSizeTotalWorker?.rpcSbp('worker/updateSizeSideEffects', { resourceID: cid, size: -parseInt(size), ultimateOwnerID }) + } + + await sbp('chelonia.db/delete', `_private_cheloniaState_${cid}`) + await removeFromIndexFactory('_private_cheloniaState_index')(cid) + // Note: `creditsWorker.js` could be updated to do this instead + await removeFromIndexFactory('_private_billable_entities')(cid) + sbp('backend/server/broadcastDeletion', cid).catch((e: unknown) => { + console.error(e, 'Error broadcasting contract deletion', cid) + }) + }).finally(() => { + contractsPendingDeletion.delete(cid) + }).catch((e: unknown) => { + console.error(e, 'Error in contract deletion cleanup') + throw e + }) } - }, - messageHandlers: { - [REQUEST_TYPE.PUSH_ACTION]: async function ({ data }) { - const socket = this - const { action, payload } = data - - if (!action) { - socket.send(createPushErrorResponse({ message: '\'action\' field is required' })) - } + }) +} + +// ============================================================================ +// Exported server lifecycle functions +// ============================================================================ + +export async function startServer (): Promise<{ uri: string }> { + // Read configuration from nconf + const appDir = nconf.get('server:appDir') || process.cwd() + const ARCHIVE_MODE = nconf.get('server:archiveMode') + const host = nconf.get('server:host') || '0.0.0.0' + const port = nconf.get('server:port') ?? 8000 + + // Validate worker intervals + if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { + console.error('The size calculation worker must run more frequently than the credits worker for accurate billing') + throw new Error('The size calculation worker must run more frequently than the credits worker for accurate billing') + } + + // Load chelonia.json manifest + try { + currentManifest = (await import(pathToFileURL(join(appDir, 'chelonia.json')).toString(), { + with: { type: 'json' } + })).default + } catch { + console.warn('`chelonia.json` unparsable or not found. Version information will be unavailable.') + } + + // Initialize workers for size calculation and credits processing + currentOwnerSizeTotalWorker = ARCHIVE_MODE || !OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL + ? undefined + : createWorker((import.meta as ImportMeta).ownerSizeTotalWorker || './ownerSizeTotalWorker.ts') + currentCreditsWorker = ARCHIVE_MODE || !CREDITS_WORKER_TASK_TIME_INTERVAL + ? undefined + : createWorker((import.meta as ImportMeta).creditsWorker || './creditsWorker.ts') - const handler = pushServerActionhandlers[action as keyof typeof pushServerActionhandlers] + // Create Hono app + currentApp = new Hono() - if (handler) { - try { - await (handler as (this: typeof socket, payload: unknown) => Promise).call(socket, payload) - } catch (error) { - const message = (error as Error)?.message || `push server failed to perform [${action}] action` - console.warn(error, `[${socket.ip}] Action '${action}' for '${REQUEST_TYPE.PUSH_ACTION}' handler failed: ${message}`) - socket.send(createPushErrorResponse({ actionType: action, message: message })) + // Global middleware: CORS + currentApp.use('*', cors({ origin: '*' })) + + // Global middleware: X-Frame-Options on every response + currentApp.use('*', async (c, next) => { + await next() + c.header('X-Frame-Options', 'DENY') + }) + + // Dev logging middleware + if (process.env.NODE_ENV === 'development' && !process.env.CI) { + currentApp.use('*', async (c, next) => { + await next() + const ip = c.req.header('x-real-ip') || 'unknown' + console.debug(chalk`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`) + }) + } + + // Create the Node http.Server (without listening yet) via @hono/node-server + currentHttpServer = createAdaptorServer({ fetch: currentApp.fetch }) as Server + + // Install SBP selectors + installServerSelectorsOnce() + + // Set SERVER_INSTANCE so routes.ts can access it + sbp('okTurtles.data/set', SERVER_INSTANCE, currentApp) + + // Create pubsub server and set PUBSUB_INSTANCE + sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(currentHttpServer, { + serverHandlers: { + connection (socket) { + const manifest = currentManifest + const appVersion = typeof manifest?.appVersion === 'string' ? manifest.appVersion : null + const contracts = manifest?.contracts as Record | undefined + const versionInfo = { + appVersion, + contractsVersion: contracts ? Object.fromEntries( + Object.entries(contracts) + .map(([k, v]) => [k, v.version]) + ) : null } - } else { - socket.send(createPushErrorResponse({ message: `No handler for the '${action}' action` })) + socket.send(createNotification(NOTIFICATION_TYPE.VERSION_INFO, versionInfo)) } }, - // This handler adds subscribed channels to the web push subscription - // associated with the WS, so that when the WS is closed we can continue - // sending messages as web push notifications. - [NOTIFICATION_TYPE.SUB] ({ channelID }) { - const socket = this - const { server } = this - if (!socket.pushSubscriptionId) return - if (!server.pushSubscriptions[socket.pushSubscriptionId]) { + socketHandlers: { + // The `close()` handler signals the server that the WS has been closed and + // that subsequent messages to subscribed channels should now be sent to its + // associated web push subscription, if it exists. + close () { + const socket = this + const { server } = this + const subscriptionId = socket.pushSubscriptionId + if (!subscriptionId) return + if (!server.pushSubscriptions[subscriptionId]) return + server.pushSubscriptions[subscriptionId].sockets.delete(socket) delete socket.pushSubscriptionId - return - } - addChannelToSubscription(server, socket.pushSubscriptionId, channelID) - }, - // This handler removes subscribed channels from the web push subscription - // associated with the WS, so that when the WS is closed we don't send - // messages as web push notifications. - [NOTIFICATION_TYPE.UNSUB] ({ channelID }) { - const socket = this - const { server } = this - if (!socket.pushSubscriptionId) return - if (!server.pushSubscriptions[socket.pushSubscriptionId]) { - delete socket.pushSubscriptionId - return + if (server.pushSubscriptions[subscriptionId].sockets.size === 0) { + server.pushSubscriptions[subscriptionId].subscriptions.forEach((channelID) => { + if (!server.subscribersByChannelID[channelID]) { + server.subscribersByChannelID[channelID] = new Set() + } + server.subscribersByChannelID[channelID].add(server.pushSubscriptions[subscriptionId]) + }) + } } + }, + messageHandlers: { + [REQUEST_TYPE.PUSH_ACTION]: async function ({ data }) { + const socket = this + const { action, payload } = data + + if (!action) { + socket.send(createPushErrorResponse({ message: '\'action\' field is required' })) + } + + const handler = pushServerActionhandlers[action as keyof typeof pushServerActionhandlers] + + if (handler) { + try { + await (handler as (this: typeof socket, payload: unknown) => Promise).call(socket, payload) + } catch (error) { + const message = (error as Error)?.message || `push server failed to perform [${action}] action` + console.warn(error, `[${socket.ip}] Action '${action}' for '${REQUEST_TYPE.PUSH_ACTION}' handler failed: ${message}`) + socket.send(createPushErrorResponse({ actionType: action, message: message })) + } + } else { + socket.send(createPushErrorResponse({ message: `No handler for the '${action}' action` })) + } + }, + // This handler adds subscribed channels to the web push subscription + // associated with the WS, so that when the WS is closed we can continue + // sending messages as web push notifications. + [NOTIFICATION_TYPE.SUB] ({ channelID }) { + const socket = this + const { server } = this + if (!socket.pushSubscriptionId) return + if (!server.pushSubscriptions[socket.pushSubscriptionId]) { + delete socket.pushSubscriptionId + return + } - deleteChannelFromSubscription(server, socket.pushSubscriptionId, channelID) + addChannelToSubscription(server, socket.pushSubscriptionId, channelID) + }, + // This handler removes subscribed channels from the web push subscription + // associated with the WS, so that when the WS is closed we don't send + // messages as web push notifications. + [NOTIFICATION_TYPE.UNSUB] ({ channelID }) { + const socket = this + const { server } = this + if (!socket.pushSubscriptionId) return + if (!server.pushSubscriptions[socket.pushSubscriptionId]) { + delete socket.pushSubscriptionId + return + } + + deleteChannelFromSubscription(server, socket.pushSubscriptionId, channelID) + } } - } -})) + })) -;(async function () { + // Initialize database await initDB() - await ownerSizeTotalWorker?.ready - await creditsWorker?.ready + + // Wait for workers to be ready + await currentOwnerSizeTotalWorker?.ready + await currentCreditsWorker?.ready + + // Configure Chelonia await sbp('chelonia/configure', SERVER) sbp('chelonia.persistentActions/configure', { databaseKey: '_private_persistent_actions' }) + // Load the saved Chelonia state // First, get the contract index const savedStateIndex = await sbp('chelonia.db/get', '_private_cheloniaState_index') @@ -544,6 +571,7 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { })) Object.assign(sbp('chelonia/rootState'), recoveredState) } + // Then, load push subscriptions const savedWebPushIndex = await sbp('chelonia.db/get', '_private_webpush_index') if (savedWebPushIndex) { @@ -563,28 +591,18 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(httpServer, { }) })) } + + // Fire-and-forget persistent actions load sbp('chelonia.persistentActions/load').catch((e: unknown) => { console.error(e, 'Error loading persistent actions') }) - // Import routes (they will register themselves on the Hono app via SERVER_INSTANCE) - await import('./routes.ts') - // Start listening - const host = nconf.get('server:host') || '0.0.0.0' - const port = nconf.get('server:port') ?? 8000 - httpServer.listen(port, host, () => { - const addr = httpServer.address() as { address: string; port: number } - const uri = `http://${addr.address}:${addr.port}` - console.info('Backend server running at:', uri) - sbp('okTurtles.events/emit', SERVER_RUNNING, { info: { uri } }) - }) -})() -// Recurring task to send messages to push clients (for periodic notifications) -let pushHeartbeatIntervalID: ReturnType -;(() => { - const map = new WeakMap() + // Register routes + registerRoutes(currentApp) - pushHeartbeatIntervalID = setInterval(() => { + // Start the push-heartbeat interval + const map = new WeakMap() + currentPushHeartbeatIntervalID = setInterval(() => { const now = Date.now() const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as WSS | undefined // Notification text @@ -605,4 +623,77 @@ let pushHeartbeatIntervalID: ReturnType }) // Repeat every 1 hour }, 1 * 60 * 60 * 1000) -})() + + // Start listening + const uri = await new Promise((resolve, reject) => { + currentHttpServer!.listen(port, host, () => { + const addr = currentHttpServer!.address() as { address: string; port: number } + const uri = `http://${addr.address}:${addr.port}` + console.info('Backend server running at:', uri) + sbp('okTurtles.events/emit', SERVER_RUNNING, { info: { uri } }) + resolve(uri) + }).once('error', reject) + }) + + return { uri } +} + +export async function stopServer (): Promise { + // Clear push-heartbeat interval + if (currentPushHeartbeatIntervalID !== undefined) { + clearInterval(currentPushHeartbeatIntervalID) + currentPushHeartbeatIntervalID = undefined + } + + // Stop rate limiters if registered + if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { + await sbp('backend/server/stopRateLimiters') + } + + // Close pubsub server (clears its ping interval) + const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as { close: () => void; clients: Set<{ terminate: () => void }> } | undefined + if (pubsub) { + pubsub.clients.forEach((client) => client.terminate()) + pubsub.close() + sbp('okTurtles.data/delete', PUBSUB_INSTANCE) + } + + // Close HTTP server + if (currentHttpServer) { + await new Promise((resolve, reject) => { + currentHttpServer!.close((err) => { + if (err) { + reject(err) + } else { + resolve() + } + }) + }) + currentHttpServer = null + } + + // Terminate workers + await Promise.all([ + currentOwnerSizeTotalWorker?.terminate(), + currentCreditsWorker?.terminate() + ]) + currentOwnerSizeTotalWorker = undefined + currentCreditsWorker = undefined + + // Close database + await closeDB() + + // Clear app and manifest + currentApp = null + currentManifest = undefined +} + +// Legacy: export the Hono app for backwards compatibility (deprecated) +export const app = new Proxy({} as Hono, { + get (_target, prop) { + if (currentApp) { + return Reflect.get(currentApp, prop) + } + return undefined + } +}) From 5eb98e160d9b73e132f8e803ebe1b2a4052a652a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Fri, 17 Apr 2026 21:23:44 +0000 Subject: [PATCH 28/71] Fixes --- build/main.js | 671 ++++++++++++++-------------- build/serve/creditsWorker.js | 16 +- build/serve/ownerSizeTotalWorker.js | 16 +- src/serve/genericWorker.ts | 5 +- src/serve/index.ts | 5 +- src/serve/logger.ts | 22 +- src/serve/routes.ts | 12 +- src/serve/server.ts | 2 +- 8 files changed, 391 insertions(+), 358 deletions(-) diff --git a/build/main.js b/build/main.js index fff6299..4ddbdc7 100644 --- a/build/main.js +++ b/build/main.js @@ -4108,9 +4108,10 @@ import crypto2 from "node:crypto"; import { Buffer as Buffer13 } from "node:buffer"; import { basename as basename52 } from "node:path"; import process5 from "node:process"; -import { join as join72 } from "node:path"; +import { join as join82 } from "node:path"; import process9 from "node:process"; import { Buffer as Buffer14 } from "node:buffer"; +import { join as join72 } from "node:path"; import { isIP } from "node:net"; import path5 from "node:path"; import process7 from "node:process"; @@ -4121,7 +4122,6 @@ import { Buffer as Buffer15 } from "node:buffer"; import { pathToFileURL } from "node:url"; import path6 from "node:path"; import process11 from "node:process"; -import { join as join82 } from "node:path"; import { notStrictEqual, strictEqual } from "node:assert"; import { dirname as dirname62, resolve as resolve42 } from "node:path"; import { readdirSync, statSync } from "node:fs"; @@ -72509,16 +72509,282 @@ init_functions(); init_esm(); var import_npm_bottleneck = __toESM(require_lib6()); var import_npm_chalk = __toESM(require_source()); +var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; +var getMimeType = (filename, mimes = baseMimes) => { + const regexp = /\.([a-zA-Z0-9]+?)$/; + const match2 = filename.match(regexp); + if (!match2) { + return; + } + let mimeType = mimes[match2[1].toLowerCase()]; + if (mimeType && mimeType.startsWith("text")) { + mimeType += "; charset=utf-8"; + } + return mimeType; +}; +var _baseMimes = { + aac: "audio/aac", + avi: "video/x-msvideo", + avif: "image/avif", + av1: "video/av1", + bin: "application/octet-stream", + bmp: "image/bmp", + css: "text/css", + csv: "text/csv", + eot: "application/vnd.ms-fontobject", + epub: "application/epub+zip", + gif: "image/gif", + gz: "application/gzip", + htm: "text/html", + html: "text/html", + ico: "image/x-icon", + ics: "text/calendar", + jpeg: "image/jpeg", + jpg: "image/jpeg", + js: "text/javascript", + json: "application/json", + jsonld: "application/ld+json", + map: "application/json", + mid: "audio/x-midi", + midi: "audio/x-midi", + mjs: "text/javascript", + mp3: "audio/mpeg", + mp4: "video/mp4", + mpeg: "video/mpeg", + oga: "audio/ogg", + ogv: "video/ogg", + ogx: "application/ogg", + opus: "audio/opus", + otf: "font/otf", + pdf: "application/pdf", + png: "image/png", + rtf: "application/rtf", + svg: "image/svg+xml", + tif: "image/tiff", + tiff: "image/tiff", + ts: "video/mp2t", + ttf: "font/ttf", + txt: "text/plain", + wasm: "application/wasm", + webm: "video/webm", + weba: "audio/webm", + webmanifest: "application/manifest+json", + webp: "image/webp", + woff: "font/woff", + woff2: "font/woff2", + xhtml: "application/xhtml+xml", + xml: "application/xml", + zip: "application/zip", + "3gp": "video/3gpp", + "3g2": "video/3gpp2", + gltf: "model/gltf+json", + glb: "model/gltf-binary" +}; +var baseMimes = _baseMimes; +var defaultJoin = (...paths) => { + let result = paths.filter((p) => p !== "").join("/"); + result = result.replace(/(?<=\/)\/+/g, ""); + const segments = result.split("/"); + const resolved = []; + for (const segment of segments) { + if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { + resolved.pop(); + } else if (segment !== ".") { + resolved.push(segment); + } + } + return resolved.join("/") || "."; +}; +var ENCODINGS = { + br: ".br", + zstd: ".zst", + gzip: ".gz" +}; +var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); +var DEFAULT_DOCUMENT = "index.html"; +var serveStatic = (options2) => { + const root = options2.root ?? "./"; + const optionPath = options2.path; + const join10 = options2.join ?? defaultJoin; + return async (c, next) => { + if (c.finalized) { + return next(); + } + let filename; + if (options2.path) { + filename = options2.path; + } else { + try { + filename = tryDecodeURI(c.req.path); + if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { + throw new Error(); + } + } catch { + await options2.onNotFound?.(c.req.path, c); + return next(); + } + } + let path8 = join10( + root, + !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename + ); + if (options2.isDir && await options2.isDir(path8)) { + path8 = join10(path8, DEFAULT_DOCUMENT); + } + const getContent = options2.getContent; + let content = await getContent(path8, c); + if (content instanceof Response) { + return c.newResponse(content.body, content); + } + if (content) { + const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); + c.header("Content-Type", mimeType || "application/octet-stream"); + if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { + const acceptEncodingSet = new Set( + c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) + ); + for (const encoding of ENCODINGS_ORDERED_KEYS) { + if (!acceptEncodingSet.has(encoding)) { + continue; + } + const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); + if (compressedContent) { + content = compressedContent; + c.header("Content-Encoding", encoding); + c.header("Vary", "Accept-Encoding", { append: true }); + break; + } + } + } + await options2.onFound?.(path8, c); + return c.body(content); + } + await options2.onNotFound?.(path8, c); + await next(); + return; + }; +}; +var { open, lstatSync, errors } = Deno; +var serveStatic2 = (options2) => { + return async function serveStatic22(c, next) { + const getContent = async (path8) => { + try { + if (isDir(path8)) { + return null; + } + const file = await open(path8); + return file.readable; + } catch (e2) { + if (!(e2 instanceof errors.NotFound)) { + console.warn(`${e2}`); + } + return null; + } + }; + const isDir = (path8) => { + let isDir2; + try { + const stat = lstatSync(path8); + isDir2 = stat.isDirectory; + } catch { + } + return isDir2; + }; + return serveStatic({ + ...options2, + getContent, + join: join72, + isDir + })(c, next); + }; +}; +var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; +var SSG_DISABLED_RESPONSE = (() => { + try { + return new Response("SSG is disabled", { + status: 404, + headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } + }); + } catch { + return null; + } +})(); +var WSContext = class { + #init; + constructor(init2) { + this.#init = init2; + this.raw = init2.raw; + this.url = init2.url ? new URL(init2.url) : null; + this.protocol = init2.protocol ?? null; + } + send(source, options2) { + this.#init.send(source, options2 ?? {}); + } + raw; + binaryType = "arraybuffer"; + get readyState() { + return this.#init.readyState; + } + url; + protocol; + close(code2, reason) { + this.#init.close(code2, reason); + } +}; +var defineWebSocketHelper = (handler) => { + return (...args) => { + if (typeof args[0] === "function") { + const [createEvents, options2] = args; + return async function upgradeWebSocket2(c, next) { + const events = await createEvents(c); + const result = await handler(c, events, options2); + if (result) { + return result; + } + await next(); + }; + } else { + const [c, events, options2] = args; + return (async () => { + const upgraded = await handler(c, events, options2); + if (!upgraded) { + throw new Error("Failed to upgrade WebSocket"); + } + return upgraded; + })(); + } + }; +}; +var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { + if (c.req.header("upgrade") !== "websocket") { + return; + } + const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); + const wsContext = new WSContext({ + close: (code2, reason) => socket.close(code2, reason), + get protocol() { + return socket.protocol; + }, + raw: socket, + get readyState() { + return socket.readyState; + }, + url: socket.url ? new URL(socket.url) : null, + send: (source) => socket.send(source) + }); + socket.onopen = (evt) => events.onOpen?.(evt, wsContext); + socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); + socket.onclose = (evt) => events.onClose?.(evt, wsContext); + socket.onerror = (evt) => events.onError?.(evt, wsContext); + return response; +}); var getConnInfo = (c) => { - const bindings = c.env.server ? c.env.server : c.env; - const address = bindings.incoming.socket.remoteAddress; - const port = bindings.incoming.socket.remotePort; - const family = bindings.incoming.socket.remoteFamily; + const { remoteAddr } = c.env; return { remote: { - address, - port, - addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0 + address: remoteAddr.hostname, + port: remoteAddr.port, + transport: remoteAddr.transport } }; }; @@ -72558,58 +72824,17 @@ if (Object.keys(logger.levels.values).includes(logLevel)) { } else { logger.warn(`Unknown log level: ${logLevel}`); } -console.debug = logger.debug.bind(logger); -console.info = logger.info.bind(logger); -console.log = logger.info.bind(logger); -console.warn = logger.warn.bind(logger); -console.error = logger.error.bind(logger); -var logger_default = logger; -var import_npm_nconf4 = __toESM(require_nconf()); -function extractBearer(c) { - const authorization = c.req.header("authorization"); - if (!authorization) return null; - const prefix = "bearer "; - if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; - return { token: authorization.slice(prefix.length) }; -} -function extractShelter(c) { - const authorization = c.req.header("authorization"); - if (!authorization) return null; - const prefix = "shelter "; - if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; - try { - const billableContractID = verifyShelterAuthorizationHeader(authorization); - return { billableContractID }; - } catch (e2) { - console.warn(e2, "Shelter authorization failed"); - return null; - } -} -var extractors = { - "chel-bearer": extractBearer, - "chel-shelter": extractShelter -}; -function authMiddleware(strategies, mode = "required") { - const strategyList = Array.isArray(strategies) ? strategies : [strategies]; - return async (c, next) => { - for (const strategy of strategyList) { - const extractor = extractors[strategy]; - if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`); - const credentials = extractor(c); - if (credentials) { - c.set("credentials", credentials); - c.set("authStrategy", strategy); - return next(); - } - } - if (mode === "optional") { - c.set("credentials", {}); - c.set("authStrategy", ""); - return next(); - } - throw new HTTPException(401, { message: "Unauthorized" }); - }; +var loggerInitialized = false; +function initializeLogger() { + if (loggerInitialized) return; + loggerInitialized = true; + console.debug = logger.debug.bind(logger); + console.info = logger.info.bind(logger); + console.log = logger.info.bind(logger); + console.warn = logger.warn.bind(logger); + console.error = logger.error.bind(logger); } +var logger_default = logger; var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/; var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/; var trimCookieWhitespace = (value) => { @@ -72792,7 +73017,6 @@ function zValidatorFunction(target, schema, hook, options2) { }); } var zValidator = zValidatorFunction; -init_zod(); var ERROR_MESSAGE = "Payload Too Large"; var BodyLimitError = class extends Error { constructor(message) { @@ -72850,6 +73074,53 @@ var bodyLimit = (options2) => { } }; }; +var import_npm_nconf4 = __toESM(require_nconf()); +init_zod(); +function extractBearer(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "bearer "; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; + return { token: authorization.slice(prefix.length) }; +} +function extractShelter(c) { + const authorization = c.req.header("authorization"); + if (!authorization) return null; + const prefix = "shelter "; + if (authorization.slice(0, prefix.length).toLowerCase() !== prefix) return null; + try { + const billableContractID = verifyShelterAuthorizationHeader(authorization); + return { billableContractID }; + } catch (e2) { + console.warn(e2, "Shelter authorization failed"); + return null; + } +} +var extractors = { + "chel-bearer": extractBearer, + "chel-shelter": extractShelter +}; +function authMiddleware(strategies, mode = "required") { + const strategyList = Array.isArray(strategies) ? strategies : [strategies]; + return async (c, next) => { + for (const strategy of strategyList) { + const extractor = extractors[strategy]; + if (!extractor) throw new Error(`Unknown auth strategy: ${strategy}`); + const credentials = extractor(c); + if (credentials) { + c.set("credentials", credentials); + c.set("authStrategy", strategy); + return next(); + } + } + if (mode === "optional") { + c.set("credentials", {}); + c.set("authStrategy", ""); + return next(); + } + throw new HTTPException(401, { message: "Unauthorized" }); + }; +} var MEGABYTE = 1048576; var SECOND = 1e3; var CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; @@ -74036,9 +74307,9 @@ var import_npm_chalk2 = __toESM(require_source()); var import_stream2 = __toESM(require_stream(), 1); var import_receiver = __toESM(require_receiver(), 1); var import_sender = __toESM(require_sender(), 1); -var import_websocket = __toESM(require_websocket(), 1); +var import_websocket3 = __toESM(require_websocket(), 1); var import_websocket_server = __toESM(require_websocket_server(), 1); -var wrapper_default = import_websocket.default; +var wrapper_default = import_websocket3.default; var isPushSubscriptionInfo = (x3) => { return has(x3, "endpoint"); }; @@ -74619,7 +74890,7 @@ async function startServer() { throw new Error("The size calculation worker must run more frequently than the credits worker for accurate billing"); } try { - currentManifest = (await import(pathToFileURL(join72(appDir, "chelonia.json")).toString(), { + currentManifest = (await import(pathToFileURL(join82(appDir, "chelonia.json")).toString(), { with: { type: "json" } })).default; } catch { @@ -74636,7 +74907,7 @@ async function startServer() { if (process9.env.NODE_ENV === "development" && !process9.env.CI) { currentApp.use("*", async (c, next) => { await next(); - const ip = c.req.header("x-real-ip") || "unknown"; + const ip = c.req.header("x-real-ip") || c.req.header("x-forwarded-for")?.split(",")[0].trim() || "unknown"; console.debug(import_npm_chalk3.default`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`); }); } @@ -74916,6 +75187,7 @@ var exit2 = (code2) => { }; async function startServer2(options2 = {}) { const { installSignalHandlers: shouldInstallSignalHandlers = true } = options2; + initializeLogger(); if (shouldInstallSignalHandlers) { installGlobalExceptionHandlers(); installSignalHandlers(); @@ -74954,275 +75226,6 @@ async function startServer2(options2 = {}) { async function stopServer2() { await stopServer(); } -var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; -var getMimeType = (filename, mimes = baseMimes) => { - const regexp = /\.([a-zA-Z0-9]+?)$/; - const match2 = filename.match(regexp); - if (!match2) { - return; - } - let mimeType = mimes[match2[1].toLowerCase()]; - if (mimeType && mimeType.startsWith("text")) { - mimeType += "; charset=utf-8"; - } - return mimeType; -}; -var _baseMimes = { - aac: "audio/aac", - avi: "video/x-msvideo", - avif: "image/avif", - av1: "video/av1", - bin: "application/octet-stream", - bmp: "image/bmp", - css: "text/css", - csv: "text/csv", - eot: "application/vnd.ms-fontobject", - epub: "application/epub+zip", - gif: "image/gif", - gz: "application/gzip", - htm: "text/html", - html: "text/html", - ico: "image/x-icon", - ics: "text/calendar", - jpeg: "image/jpeg", - jpg: "image/jpeg", - js: "text/javascript", - json: "application/json", - jsonld: "application/ld+json", - map: "application/json", - mid: "audio/x-midi", - midi: "audio/x-midi", - mjs: "text/javascript", - mp3: "audio/mpeg", - mp4: "video/mp4", - mpeg: "video/mpeg", - oga: "audio/ogg", - ogv: "video/ogg", - ogx: "application/ogg", - opus: "audio/opus", - otf: "font/otf", - pdf: "application/pdf", - png: "image/png", - rtf: "application/rtf", - svg: "image/svg+xml", - tif: "image/tiff", - tiff: "image/tiff", - ts: "video/mp2t", - ttf: "font/ttf", - txt: "text/plain", - wasm: "application/wasm", - webm: "video/webm", - weba: "audio/webm", - webmanifest: "application/manifest+json", - webp: "image/webp", - woff: "font/woff", - woff2: "font/woff2", - xhtml: "application/xhtml+xml", - xml: "application/xml", - zip: "application/zip", - "3gp": "video/3gpp", - "3g2": "video/3gpp2", - gltf: "model/gltf+json", - glb: "model/gltf-binary" -}; -var baseMimes = _baseMimes; -var defaultJoin = (...paths) => { - let result = paths.filter((p) => p !== "").join("/"); - result = result.replace(/(?<=\/)\/+/g, ""); - const segments = result.split("/"); - const resolved = []; - for (const segment of segments) { - if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { - resolved.pop(); - } else if (segment !== ".") { - resolved.push(segment); - } - } - return resolved.join("/") || "."; -}; -var ENCODINGS = { - br: ".br", - zstd: ".zst", - gzip: ".gz" -}; -var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); -var DEFAULT_DOCUMENT = "index.html"; -var serveStatic = (options2) => { - const root = options2.root ?? "./"; - const optionPath = options2.path; - const join10 = options2.join ?? defaultJoin; - return async (c, next) => { - if (c.finalized) { - return next(); - } - let filename; - if (options2.path) { - filename = options2.path; - } else { - try { - filename = tryDecodeURI(c.req.path); - if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { - throw new Error(); - } - } catch { - await options2.onNotFound?.(c.req.path, c); - return next(); - } - } - let path8 = join10( - root, - !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename - ); - if (options2.isDir && await options2.isDir(path8)) { - path8 = join10(path8, DEFAULT_DOCUMENT); - } - const getContent = options2.getContent; - let content = await getContent(path8, c); - if (content instanceof Response) { - return c.newResponse(content.body, content); - } - if (content) { - const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); - c.header("Content-Type", mimeType || "application/octet-stream"); - if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { - const acceptEncodingSet = new Set( - c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) - ); - for (const encoding of ENCODINGS_ORDERED_KEYS) { - if (!acceptEncodingSet.has(encoding)) { - continue; - } - const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); - if (compressedContent) { - content = compressedContent; - c.header("Content-Encoding", encoding); - c.header("Vary", "Accept-Encoding", { append: true }); - break; - } - } - } - await options2.onFound?.(path8, c); - return c.body(content); - } - await options2.onNotFound?.(path8, c); - await next(); - return; - }; -}; -var { open, lstatSync, errors } = Deno; -var serveStatic2 = (options2) => { - return async function serveStatic22(c, next) { - const getContent = async (path8) => { - try { - if (isDir(path8)) { - return null; - } - const file = await open(path8); - return file.readable; - } catch (e2) { - if (!(e2 instanceof errors.NotFound)) { - console.warn(`${e2}`); - } - return null; - } - }; - const isDir = (path8) => { - let isDir2; - try { - const stat = lstatSync(path8); - isDir2 = stat.isDirectory; - } catch { - } - return isDir2; - }; - return serveStatic({ - ...options2, - getContent, - join: join82, - isDir - })(c, next); - }; -}; -var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; -var SSG_DISABLED_RESPONSE = (() => { - try { - return new Response("SSG is disabled", { - status: 404, - headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } - }); - } catch { - return null; - } -})(); -var WSContext = class { - #init; - constructor(init2) { - this.#init = init2; - this.raw = init2.raw; - this.url = init2.url ? new URL(init2.url) : null; - this.protocol = init2.protocol ?? null; - } - send(source, options2) { - this.#init.send(source, options2 ?? {}); - } - raw; - binaryType = "arraybuffer"; - get readyState() { - return this.#init.readyState; - } - url; - protocol; - close(code2, reason) { - this.#init.close(code2, reason); - } -}; -var defineWebSocketHelper = (handler) => { - return (...args) => { - if (typeof args[0] === "function") { - const [createEvents, options2] = args; - return async function upgradeWebSocket2(c, next) { - const events = await createEvents(c); - const result = await handler(c, events, options2); - if (result) { - return result; - } - await next(); - }; - } else { - const [c, events, options2] = args; - return (async () => { - const upgraded = await handler(c, events, options2); - if (!upgraded) { - throw new Error("Failed to upgrade WebSocket"); - } - return upgraded; - })(); - } - }; -}; -var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { - if (c.req.header("upgrade") !== "websocket") { - return; - } - const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); - const wsContext = new WSContext({ - close: (code2, reason) => socket.close(code2, reason), - get protocol() { - return socket.protocol; - }, - raw: socket, - get readyState() { - return socket.readyState; - }, - url: socket.url ? new URL(socket.url) : null, - send: (source) => socket.send(source) - }); - socket.onopen = (evt) => events.onOpen?.(evt, wsContext); - socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); - socket.onclose = (evt) => events.onClose?.(evt, wsContext); - socket.onerror = (evt) => events.onError?.(evt, wsContext); - return response; -}); var import_npm_nconf6 = __toESM(require_nconf()); var getDashboardPath = () => { const baseDir = import.meta.dirname || path6.join(process11.cwd(), "build"); diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 814a512..8f29a0d 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -4633,11 +4633,17 @@ if (Object.keys(logger.levels.values).includes(logLevel)) { } else { logger.warn(`Unknown log level: ${logLevel}`); } -console.debug = logger.debug.bind(logger); -console.info = logger.info.bind(logger); -console.log = logger.info.bind(logger); -console.warn = logger.warn.bind(logger); -console.error = logger.error.bind(logger); +var loggerInitialized = false; +function initializeLogger() { + if (loggerInitialized) return; + loggerInitialized = true; + console.debug = logger.debug.bind(logger); + console.info = logger.info.bind(logger); + console.log = logger.info.bind(logger); + console.warn = logger.warn.bind(logger); + console.error = logger.error.bind(logger); +} +initializeLogger(); Object.defineProperties(Buffer2, { [serdesDeserializeSymbol]: { value(buf) { diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index deaef25..0abcbb0 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -4718,11 +4718,17 @@ if (Object.keys(logger.levels.values).includes(logLevel)) { } else { logger.warn(`Unknown log level: ${logLevel}`); } -console.debug = logger.debug.bind(logger); -console.info = logger.info.bind(logger); -console.log = logger.info.bind(logger); -console.warn = logger.warn.bind(logger); -console.error = logger.error.bind(logger); +var loggerInitialized = false; +function initializeLogger() { + if (loggerInitialized) return; + loggerInitialized = true; + console.debug = logger.debug.bind(logger); + console.info = logger.info.bind(logger); + console.log = logger.info.bind(logger); + console.warn = logger.warn.bind(logger); + console.error = logger.error.bind(logger); +} +initializeLogger(); Object.defineProperties(Buffer2, { [serdesDeserializeSymbol]: { value(buf) { diff --git a/src/serve/genericWorker.ts b/src/serve/genericWorker.ts index fbffb6e..072341d 100644 --- a/src/serve/genericWorker.ts +++ b/src/serve/genericWorker.ts @@ -2,7 +2,10 @@ import { Buffer } from 'node:buffer' import { deserializer, serdesDeserializeSymbol, serdesSerializeSymbol, serdesTagSymbol, serializer } from 'npm:@chelonia/serdes' import 'npm:@sbp/okturtles.eventqueue' import sbp from 'npm:@sbp/sbp' -import './logger.ts' +import { initializeLogger } from './logger.ts' + +// Initialize pino logger for worker processes +initializeLogger() Object.defineProperties(Buffer, { [serdesDeserializeSymbol]: { diff --git a/src/serve/index.ts b/src/serve/index.ts index 0f48383..3d07584 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -7,7 +7,7 @@ import chalk from 'npm:chalk' import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' import { PUBSUB_INSTANCE } from './instance-keys.ts' import { startServer as startServerImpl, stopServer as stopServerImpl } from './server.ts' -import './logger.ts' +import { initializeLogger } from './logger.ts' console.info('NODE_ENV =', process.env.NODE_ENV) @@ -110,6 +110,9 @@ export interface StartServerOptions { export async function startServer (options: StartServerOptions = {}): Promise<{ uri: string }> { const { installSignalHandlers: shouldInstallSignalHandlers = true } = options + // Initialize pino logger (replaces console.* methods) + initializeLogger() + // Install global exception handlers once per process (only if signal handlers are enabled) if (shouldInstallSignalHandlers) { installGlobalExceptionHandlers() diff --git a/src/serve/logger.ts b/src/serve/logger.ts index 5991914..51a33ca 100644 --- a/src/serve/logger.ts +++ b/src/serve/logger.ts @@ -48,10 +48,22 @@ if (Object.keys(logger.levels.values).includes(logLevel)) { logger.warn(`Unknown log level: ${logLevel}`) } -console.debug = logger.debug.bind(logger) -console.info = logger.info.bind(logger) -console.log = logger.info.bind(logger) -console.warn = logger.warn.bind(logger) -console.error = logger.error.bind(logger) +let loggerInitialized = false + +/** + * Initialize the pino logger by replacing console.* methods. + * This should be called explicitly when pino logging is desired + * (e.g., in the serve command), not automatically on import. + */ +export function initializeLogger (): void { + if (loggerInitialized) return + loggerInitialized = true + + console.debug = logger.debug.bind(logger) + console.info = logger.info.bind(logger) + console.log = logger.info.bind(logger) + console.warn = logger.warn.bind(logger) + console.error = logger.error.bind(logger) +} export default logger diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 8a5afb3..7d7aa9c 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -8,8 +8,8 @@ import 'npm:@chelonia/lib/persistent-actions' import sbp from 'npm:@sbp/sbp' import Bottleneck from 'npm:bottleneck' import chalk from 'npm:chalk' +import { getConnInfo } from 'npm:hono/deno' import { HTTPException } from 'npm:hono/http-exception' -import { getConnInfo } from 'npm:@hono/node-server/conninfo' // TODO: Use logger for debugging route handlers import { isIP } from 'node:net' import path from 'node:path' @@ -17,14 +17,14 @@ import process from 'node:process' import { appendToIndexFactory, lookupUltimateOwner } from './database.ts' import logger from './logger.ts' import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' +import { Readable } from 'node:stream' +import { zValidator } from 'npm:@hono/zod-validator' +import type { Context, Hono, MiddlewareHandler } from 'npm:hono' +import { bodyLimit } from 'npm:hono/body-limit' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' -import { authMiddleware, type AuthCredentials } from './auth.ts' -import type { Hono, Context, MiddlewareHandler } from 'npm:hono' -import { zValidator } from 'npm:@hono/zod-validator' import * as z from 'npm:zod' -import { bodyLimit } from 'npm:hono/body-limit' -import { Readable } from 'node:stream' +import { authMiddleware, type AuthCredentials } from './auth.ts' const MEGABYTE = 1048576 // TODO: add settings for these const SECOND = 1000 diff --git a/src/serve/server.ts b/src/serve/server.ts index 060e2e0..1712036 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -427,7 +427,7 @@ export async function startServer (): Promise<{ uri: string }> { if (process.env.NODE_ENV === 'development' && !process.env.CI) { currentApp.use('*', async (c, next) => { await next() - const ip = c.req.header('x-real-ip') || 'unknown' + const ip = c.req.header('x-real-ip') || c.req.header('x-forwarded-for')?.split(',')[0].trim() || 'unknown' console.debug(chalk`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`) }) } From 0679f6c962c6826f2f77bfa5a8c7107ff02944bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:36:59 +0000 Subject: [PATCH 29/71] Feedback --- build/main.js | 773 +++++++++++++++++----------------- scripts/build.ts | 2 +- src/serve/dashboard-server.ts | 14 +- src/serve/database.ts | 25 +- src/serve/routes.ts | 12 +- src/serve/server.ts | 91 ++-- 6 files changed, 477 insertions(+), 440 deletions(-) diff --git a/build/main.js b/build/main.js index 4ddbdc7..61d57dc 100644 --- a/build/main.js +++ b/build/main.js @@ -4108,20 +4108,20 @@ import crypto2 from "node:crypto"; import { Buffer as Buffer13 } from "node:buffer"; import { basename as basename52 } from "node:path"; import process5 from "node:process"; -import { join as join82 } from "node:path"; +import { join as join72 } from "node:path"; import process9 from "node:process"; import { Buffer as Buffer14 } from "node:buffer"; -import { join as join72 } from "node:path"; import { isIP } from "node:net"; import path5 from "node:path"; import process7 from "node:process"; -import process6 from "node:process"; import { Readable as Readable3 } from "node:stream"; +import process6 from "node:process"; import process8 from "node:process"; import { Buffer as Buffer15 } from "node:buffer"; import { pathToFileURL } from "node:url"; import path6 from "node:path"; import process11 from "node:process"; +import { join as join82 } from "node:path"; import { notStrictEqual, strictEqual } from "node:assert"; import { dirname as dirname62, resolve as resolve42 } from "node:path"; import { readdirSync, statSync } from "node:fs"; @@ -68311,6 +68311,7 @@ var globImport_database_ts2 = __glob({ var production = process2.env.NODE_ENV === "production"; var currentBackend = null; var currentCache = null; +var isClosing = false; var baseSelectorsInstalled = false; function installBaseSelectorsOnce() { if (baseSelectorsInstalled) return; @@ -68501,17 +68502,23 @@ var initDB = async ({ skipDbPreloading } = {}) => { initedDB = "preloaded"; }; async function closeDB() { - if (currentBackend) { - try { - await currentBackend.close(); - } catch (e2) { - console.error(e2, "Error closing DB"); + if (isClosing) return; + isClosing = true; + try { + if (currentBackend) { + try { + await currentBackend.close(); + } catch (e2) { + console.error(e2, "Error closing DB"); + } + currentBackend = null; } - currentBackend = null; + currentCache?.clear(); + currentCache = null; + initedDB = false; + } finally { + isClosing = false; } - currentCache?.clear(); - currentCache = null; - initedDB = false; } init_functions(); async function createEntryFromFile(filepath, multicode) { @@ -72506,335 +72513,22 @@ var createWorker = (path8) => { var createWorker_default = createWorker; init_SPMessage(); init_functions(); -init_esm(); -var import_npm_bottleneck = __toESM(require_lib6()); -var import_npm_chalk = __toESM(require_source()); -var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; -var getMimeType = (filename, mimes = baseMimes) => { - const regexp = /\.([a-zA-Z0-9]+?)$/; - const match2 = filename.match(regexp); - if (!match2) { - return; - } - let mimeType = mimes[match2[1].toLowerCase()]; - if (mimeType && mimeType.startsWith("text")) { - mimeType += "; charset=utf-8"; - } - return mimeType; -}; -var _baseMimes = { - aac: "audio/aac", - avi: "video/x-msvideo", - avif: "image/avif", - av1: "video/av1", - bin: "application/octet-stream", - bmp: "image/bmp", - css: "text/css", - csv: "text/csv", - eot: "application/vnd.ms-fontobject", - epub: "application/epub+zip", - gif: "image/gif", - gz: "application/gzip", - htm: "text/html", - html: "text/html", - ico: "image/x-icon", - ics: "text/calendar", - jpeg: "image/jpeg", - jpg: "image/jpeg", - js: "text/javascript", - json: "application/json", - jsonld: "application/ld+json", - map: "application/json", - mid: "audio/x-midi", - midi: "audio/x-midi", - mjs: "text/javascript", - mp3: "audio/mpeg", - mp4: "video/mp4", - mpeg: "video/mpeg", - oga: "audio/ogg", - ogv: "video/ogg", - ogx: "application/ogg", - opus: "audio/opus", - otf: "font/otf", - pdf: "application/pdf", - png: "image/png", - rtf: "application/rtf", - svg: "image/svg+xml", - tif: "image/tiff", - tiff: "image/tiff", - ts: "video/mp2t", - ttf: "font/ttf", - txt: "text/plain", - wasm: "application/wasm", - webm: "video/webm", - weba: "audio/webm", - webmanifest: "application/manifest+json", - webp: "image/webp", - woff: "font/woff", - woff2: "font/woff2", - xhtml: "application/xhtml+xml", - xml: "application/xml", - zip: "application/zip", - "3gp": "video/3gpp", - "3g2": "video/3gpp2", - gltf: "model/gltf+json", - glb: "model/gltf-binary" -}; -var baseMimes = _baseMimes; -var defaultJoin = (...paths) => { - let result = paths.filter((p) => p !== "").join("/"); - result = result.replace(/(?<=\/)\/+/g, ""); - const segments = result.split("/"); - const resolved = []; - for (const segment of segments) { - if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { - resolved.pop(); - } else if (segment !== ".") { - resolved.push(segment); - } - } - return resolved.join("/") || "."; -}; -var ENCODINGS = { - br: ".br", - zstd: ".zst", - gzip: ".gz" -}; -var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); -var DEFAULT_DOCUMENT = "index.html"; -var serveStatic = (options2) => { - const root = options2.root ?? "./"; - const optionPath = options2.path; - const join10 = options2.join ?? defaultJoin; - return async (c, next) => { - if (c.finalized) { - return next(); - } - let filename; - if (options2.path) { - filename = options2.path; - } else { - try { - filename = tryDecodeURI(c.req.path); - if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { - throw new Error(); - } - } catch { - await options2.onNotFound?.(c.req.path, c); - return next(); - } - } - let path8 = join10( - root, - !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename - ); - if (options2.isDir && await options2.isDir(path8)) { - path8 = join10(path8, DEFAULT_DOCUMENT); - } - const getContent = options2.getContent; - let content = await getContent(path8, c); - if (content instanceof Response) { - return c.newResponse(content.body, content); - } - if (content) { - const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); - c.header("Content-Type", mimeType || "application/octet-stream"); - if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { - const acceptEncodingSet = new Set( - c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) - ); - for (const encoding of ENCODINGS_ORDERED_KEYS) { - if (!acceptEncodingSet.has(encoding)) { - continue; - } - const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); - if (compressedContent) { - content = compressedContent; - c.header("Content-Encoding", encoding); - c.header("Vary", "Accept-Encoding", { append: true }); - break; - } - } - } - await options2.onFound?.(path8, c); - return c.body(content); - } - await options2.onNotFound?.(path8, c); - await next(); - return; - }; -}; -var { open, lstatSync, errors } = Deno; -var serveStatic2 = (options2) => { - return async function serveStatic22(c, next) { - const getContent = async (path8) => { - try { - if (isDir(path8)) { - return null; - } - const file = await open(path8); - return file.readable; - } catch (e2) { - if (!(e2 instanceof errors.NotFound)) { - console.warn(`${e2}`); - } - return null; - } - }; - const isDir = (path8) => { - let isDir2; - try { - const stat = lstatSync(path8); - isDir2 = stat.isDirectory; - } catch { - } - return isDir2; - }; - return serveStatic({ - ...options2, - getContent, - join: join72, - isDir - })(c, next); - }; -}; -var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; -var SSG_DISABLED_RESPONSE = (() => { - try { - return new Response("SSG is disabled", { - status: 404, - headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } - }); - } catch { - return null; - } -})(); -var WSContext = class { - #init; - constructor(init2) { - this.#init = init2; - this.raw = init2.raw; - this.url = init2.url ? new URL(init2.url) : null; - this.protocol = init2.protocol ?? null; - } - send(source, options2) { - this.#init.send(source, options2 ?? {}); - } - raw; - binaryType = "arraybuffer"; - get readyState() { - return this.#init.readyState; - } - url; - protocol; - close(code2, reason) { - this.#init.close(code2, reason); - } -}; -var defineWebSocketHelper = (handler) => { - return (...args) => { - if (typeof args[0] === "function") { - const [createEvents, options2] = args; - return async function upgradeWebSocket2(c, next) { - const events = await createEvents(c); - const result = await handler(c, events, options2); - if (result) { - return result; - } - await next(); - }; - } else { - const [c, events, options2] = args; - return (async () => { - const upgraded = await handler(c, events, options2); - if (!upgraded) { - throw new Error("Failed to upgrade WebSocket"); - } - return upgraded; - })(); - } - }; -}; -var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { - if (c.req.header("upgrade") !== "websocket") { - return; - } - const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); - const wsContext = new WSContext({ - close: (code2, reason) => socket.close(code2, reason), - get protocol() { - return socket.protocol; - }, - raw: socket, - get readyState() { - return socket.readyState; - }, - url: socket.url ? new URL(socket.url) : null, - send: (source) => socket.send(source) - }); - socket.onopen = (evt) => events.onOpen?.(evt, wsContext); - socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); - socket.onclose = (evt) => events.onClose?.(evt, wsContext); - socket.onerror = (evt) => events.onError?.(evt, wsContext); - return response; -}); var getConnInfo = (c) => { - const { remoteAddr } = c.env; + const bindings = c.env.server ? c.env.server : c.env; + const address = bindings.incoming.socket.remoteAddress; + const port = bindings.incoming.socket.remotePort; + const family = bindings.incoming.socket.remoteFamily; return { remote: { - address: remoteAddr.hostname, - port: remoteAddr.port, - transport: remoteAddr.transport + address, + port, + addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0 } }; }; -var import_npm_pino = __toESM(require_pino()); -var prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; -function logMethod(args, method) { - const stringIdx = typeof args[0] === "string" ? 0 : 1; - if (args.length > 1) { - for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { - args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; - } - } - method.apply(this, args); -} -var logger; -if (prettyPrint) { - try { - logger = (0, import_npm_pino.default)({ - hooks: { logMethod }, - transport: { - target: "pino-pretty", - options: { - colorize: true - } - } - }); - } catch (e2) { - console.warn("pino-pretty transport unavailable, using basic logging", e2); - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); - } -} else { - logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); -} -var logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); -if (Object.keys(logger.levels.values).includes(logLevel)) { - logger.level = logLevel; -} else { - logger.warn(`Unknown log level: ${logLevel}`); -} -var loggerInitialized = false; -function initializeLogger() { - if (loggerInitialized) return; - loggerInitialized = true; - console.debug = logger.debug.bind(logger); - console.info = logger.info.bind(logger); - console.log = logger.info.bind(logger); - console.warn = logger.warn.bind(logger); - console.error = logger.error.bind(logger); -} -var logger_default = logger; +init_esm(); +var import_npm_bottleneck = __toESM(require_lib6()); +var import_npm_chalk = __toESM(require_source()); var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/; var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/; var trimCookieWhitespace = (value) => { @@ -73074,6 +72768,53 @@ var bodyLimit = (options2) => { } }; }; +var import_npm_pino = __toESM(require_pino()); +var prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; +function logMethod(args, method) { + const stringIdx = typeof args[0] === "string" ? 0 : 1; + if (args.length > 1) { + for (let i2 = stringIdx + 1; i2 < args.length; ++i2) { + args[stringIdx] += typeof args[i2] === "string" ? " %s" : " %o"; + } + } + method.apply(this, args); +} +var logger; +if (prettyPrint) { + try { + logger = (0, import_npm_pino.default)({ + hooks: { logMethod }, + transport: { + target: "pino-pretty", + options: { + colorize: true + } + } + }); + } catch (e2) { + console.warn("pino-pretty transport unavailable, using basic logging", e2); + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); + } +} else { + logger = (0, import_npm_pino.default)({ hooks: { logMethod } }); +} +var logLevel = process6.env.LOG_LEVEL || (prettyPrint ? "debug" : "info"); +if (Object.keys(logger.levels.values).includes(logLevel)) { + logger.level = logLevel; +} else { + logger.warn(`Unknown log level: ${logLevel}`); +} +var loggerInitialized = false; +function initializeLogger() { + if (loggerInitialized) return; + loggerInitialized = true; + console.debug = logger.debug.bind(logger); + console.info = logger.info.bind(logger); + console.log = logger.info.bind(logger); + console.warn = logger.warn.bind(logger); + console.error = logger.error.bind(logger); +} +var logger_default = logger; var import_npm_nconf4 = __toESM(require_nconf()); init_zod(); function extractBearer(c) { @@ -74005,12 +73746,12 @@ function registerRoutes(app2) { app2.post( "/zkpp/:contractID/updatePasswordHash", zValidator("param", zkppContractParamSchema), - zValidator("json", zkppUpdatePasswordBodySchema), + zValidatorFormOrJson(zkppUpdatePasswordBodySchema), async function(c) { const { contractID } = c.req.valid("param"); if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { - const payload = c.req.valid("json"); + const payload = c.get("validatedBody"); const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea); if (result) { return c.json(result); @@ -74307,9 +74048,9 @@ var import_npm_chalk2 = __toESM(require_source()); var import_stream2 = __toESM(require_stream(), 1); var import_receiver = __toESM(require_receiver(), 1); var import_sender = __toESM(require_sender(), 1); -var import_websocket3 = __toESM(require_websocket(), 1); +var import_websocket = __toESM(require_websocket(), 1); var import_websocket_server = __toESM(require_websocket_server(), 1); -var wrapper_default = import_websocket3.default; +var wrapper_default = import_websocket.default; var isPushSubscriptionInfo = (x3) => { return has(x3, "endpoint"); }; @@ -74640,6 +74381,7 @@ var currentOwnerSizeTotalWorker = void 0; var currentCreditsWorker = void 0; var currentManifest = void 0; var currentPushHeartbeatIntervalID = void 0; +var isStopping = false; var appendToOrphanedNamesIndex = appendToIndexFactory("_private_orphaned_names_index"); var serverSelectorsInstalled = false; function installServerSelectorsOnce() { @@ -74890,7 +74632,7 @@ async function startServer() { throw new Error("The size calculation worker must run more frequently than the credits worker for accurate billing"); } try { - currentManifest = (await import(pathToFileURL(join82(appDir, "chelonia.json")).toString(), { + currentManifest = (await import(pathToFileURL(join72(appDir, "chelonia.json")).toString(), { with: { type: "json" } })).default; } catch { @@ -75074,40 +74816,46 @@ async function startServer() { return { uri }; } async function stopServer() { - if (currentPushHeartbeatIntervalID !== void 0) { - clearInterval(currentPushHeartbeatIntervalID); - currentPushHeartbeatIntervalID = void 0; - } - if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { - await esm_default("backend/server/stopRateLimiters"); - } - const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); - if (pubsub) { - pubsub.clients.forEach((client) => client.terminate()); - pubsub.close(); - esm_default("okTurtles.data/delete", PUBSUB_INSTANCE); - } - if (currentHttpServer) { - await new Promise((resolve82, reject) => { - currentHttpServer.close((err) => { - if (err) { - reject(err); - } else { - resolve82(); - } + if (isStopping) return; + isStopping = true; + try { + if (currentPushHeartbeatIntervalID !== void 0) { + clearInterval(currentPushHeartbeatIntervalID); + currentPushHeartbeatIntervalID = void 0; + } + if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { + await esm_default("backend/server/stopRateLimiters"); + } + const pubsub = esm_default("okTurtles.data/get", PUBSUB_INSTANCE); + if (pubsub) { + pubsub.clients.forEach((client) => client.terminate()); + pubsub.close(); + esm_default("okTurtles.data/delete", PUBSUB_INSTANCE); + } + if (currentHttpServer) { + await new Promise((resolve82, reject) => { + currentHttpServer.close((err) => { + if (err) { + reject(err); + } else { + resolve82(); + } + }); }); - }); - currentHttpServer = null; + currentHttpServer = null; + } + await Promise.all([ + currentOwnerSizeTotalWorker?.terminate(), + currentCreditsWorker?.terminate() + ]); + currentOwnerSizeTotalWorker = void 0; + currentCreditsWorker = void 0; + await closeDB(); + currentApp = null; + currentManifest = void 0; + } finally { + isStopping = false; } - await Promise.all([ - currentOwnerSizeTotalWorker?.terminate(), - currentCreditsWorker?.terminate() - ]); - currentOwnerSizeTotalWorker = void 0; - currentCreditsWorker = void 0; - await closeDB(); - currentApp = null; - currentManifest = void 0; } var app = new Proxy({}, { get(_target, prop) { @@ -75226,6 +74974,275 @@ async function startServer2(options2 = {}) { async function stopServer2() { await stopServer(); } +var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; +var getMimeType = (filename, mimes = baseMimes) => { + const regexp = /\.([a-zA-Z0-9]+?)$/; + const match2 = filename.match(regexp); + if (!match2) { + return; + } + let mimeType = mimes[match2[1].toLowerCase()]; + if (mimeType && mimeType.startsWith("text")) { + mimeType += "; charset=utf-8"; + } + return mimeType; +}; +var _baseMimes = { + aac: "audio/aac", + avi: "video/x-msvideo", + avif: "image/avif", + av1: "video/av1", + bin: "application/octet-stream", + bmp: "image/bmp", + css: "text/css", + csv: "text/csv", + eot: "application/vnd.ms-fontobject", + epub: "application/epub+zip", + gif: "image/gif", + gz: "application/gzip", + htm: "text/html", + html: "text/html", + ico: "image/x-icon", + ics: "text/calendar", + jpeg: "image/jpeg", + jpg: "image/jpeg", + js: "text/javascript", + json: "application/json", + jsonld: "application/ld+json", + map: "application/json", + mid: "audio/x-midi", + midi: "audio/x-midi", + mjs: "text/javascript", + mp3: "audio/mpeg", + mp4: "video/mp4", + mpeg: "video/mpeg", + oga: "audio/ogg", + ogv: "video/ogg", + ogx: "application/ogg", + opus: "audio/opus", + otf: "font/otf", + pdf: "application/pdf", + png: "image/png", + rtf: "application/rtf", + svg: "image/svg+xml", + tif: "image/tiff", + tiff: "image/tiff", + ts: "video/mp2t", + ttf: "font/ttf", + txt: "text/plain", + wasm: "application/wasm", + webm: "video/webm", + weba: "audio/webm", + webmanifest: "application/manifest+json", + webp: "image/webp", + woff: "font/woff", + woff2: "font/woff2", + xhtml: "application/xhtml+xml", + xml: "application/xml", + zip: "application/zip", + "3gp": "video/3gpp", + "3g2": "video/3gpp2", + gltf: "model/gltf+json", + glb: "model/gltf-binary" +}; +var baseMimes = _baseMimes; +var defaultJoin = (...paths) => { + let result = paths.filter((p) => p !== "").join("/"); + result = result.replace(/(?<=\/)\/+/g, ""); + const segments = result.split("/"); + const resolved = []; + for (const segment of segments) { + if (segment === ".." && resolved.length > 0 && resolved.at(-1) !== "..") { + resolved.pop(); + } else if (segment !== ".") { + resolved.push(segment); + } + } + return resolved.join("/") || "."; +}; +var ENCODINGS = { + br: ".br", + zstd: ".zst", + gzip: ".gz" +}; +var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS); +var DEFAULT_DOCUMENT = "index.html"; +var serveStatic = (options2) => { + const root = options2.root ?? "./"; + const optionPath = options2.path; + const join10 = options2.join ?? defaultJoin; + return async (c, next) => { + if (c.finalized) { + return next(); + } + let filename; + if (options2.path) { + filename = options2.path; + } else { + try { + filename = tryDecodeURI(c.req.path); + if (/(?:^|[\/\\])\.{1,2}(?:$|[\/\\])|[\/\\]{2,}/.test(filename)) { + throw new Error(); + } + } catch { + await options2.onNotFound?.(c.req.path, c); + return next(); + } + } + let path8 = join10( + root, + !optionPath && options2.rewriteRequestPath ? options2.rewriteRequestPath(filename) : filename + ); + if (options2.isDir && await options2.isDir(path8)) { + path8 = join10(path8, DEFAULT_DOCUMENT); + } + const getContent = options2.getContent; + let content = await getContent(path8, c); + if (content instanceof Response) { + return c.newResponse(content.body, content); + } + if (content) { + const mimeType = options2.mimes && getMimeType(path8, options2.mimes) || getMimeType(path8); + c.header("Content-Type", mimeType || "application/octet-stream"); + if (options2.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) { + const acceptEncodingSet = new Set( + c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim()) + ); + for (const encoding of ENCODINGS_ORDERED_KEYS) { + if (!acceptEncodingSet.has(encoding)) { + continue; + } + const compressedContent = await getContent(path8 + ENCODINGS[encoding], c); + if (compressedContent) { + content = compressedContent; + c.header("Content-Encoding", encoding); + c.header("Vary", "Accept-Encoding", { append: true }); + break; + } + } + } + await options2.onFound?.(path8, c); + return c.body(content); + } + await options2.onNotFound?.(path8, c); + await next(); + return; + }; +}; +var { open, lstatSync, errors } = Deno; +var serveStatic2 = (options2) => { + return async function serveStatic22(c, next) { + const getContent = async (path8) => { + try { + if (isDir(path8)) { + return null; + } + const file = await open(path8); + return file.readable; + } catch (e2) { + if (!(e2 instanceof errors.NotFound)) { + console.warn(`${e2}`); + } + return null; + } + }; + const isDir = (path8) => { + let isDir2; + try { + const stat = lstatSync(path8); + isDir2 = stat.isDirectory; + } catch { + } + return isDir2; + }; + return serveStatic({ + ...options2, + getContent, + join: join82, + isDir + })(c, next); + }; +}; +var X_HONO_DISABLE_SSG_HEADER_KEY = "x-hono-disable-ssg"; +var SSG_DISABLED_RESPONSE = (() => { + try { + return new Response("SSG is disabled", { + status: 404, + headers: { [X_HONO_DISABLE_SSG_HEADER_KEY]: "true" } + }); + } catch { + return null; + } +})(); +var WSContext = class { + #init; + constructor(init2) { + this.#init = init2; + this.raw = init2.raw; + this.url = init2.url ? new URL(init2.url) : null; + this.protocol = init2.protocol ?? null; + } + send(source, options2) { + this.#init.send(source, options2 ?? {}); + } + raw; + binaryType = "arraybuffer"; + get readyState() { + return this.#init.readyState; + } + url; + protocol; + close(code2, reason) { + this.#init.close(code2, reason); + } +}; +var defineWebSocketHelper = (handler) => { + return (...args) => { + if (typeof args[0] === "function") { + const [createEvents, options2] = args; + return async function upgradeWebSocket2(c, next) { + const events = await createEvents(c); + const result = await handler(c, events, options2); + if (result) { + return result; + } + await next(); + }; + } else { + const [c, events, options2] = args; + return (async () => { + const upgraded = await handler(c, events, options2); + if (!upgraded) { + throw new Error("Failed to upgrade WebSocket"); + } + return upgraded; + })(); + } + }; +}; +var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { + if (c.req.header("upgrade") !== "websocket") { + return; + } + const { response, socket } = Deno.upgradeWebSocket(c.req.raw, options2 ?? {}); + const wsContext = new WSContext({ + close: (code2, reason) => socket.close(code2, reason), + get protocol() { + return socket.protocol; + }, + raw: socket, + get readyState() { + return socket.readyState; + }, + url: socket.url ? new URL(socket.url) : null, + send: (source) => socket.send(source) + }); + socket.onopen = (evt) => events.onOpen?.(evt, wsContext); + socket.onmessage = (evt) => events.onMessage?.(evt, wsContext); + socket.onclose = (evt) => events.onClose?.(evt, wsContext); + socket.onerror = (evt) => events.onError?.(evt, wsContext); + return response; +}); var import_npm_nconf6 = __toESM(require_nconf()); var getDashboardPath = () => { const baseDir = import.meta.dirname || path6.join(process11.cwd(), "build"); @@ -75237,16 +75254,18 @@ async function startDashboard() { const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; const dashboardRoot = getDashboardPath(); const app2 = new Hono2(); - app2.get("/assets/*", serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })); - app2.get("/dashboard", serveStatic2({ path: path6.join(dashboardRoot, "index.html") })); - app2.get("/dashboard/", serveStatic2({ path: path6.join(dashboardRoot, "index.html") })); + const staticMiddleware = serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p }); + const indexMiddleware = serveStatic2({ path: path6.join(dashboardRoot, "index.html") }); + app2.get("/assets/*", staticMiddleware); + app2.get("/dashboard", indexMiddleware); + app2.get("/dashboard/", indexMiddleware); app2.get("/*", async (c) => { - const staticResponse = await serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p })(c, async () => { + const staticResponse = await staticMiddleware(c, async () => { }); if (staticResponse) { return staticResponse; } - const indexResponse = await serveStatic2({ path: path6.join(dashboardRoot, "index.html") })(c, async () => { + const indexResponse = await indexMiddleware(c, async () => { }); return indexResponse || c.text("Not Found", 404); }); diff --git a/scripts/build.ts b/scripts/build.ts index 183db86..5e1eef1 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -52,7 +52,7 @@ console.log(colors.green('built:'), options.outdir) import { builtinModules } from 'node:module' const nodeBuiltins = new Set(builtinModules.filter((m: string) => !m.startsWith('_'))) -const bareBuiltinRe = /\bfrom\s+"([^"]+)"/g +const bareBuiltinRe = /\bfrom\s+["']([^"']+)["']/g function addNodePrefix (source: string): string { return source.replace(bareBuiltinRe, (match, specifier) => { diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index 149a6a1..cf2529d 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -20,20 +20,24 @@ export async function startDashboard (): Promise { const app = new Hono() - app.get('/assets/*', serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })) + // Cache middleware instances to avoid creating new ones on every request + const staticMiddleware = serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p }) + const indexMiddleware = serveStatic({ path: path.join(dashboardRoot, 'index.html') }) - app.get('/dashboard', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) - app.get('/dashboard/', serveStatic({ path: path.join(dashboardRoot, 'index.html') })) + app.get('/assets/*', staticMiddleware) + + app.get('/dashboard', indexMiddleware) + app.get('/dashboard/', indexMiddleware) // SPA fallback: try static file first, then serve index.html for SPA routing app.get('/*', async (c) => { - const staticResponse = await serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p })(c, async () => {}) + const staticResponse = await staticMiddleware(c, async () => {}) // If static file exists and was served successfully, return it if (staticResponse) { return staticResponse } // File not found, serve index.html for SPA routing - const indexResponse = await serveStatic({ path: path.join(dashboardRoot, 'index.html') })(c, async () => {}) + const indexResponse = await indexMiddleware(c, async () => {}) return indexResponse || c.text('Not Found', 404) }) diff --git a/src/serve/database.ts b/src/serve/database.ts index 2f0b6f2..080eab6 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -23,6 +23,7 @@ const production = process.env.NODE_ENV === 'production' // backend + cache without needing to re-overwrite the selectors. let currentBackend: DatabaseBackend | null = null let currentCache: LRU | null = null +let isClosing = false let baseSelectorsInstalled = false function installBaseSelectorsOnce () { @@ -335,17 +336,23 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } export async function closeDB (): Promise { - if (currentBackend) { - try { - await currentBackend.close() - } catch (e) { - console.error(e, 'Error closing DB') + if (isClosing) return + isClosing = true + try { + if (currentBackend) { + try { + await currentBackend.close() + } catch (e) { + console.error(e, 'Error closing DB') + } + currentBackend = null } - currentBackend = null + currentCache?.clear() + currentCache = null + initedDB = false + } finally { + isClosing = false } - currentCache?.clear() - currentCache = null - initedDB = false } export * from './db-utils.ts' diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 7d7aa9c..e5bfb72 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -5,22 +5,22 @@ import { SPMessage } from 'npm:@chelonia/lib/SPMessage' import 'npm:@chelonia/lib/chelonia' import { blake32Hash, createCID, maybeParseCID, multicodes } from 'npm:@chelonia/lib/functions' import 'npm:@chelonia/lib/persistent-actions' +import { getConnInfo } from 'npm:@hono/node-server/conninfo' import sbp from 'npm:@sbp/sbp' import Bottleneck from 'npm:bottleneck' import chalk from 'npm:chalk' -import { getConnInfo } from 'npm:hono/deno' import { HTTPException } from 'npm:hono/http-exception' // TODO: Use logger for debugging route handlers import { isIP } from 'node:net' import path from 'node:path' import process from 'node:process' -import { appendToIndexFactory, lookupUltimateOwner } from './database.ts' -import logger from './logger.ts' -import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' import { Readable } from 'node:stream' import { zValidator } from 'npm:@hono/zod-validator' import type { Context, Hono, MiddlewareHandler } from 'npm:hono' import { bodyLimit } from 'npm:hono/body-limit' +import { appendToIndexFactory, lookupUltimateOwner } from './database.ts' +import logger from './logger.ts' +import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' import * as z from 'npm:zod' @@ -1144,12 +1144,12 @@ app.post('/name', async function (c) { app.post('/zkpp/:contractID/updatePasswordHash', zValidator('param', zkppContractParamSchema), - zValidator('json', zkppUpdatePasswordBodySchema), + zValidatorFormOrJson(zkppUpdatePasswordBodySchema), async function (c) { const { contractID } = c.req.valid('param') if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { - const payload = c.req.valid('json') + const payload = c.get('validatedBody') as z.infer const result = await updateContractSalt(contractID, payload.r, payload.s, payload.sig, payload.hc, payload.Ea) if (result) { diff --git a/src/serve/server.ts b/src/serve/server.ts index 1712036..1379d7e 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -45,6 +45,7 @@ let currentOwnerSizeTotalWorker: ReturnType | undefined = u let currentCreditsWorker: ReturnType | undefined = undefined let currentManifest: Record | undefined = undefined let currentPushHeartbeatIntervalID: ReturnType | undefined = undefined +let isStopping = false // Helper for appending to orphaned names index (stateless) const appendToOrphanedNamesIndex = appendToIndexFactory('_private_orphaned_names_index') @@ -639,53 +640,59 @@ export async function startServer (): Promise<{ uri: string }> { } export async function stopServer (): Promise { - // Clear push-heartbeat interval - if (currentPushHeartbeatIntervalID !== undefined) { - clearInterval(currentPushHeartbeatIntervalID) - currentPushHeartbeatIntervalID = undefined - } + if (isStopping) return + isStopping = true + try { + // Clear push-heartbeat interval + if (currentPushHeartbeatIntervalID !== undefined) { + clearInterval(currentPushHeartbeatIntervalID) + currentPushHeartbeatIntervalID = undefined + } - // Stop rate limiters if registered - if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { - await sbp('backend/server/stopRateLimiters') - } + // Stop rate limiters if registered + if (sbp('sbp/selectors/fn', 'backend/server/stopRateLimiters')) { + await sbp('backend/server/stopRateLimiters') + } - // Close pubsub server (clears its ping interval) - const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as { close: () => void; clients: Set<{ terminate: () => void }> } | undefined - if (pubsub) { - pubsub.clients.forEach((client) => client.terminate()) - pubsub.close() - sbp('okTurtles.data/delete', PUBSUB_INSTANCE) - } + // Close pubsub server (clears its ping interval) + const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as { close: () => void; clients: Set<{ terminate: () => void }> } | undefined + if (pubsub) { + pubsub.clients.forEach((client) => client.terminate()) + pubsub.close() + sbp('okTurtles.data/delete', PUBSUB_INSTANCE) + } - // Close HTTP server - if (currentHttpServer) { - await new Promise((resolve, reject) => { - currentHttpServer!.close((err) => { - if (err) { - reject(err) - } else { - resolve() - } + // Close HTTP server + if (currentHttpServer) { + await new Promise((resolve, reject) => { + currentHttpServer!.close((err) => { + if (err) { + reject(err) + } else { + resolve() + } + }) }) - }) - currentHttpServer = null - } - - // Terminate workers - await Promise.all([ - currentOwnerSizeTotalWorker?.terminate(), - currentCreditsWorker?.terminate() - ]) - currentOwnerSizeTotalWorker = undefined - currentCreditsWorker = undefined - - // Close database - await closeDB() + currentHttpServer = null + } - // Clear app and manifest - currentApp = null - currentManifest = undefined + // Terminate workers + await Promise.all([ + currentOwnerSizeTotalWorker?.terminate(), + currentCreditsWorker?.terminate() + ]) + currentOwnerSizeTotalWorker = undefined + currentCreditsWorker = undefined + + // Close database + await closeDB() + + // Clear app and manifest + currentApp = null + currentManifest = undefined + } finally { + isStopping = false + } } // Legacy: export the Hono app for backwards compatibility (deprecated) From b220cc0f6e900eab387cbdead31930747a8bdfc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Fri, 17 Apr 2026 23:59:35 +0000 Subject: [PATCH 30/71] Feedback --- scripts/build.ts | 4 ++-- src/serve/routes.ts | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/scripts/build.ts b/scripts/build.ts index 5e1eef1..45453f5 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -52,10 +52,10 @@ console.log(colors.green('built:'), options.outdir) import { builtinModules } from 'node:module' const nodeBuiltins = new Set(builtinModules.filter((m: string) => !m.startsWith('_'))) -const bareBuiltinRe = /\bfrom\s+["']([^"']+)["']/g +const bareBuiltinRe = /\bfrom\s+(["'])([^"']+)\1/g function addNodePrefix (source: string): string { - return source.replace(bareBuiltinRe, (match, specifier) => { + return source.replace(bareBuiltinRe, (match, _, specifier) => { return nodeBuiltins.has(specifier) ? `from "node:${specifier}"` : match }) } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index e5bfb72..227206e 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -242,24 +242,23 @@ export function getStaticServeConfig () { const appDir = nconf.get('server:appDir') || '.' const dashboardDir = import.meta.dirname || './build/dist-dashboard' return { - routePath: isCheloniaDashboard ? '/dashboard/{path*}' : '/app/{path*}', distAssets: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'assets')), distIndexHtml: path.resolve(path.join(isCheloniaDashboard ? dashboardDir : appDir, 'index.html')), redirect: isCheloniaDashboard ? '/dashboard/' : '/app/' } } -const errorMapper = (e: Error): never => { +const errorMapper = (e: Error): HTTPException => { switch (e?.name) { case 'BackendErrorNotFound': - throw new HTTPException(404) + return new HTTPException(404) case 'BackendErrorGone': - throw new HTTPException(410) + return new HTTPException(410) case 'BackendErrorBadData': - throw new HTTPException(422, { message: e.message }) + return new HTTPException(422, { message: e.message }) default: console.error(e, 'Unexpected backend error') - throw new HTTPException(500, { message: e.message ?? 'internal error' }) + return new HTTPException(500, { message: e.message ?? 'internal error' }) } } @@ -511,7 +510,7 @@ export function registerRoutes (app: Hono): void { if (err instanceof HTTPException) throw err ;(err as unknown as { ip: string }).ip = ip logger.error(err, `GET /eventsAfter/${contractID}/${since}`, (err as Error).message) - errorMapper(err as Error) + throw errorMapper(err as Error) } }) @@ -856,7 +855,7 @@ app.post('/name', async function (c) { await sbp('backend/deleteFile', hash, null, true) return c.body(null, 200) } catch (e) { - errorMapper(e as Error) + throw errorMapper(e as Error) } }) @@ -914,7 +913,7 @@ app.post('/name', async function (c) { // TODO: Tracking progress not yet implemented return c.json({ id }, 202) } catch (e) { - errorMapper(e as Error) + throw errorMapper(e as Error) } }) @@ -1040,14 +1039,14 @@ app.post('/name', async function (c) { // SPA routes - app.get('/assets/:subpath{.+}', async function (c) { + app.get('/assets/:subpath{.+}', function (c) { const subpath = c.req.param('subpath') return serveAsset(c, subpath, staticServeConfig.distAssets) }) // Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) if (isCheloniaDashboard) { - app.get('/dashboard/assets/:subpath{.+}', async function (c) { + app.get('/dashboard/assets/:subpath{.+}', function (c) { const subpath = c.req.param('subpath') return serveAsset(c, subpath, staticServeConfig.distAssets) }) From 8219614ff9e14dc6ccb6a8714474a599469ebd78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 00:09:46 +0000 Subject: [PATCH 31/71] Build --- build/main.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/build/main.js b/build/main.js index 61d57dc..21af8a3 100644 --- a/build/main.js +++ b/build/main.js @@ -73026,7 +73026,6 @@ function getStaticServeConfig() { const appDir = import_npm_nconf4.default.get("server:appDir") || "."; const dashboardDir = import.meta.dirname || "./build/dist-dashboard"; return { - routePath: isCheloniaDashboard ? "/dashboard/{path*}" : "/app/{path*}", distAssets: path5.resolve(path5.join(isCheloniaDashboard ? dashboardDir : appDir, "assets")), distIndexHtml: path5.resolve(path5.join(isCheloniaDashboard ? dashboardDir : appDir, "index.html")), redirect: isCheloniaDashboard ? "/dashboard/" : "/app/" @@ -73035,14 +73034,14 @@ function getStaticServeConfig() { var errorMapper = (e2) => { switch (e2?.name) { case "BackendErrorNotFound": - throw new HTTPException(404); + return new HTTPException(404); case "BackendErrorGone": - throw new HTTPException(410); + return new HTTPException(410); case "BackendErrorBadData": - throw new HTTPException(422, { message: e2.message }); + return new HTTPException(422, { message: e2.message }); default: console.error(e2, "Unexpected backend error"); - throw new HTTPException(500, { message: e2.message ?? "internal error" }); + return new HTTPException(500, { message: e2.message ?? "internal error" }); } }; function getClientIP(c) { @@ -73245,7 +73244,7 @@ function registerRoutes(app2) { if (err instanceof HTTPException) throw err; err.ip = ip; logger_default.error(err, `GET /eventsAfter/${contractID}/${since}`, err.message); - errorMapper(err); + throw errorMapper(err); } } ); @@ -73501,7 +73500,7 @@ function registerRoutes(app2) { await esm_default("backend/deleteFile", hash3, null, true); return c.body(null, 200); } catch (e2) { - errorMapper(e2); + throw errorMapper(e2); } } ); @@ -73549,7 +73548,7 @@ function registerRoutes(app2) { } return c.json({ id }, 202); } catch (e2) { - errorMapper(e2); + throw errorMapper(e2); } } ); @@ -73652,12 +73651,12 @@ function registerRoutes(app2) { if (!messages) return c.json([]); return c.json(messages, 200, { "Cache-Control": "no-store" }); }); - app2.get("/assets/:subpath{.+}", async function(c) { + app2.get("/assets/:subpath{.+}", function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); if (isCheloniaDashboard) { - app2.get("/dashboard/assets/:subpath{.+}", async function(c) { + app2.get("/dashboard/assets/:subpath{.+}", function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); From 07da7a740e7eb9e8446de42b4bc115c0d3746e3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:06:46 +0000 Subject: [PATCH 32/71] Fix tests --- src/serve/routes-zkpp.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index 73a7f69..143f404 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -145,7 +145,7 @@ Deno.test({ body: JSON.stringify({ r: publicKey, s: step1.s, sig: step1.sig, Eh: encryptedHashedPassword }) }) if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) - const encryptedToken = (await res2.text()).replace(/^"|"$/g, '') + const encryptedToken = await res2.text() const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) @@ -177,10 +177,10 @@ Deno.test({ const encryptedSalt = await saltRes.text() if (!encryptedSalt) throw new Error('Expected encrypted salt response') - const saltBuf = Buffer.from(encryptedSalt.replace(/^"|"$/g, ''), 'base64url') - const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const saltBuf = Buffer.from(encryptedSalt, 'base64url') + const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) - const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + const decrypted = nacl.secretbox.open(saltBuf.subarray(nacl.secretbox.nonceLength), nonce, encryptionKey) if (!decrypted) throw new Error('Failed to decrypt contract salt') const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') @@ -270,7 +270,7 @@ Deno.test({ }).toString() }) if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) - const encryptedToken = (await res2.text()).replace(/^"|"$/g, '') + const encryptedToken = (await res2.text()) const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) @@ -300,10 +300,10 @@ Deno.test({ const encryptedSalt = await saltRes.text() if (!encryptedSalt) throw new Error('Expected encrypted salt response') - const saltBuf = Buffer.from(encryptedSalt.replace(/^"|"$/g, ''), 'base64url') - const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const saltBuf = Buffer.from(encryptedSalt, 'base64url') + const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) - const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + const decrypted = nacl.secretbox.open(saltBuf.subarray(nacl.secretbox.nonceLength), nonce, encryptionKey) if (!decrypted) throw new Error('Failed to decrypt contract salt') const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') From e5c8b75abf365ecedb3e69fc4e567b29612c3104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:30:43 +0000 Subject: [PATCH 33/71] Add character set validation --- src/serve/routes-zkpp.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index 143f404..b9a2faf 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -62,6 +62,7 @@ Deno.test({ if (res2.status !== 200) throw new Error(`Step 2 failed: ${res2.status}`) const token = await res2.text() if (!token) throw new Error('Expected registration token') + if (/[^\da-zA-Z_-]/.test(token)) throw new Error('Unexpected registration token characters') }) await t.step('POST /zkpp/register with invalid name returns 400', async () => { @@ -146,6 +147,7 @@ Deno.test({ }) if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) const encryptedToken = await res2.text() + if (/[^\dA-Za-z_-]/.test(encryptedToken)) throw new Error('Invalid characters in encrypted token') const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) @@ -175,6 +177,7 @@ Deno.test({ ) if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) const encryptedSalt = await saltRes.text() + if (/[^\dA-Za-z_-]/.test(encryptedSalt)) throw new Error('Invalid characters in encrypted salt') if (!encryptedSalt) throw new Error('Expected encrypted salt response') const saltBuf = Buffer.from(encryptedSalt, 'base64url') @@ -230,6 +233,7 @@ Deno.test({ if (res2.status !== 200) throw new Error(`Step 2 failed: ${res2.status}`) const token = await res2.text() if (!token) throw new Error('Expected registration token') + if (/[^\da-zA-Z_-]/.test(token)) throw new Error('Unexpected characters in registration token') }) await t.step('POST /zkpp/{contractID}/updatePasswordHash with form-urlencoded body returns 400 for missing params', async () => { @@ -271,6 +275,7 @@ Deno.test({ }) if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) const encryptedToken = (await res2.text()) + if (/[^\da-zA-Z_-]/.test(encryptedToken)) throw new Error('Unexpected characters in encrypted token') const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) @@ -299,6 +304,7 @@ Deno.test({ if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) const encryptedSalt = await saltRes.text() if (!encryptedSalt) throw new Error('Expected encrypted salt response') + if (/[^\da-zA-Z_-]/.test(encryptedSalt)) throw new Error('Unexpected characters in encrypted salt') const saltBuf = Buffer.from(encryptedSalt, 'base64url') const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) From 1976411de22da40749ec66141f2a2eca28a86a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 01:34:39 +0000 Subject: [PATCH 34/71] Update return types --- build/main.js | 4 ++-- src/serve/routes.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/main.js b/build/main.js index 21af8a3..ca7608c 100644 --- a/build/main.js +++ b/build/main.js @@ -73693,7 +73693,7 @@ function registerRoutes(app2) { } else { const result = register(name, payload.r, payload.s, payload.sig, payload.Eh); if (result) { - return c.json(result); + return c.text(result); } } } catch (e2) { @@ -73732,7 +73732,7 @@ function registerRoutes(app2) { try { const salt = await getContractSalt(contractID, r, s, sig, hc); if (salt) { - return c.json(salt); + return c.text(salt); } } catch (e2) { ; diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 227206e..83559e0 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -1091,7 +1091,7 @@ app.post('/name', async function (c) { const result = register(name, payload.r, payload.s, payload.sig, payload.Eh) if (result) { - return c.json(result) + return c.text(result) } } } catch (e) { @@ -1131,7 +1131,7 @@ app.post('/name', async function (c) { const salt = await getContractSalt(contractID, r, s, sig, hc) if (salt) { - return c.json(salt) + return c.text(salt) } } catch (e) { ;(e as { ip: string }).ip = getClientIP(c) From a925f54dd8660d258cb3dfafeb7b09ac730f4527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:05:45 +0000 Subject: [PATCH 35/71] Feedback --- build/main.js | 144 +++++++++++++++------------- build/serve/creditsWorker.js | 30 +++--- build/serve/ownerSizeTotalWorker.js | 30 +++--- scripts/build.ts | 29 +++--- src/serve/routes.ts | 13 ++- 5 files changed, 133 insertions(+), 113 deletions(-) diff --git a/build/main.js b/build/main.js index ca7608c..3b9b282 100644 --- a/build/main.js +++ b/build/main.js @@ -6453,7 +6453,7 @@ var require_memory = __commonJS({ }); var require_common = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf/common.js"(exports2) { - var fs = __require2("fs"); + var fs = __require2("node:fs"); var async = require_async(); var formats = require_formats(); var Memory = require_memory().Memory; @@ -6934,9 +6934,9 @@ var require_package = __commonJS({ var require_build = __commonJS({ "node_modules/.deno/y18n@5.0.8/node_modules/y18n/build/index.cjs"(exports2, module14) { "use strict"; - var fs = __require2("fs"); - var util = __require2("util"); - var path8 = __require2("path"); + var fs = __require2("node:fs"); + var util = __require2("node:util"); + var path8 = __require2("node:path"); var shim4; var Y18N2 = class { constructor(opts) { @@ -7120,9 +7120,9 @@ var require_build = __commonJS({ var require_build2 = __commonJS({ "node_modules/.deno/yargs-parser@20.2.9/node_modules/yargs-parser/build/index.cjs"(exports2, module14) { "use strict"; - var util = __require2("util"); - var fs = __require2("fs"); - var path8 = __require2("path"); + var util = __require2("node:util"); + var fs = __require2("node:fs"); + var path8 = __require2("node:path"); function camelCase2(str) { const isCamelCase = str !== str.toLowerCase() && str !== str.toUpperCase(); if (!isCamelCase) { @@ -9695,8 +9695,8 @@ var require_build3 = __commonJS({ }); var require_sync = __commonJS({ "node_modules/.deno/escalade@3.2.0/node_modules/escalade/sync/index.js"(exports2, module14) { - var { dirname: dirname82, resolve: resolve82 } = __require2("path"); - var { readdirSync: readdirSync2, statSync: statSync3 } = __require2("fs"); + var { dirname: dirname82, resolve: resolve82 } = __require2("node:path"); + var { readdirSync: readdirSync2, statSync: statSync3 } = __require2("node:fs"); module14.exports = function(start, callback) { let dir = resolve82(".", start); let tmp, stats = statSync3(dir); @@ -9737,10 +9737,10 @@ var require_get_caller_file = __commonJS({ var require_require_directory = __commonJS({ "node_modules/.deno/require-directory@2.1.1/node_modules/require-directory/index.js"(exports2, module14) { "use strict"; - var fs = __require2("fs"); - var join10 = __require2("path").join; - var resolve82 = __require2("path").resolve; - var dirname82 = __require2("path").dirname; + var fs = __require2("node:fs"); + var join10 = __require2("node:path").join; + var resolve82 = __require2("node:path").resolve; + var dirname82 = __require2("node:path").dirname; var defaultOptions4 = { extensions: ["js", "json", "coffee"], recurse: true, @@ -9798,7 +9798,7 @@ var require_require_directory = __commonJS({ var require_build4 = __commonJS({ "node_modules/.deno/yargs@16.2.0/node_modules/yargs/build/index.cjs"(exports2, module14) { "use strict"; - var assert2 = __require2("assert"); + var assert2 = __require2("node:assert"); var YError2 = class _YError2 extends Error { constructor(msg) { super(msg || "yargs error"); @@ -12436,9 +12436,9 @@ ${customMsgs.join("\n")}` : ""; } var _a2; var _b; - var { readFileSync: readFileSync4 } = __require2("fs"); - var { inspect: inspect2 } = __require2("util"); - var { resolve: resolve82 } = __require2("path"); + var { readFileSync: readFileSync4 } = __require2("node:fs"); + var { inspect: inspect2 } = __require2("node:util"); + var { resolve: resolve82 } = __require2("node:path"); var y18n3 = require_build(); var Parser2 = require_build2(); var cjsPlatformShim = { @@ -12456,7 +12456,7 @@ ${customMsgs.join("\n")}` : ""; inspect: inspect2, mainFilename: (_b = (_a2 = __require2 === null || __require2 === void 0 ? void 0 : __require2.main) === null || _a2 === void 0 ? void 0 : _a2.filename) !== null && _b !== void 0 ? _b : process.cwd(), Parser: Parser2, - path: __require2("path"), + path: __require2("node:path"), process: { argv: () => process.argv, cwd: process.cwd, @@ -12533,7 +12533,7 @@ var require_yargs = __commonJS({ }); var require_argv = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf/stores/argv.js"(exports2) { - var util = __require2("util"); + var util = __require2("node:util"); var common4 = require_common(); var Memory = require_memory().Memory; var Argv = exports2.Argv = function(options2, usage2) { @@ -12606,7 +12606,7 @@ var require_argv = __commonJS({ }); var require_env = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf/stores/env.js"(exports2) { - var util = __require2("util"); + var util = __require2("node:util"); var common4 = require_common(); var Memory = require_memory().Memory; var Env = exports2.Env = function(options2) { @@ -12682,7 +12682,7 @@ var require_env = __commonJS({ var require_secure_keys = __commonJS({ "node_modules/.deno/secure-keys@1.0.0/node_modules/secure-keys/index.js"(exports2, module14) { "use strict"; - var crypto3 = __require2("crypto"); + var crypto3 = __require2("node:crypto"); var json = { stringify: function(obj, replacer, spacing) { return JSON.stringify(obj, replacer || null, spacing || 2); @@ -12733,9 +12733,9 @@ var require_secure_keys = __commonJS({ }); var require_file = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf/stores/file.js"(exports2) { - var fs = __require2("fs"); - var path8 = __require2("path"); - var util = __require2("util"); + var fs = __require2("node:fs"); + var path8 = __require2("node:path"); + var util = __require2("node:util"); var Secure = require_secure_keys(); var formats = require_formats(); var Memory = require_memory().Memory; @@ -12889,7 +12889,7 @@ var require_file = __commonJS({ }); var require_literal = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf/stores/literal.js"(exports2) { - var util = __require2("util"); + var util = __require2("node:util"); var Memory = require_memory().Memory; var Literal = exports2.Literal = function Literal2(options2) { Memory.call(this, options2); @@ -22081,7 +22081,7 @@ var require_nacl_fast = __commonJS({ cleanup(v2); }); } else if (typeof __require2 !== "undefined") { - crypto3 = __require2("crypto"); + crypto3 = __require2("node:crypto"); if (crypto3 && crypto3.randomBytes) { nacl4.setPRNG(function(x3, n) { var i2, v2 = crypto3.randomBytes(n); @@ -37493,8 +37493,8 @@ var require_enterprise_maintenance_manager = __commonJS({ }; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.emitDiagnostics = exports2.dbgMaintenance = exports2.MAINTENANCE_EVENTS = void 0; - var net_1 = __require2("net"); - var promises_1 = __require2("dns/promises"); + var net_1 = __require2("node:net"); + var promises_1 = __require2("node:dns/promises"); var node_assert_1 = __importDefault(__require2("node:assert")); var promises_2 = __require2("node:timers/promises"); var node_diagnostics_channel_1 = __importDefault(__require2("node:diagnostics_channel")); @@ -38283,7 +38283,7 @@ var require_linked_list = __commonJS({ }; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.EmptyAwareSinglyLinkedList = exports2.SinglyLinkedList = exports2.DoublyLinkedList = void 0; - var events_1 = __importDefault(__require2("events")); + var events_1 = __importDefault(__require2("node:events")); var DoublyLinkedList = class { #length = 0; get length() { @@ -39575,7 +39575,7 @@ var require_cache = __commonJS({ "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); exports2.PooledNoRedirectClientSideCache = exports2.BasicPooledClientSideCache = exports2.PooledClientSideCacheProvider = exports2.BasicClientSideCache = exports2.ClientSideCacheProvider = exports2.CacheStats = void 0; - var stream_1 = __require2("stream"); + var stream_1 = __require2("node:stream"); var CacheStats = class _CacheStats { hitCount; missCount; @@ -50684,8 +50684,8 @@ var require_has_flag = __commonJS({ var require_supports_color = __commonJS({ "node_modules/.deno/supports-color@7.2.0/node_modules/supports-color/index.js"(exports2, module14) { "use strict"; - var os = __require2("os"); - var tty = __require2("tty"); + var os = __require2("node:os"); + var tty = __require2("node:tty"); var hasFlag = require_has_flag(); var { env: env2 } = process; var forceColor; @@ -55164,10 +55164,10 @@ var require_atomic_sleep = __commonJS({ var require_sonic_boom = __commonJS({ "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports2, module14) { "use strict"; - var fs = __require2("fs"); - var EventEmitter = __require2("events"); - var inherits = __require2("util").inherits; - var path8 = __require2("path"); + var fs = __require2("node:fs"); + var EventEmitter = __require2("node:events"); + var inherits = __require2("node:util").inherits; + var path8 = __require2("node:path"); var sleep = require_atomic_sleep(); var BUSY_WRITE_TIMEOUT = 100; var kEmptyBuffer = Buffer.allocUnsafe(0); @@ -55933,17 +55933,17 @@ var require_thread_stream = __commonJS({ "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports2, module14) { "use strict"; var { version: version3 } = require_package3(); - var { EventEmitter } = __require2("events"); - var { Worker: Worker2 } = __require2("worker_threads"); - var { join: join10 } = __require2("path"); - var { pathToFileURL: pathToFileURL2 } = __require2("url"); + var { EventEmitter } = __require2("node:events"); + var { Worker: Worker2 } = __require2("node:worker_threads"); + var { join: join10 } = __require2("node:path"); + var { pathToFileURL: pathToFileURL2 } = __require2("node:url"); var { wait } = require_wait(); var { WRITE_INDEX, READ_INDEX } = require_indexes(); - var buffer = __require2("buffer"); - var assert2 = __require2("assert"); + var buffer = __require2("node:buffer"); + var assert2 = __require2("node:assert"); var kImpl = Symbol("kImpl"); var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; var FakeWeakRef = class { @@ -56353,9 +56353,9 @@ var require_thread_stream = __commonJS({ var require_transport = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports2, module14) { "use strict"; - var { createRequire } = __require2("module"); + var { createRequire } = __require2("node:module"); var getCallers = require_caller(); - var { join: join10, isAbsolute: isAbsolute8, sep } = __require2("path"); + var { join: join10, isAbsolute: isAbsolute8, sep } = __require2("node:path"); var sleep = require_atomic_sleep(); var onExit = require_on_exit_leak_free(); var ThreadStream = require_thread_stream(); @@ -56489,7 +56489,7 @@ var require_tools = __commonJS({ nestedKeyStrSym, msgPrefixSym } = require_symbols(); - var { isMainThread } = __require2("worker_threads"); + var { isMainThread } = __require2("node:worker_threads"); var transport = require_transport(); function noop() { } @@ -57001,7 +57001,7 @@ var require_meta = __commonJS({ var require_proto = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports2, module14) { "use strict"; - var { EventEmitter } = __require2("events"); + var { EventEmitter } = __require2("node:events"); var { lsCacheSym, levelValSym, @@ -57948,7 +57948,7 @@ var require_multistream = __commonJS({ var require_pino = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports2, module14) { "use strict"; - var os = __require2("os"); + var os = __require2("node:os"); var stdSerializers = require_pino_std_serializers(); var caller = require_caller(); var redaction = require_redaction(); @@ -58151,7 +58151,7 @@ var require_pino = __commonJS({ var require_stream = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/stream.js"(exports2, module14) { "use strict"; - var { Duplex } = __require2("stream"); + var { Duplex } = __require2("node:stream"); function emitClose(stream) { stream.emit("close"); } @@ -58383,7 +58383,7 @@ var require_limiter = __commonJS({ var require_permessage_deflate = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/permessage-deflate.js"(exports2, module14) { "use strict"; - var zlib = __require2("zlib"); + var zlib = __require2("node:zlib"); var bufferUtil = require_buffer_util(); var Limiter = require_limiter(); var { kStatusCode } = require_constants2(); @@ -58948,7 +58948,7 @@ var require_validation = __commonJS({ var require_receiver = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/receiver.js"(exports2, module14) { "use strict"; - var { Writable } = __require2("stream"); + var { Writable } = __require2("node:stream"); var PerMessageDeflate = require_permessage_deflate(); var { BINARY_TYPES, @@ -59462,9 +59462,9 @@ var require_receiver = __commonJS({ var require_sender = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/sender.js"(exports2, module14) { "use strict"; - var net = __require2("net"); - var tls = __require2("tls"); - var { randomFillSync } = __require2("crypto"); + var net = __require2("node:net"); + var tls = __require2("node:tls"); + var { randomFillSync } = __require2("node:crypto"); var PerMessageDeflate = require_permessage_deflate(); var { EMPTY_BUFFER } = require_constants2(); var { isValidStatusCode } = require_validation(); @@ -60232,14 +60232,14 @@ var require_extension = __commonJS({ var require_websocket = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket.js"(exports2, module14) { "use strict"; - var EventEmitter = __require2("events"); - var https = __require2("https"); - var http = __require2("http"); - var net = __require2("net"); - var tls = __require2("tls"); - var { randomBytes: randomBytes3, createHash } = __require2("crypto"); - var { Readable: Readable4 } = __require2("stream"); - var { URL: URL2 } = __require2("url"); + var EventEmitter = __require2("node:events"); + var https = __require2("node:https"); + var http = __require2("node:http"); + var net = __require2("node:net"); + var tls = __require2("node:tls"); + var { randomBytes: randomBytes3, createHash } = __require2("node:crypto"); + var { Readable: Readable4 } = __require2("node:stream"); + var { URL: URL2 } = __require2("node:url"); var PerMessageDeflate = require_permessage_deflate(); var Receiver2 = require_receiver(); var Sender2 = require_sender(); @@ -61097,12 +61097,12 @@ var require_subprotocol = __commonJS({ var require_websocket_server = __commonJS({ "node_modules/.deno/ws@8.5.0/node_modules/ws/lib/websocket-server.js"(exports2, module14) { "use strict"; - var EventEmitter = __require2("events"); - var http = __require2("http"); - var https = __require2("https"); - var net = __require2("net"); - var tls = __require2("tls"); - var { createHash } = __require2("crypto"); + var EventEmitter = __require2("node:events"); + var http = __require2("node:http"); + var https = __require2("node:https"); + var net = __require2("node:net"); + var tls = __require2("node:tls"); + var { createHash } = __require2("node:crypto"); var extension = require_extension(); var PerMessageDeflate = require_permessage_deflate(); var subprotocol = require_subprotocol(); @@ -72864,6 +72864,14 @@ function authMiddleware(strategies, mode = "required") { } var MEGABYTE = 1048576; var SECOND = 1e3; +function parseBooleanParam(value) { + if (value === void 0) return false; + const normalized = value.toLowerCase(); + if (normalized === "" || normalized === "true" || normalized === "yes" || normalized === "on" || normalized === "1") { + return true; + } + return false; +} var CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; var KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; var NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? stream.destroy()); const streamHeaders = stream.headers || {}; const webStream = Readable3.toWeb(stream); diff --git a/build/serve/creditsWorker.js b/build/serve/creditsWorker.js index 8f29a0d..cbc985a 100644 --- a/build/serve/creditsWorker.js +++ b/build/serve/creditsWorker.js @@ -1259,10 +1259,10 @@ var require_atomic_sleep = __commonJS({ var require_sonic_boom = __commonJS({ "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports, module) { "use strict"; - var fs = __require2("fs"); - var EventEmitter = __require2("events"); - var inherits = __require2("util").inherits; - var path = __require2("path"); + var fs = __require2("node:fs"); + var EventEmitter = __require2("node:events"); + var inherits = __require2("node:util").inherits; + var path = __require2("node:path"); var sleep = require_atomic_sleep(); var BUSY_WRITE_TIMEOUT = 100; var kEmptyBuffer = Buffer.allocUnsafe(0); @@ -2028,17 +2028,17 @@ var require_thread_stream = __commonJS({ "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports, module) { "use strict"; var { version } = require_package(); - var { EventEmitter } = __require2("events"); - var { Worker } = __require2("worker_threads"); - var { join } = __require2("path"); - var { pathToFileURL } = __require2("url"); + var { EventEmitter } = __require2("node:events"); + var { Worker } = __require2("node:worker_threads"); + var { join } = __require2("node:path"); + var { pathToFileURL } = __require2("node:url"); var { wait } = require_wait(); var { WRITE_INDEX, READ_INDEX } = require_indexes(); - var buffer = __require2("buffer"); - var assert = __require2("assert"); + var buffer = __require2("node:buffer"); + var assert = __require2("node:assert"); var kImpl = Symbol("kImpl"); var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; var FakeWeakRef = class { @@ -2448,9 +2448,9 @@ var require_thread_stream = __commonJS({ var require_transport = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports, module) { "use strict"; - var { createRequire } = __require2("module"); + var { createRequire } = __require2("node:module"); var getCallers = require_caller(); - var { join, isAbsolute, sep } = __require2("path"); + var { join, isAbsolute, sep } = __require2("node:path"); var sleep = require_atomic_sleep(); var onExit = require_on_exit_leak_free(); var ThreadStream = require_thread_stream(); @@ -2584,7 +2584,7 @@ var require_tools = __commonJS({ nestedKeyStrSym, msgPrefixSym } = require_symbols(); - var { isMainThread } = __require2("worker_threads"); + var { isMainThread } = __require2("node:worker_threads"); var transport = require_transport(); function noop() { } @@ -3096,7 +3096,7 @@ var require_meta = __commonJS({ var require_proto = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports, module) { "use strict"; - var { EventEmitter } = __require2("events"); + var { EventEmitter } = __require2("node:events"); var { lsCacheSym, levelValSym, @@ -4043,7 +4043,7 @@ var require_multistream = __commonJS({ var require_pino = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports, module) { "use strict"; - var os = __require2("os"); + var os = __require2("node:os"); var stdSerializers = require_pino_std_serializers(); var caller = require_caller(); var redaction = require_redaction(); diff --git a/build/serve/ownerSizeTotalWorker.js b/build/serve/ownerSizeTotalWorker.js index 0abcbb0..2744f84 100644 --- a/build/serve/ownerSizeTotalWorker.js +++ b/build/serve/ownerSizeTotalWorker.js @@ -1259,10 +1259,10 @@ var require_atomic_sleep = __commonJS({ var require_sonic_boom = __commonJS({ "node_modules/.deno/sonic-boom@3.8.1/node_modules/sonic-boom/index.js"(exports, module) { "use strict"; - var fs = __require2("fs"); - var EventEmitter = __require2("events"); - var inherits = __require2("util").inherits; - var path = __require2("path"); + var fs = __require2("node:fs"); + var EventEmitter = __require2("node:events"); + var inherits = __require2("node:util").inherits; + var path = __require2("node:path"); var sleep = require_atomic_sleep(); var BUSY_WRITE_TIMEOUT = 100; var kEmptyBuffer = Buffer.allocUnsafe(0); @@ -2028,17 +2028,17 @@ var require_thread_stream = __commonJS({ "node_modules/.deno/thread-stream@2.7.0/node_modules/thread-stream/index.js"(exports, module) { "use strict"; var { version } = require_package(); - var { EventEmitter } = __require2("events"); - var { Worker } = __require2("worker_threads"); - var { join } = __require2("path"); - var { pathToFileURL } = __require2("url"); + var { EventEmitter } = __require2("node:events"); + var { Worker } = __require2("node:worker_threads"); + var { join } = __require2("node:path"); + var { pathToFileURL } = __require2("node:url"); var { wait } = require_wait(); var { WRITE_INDEX, READ_INDEX } = require_indexes(); - var buffer = __require2("buffer"); - var assert = __require2("assert"); + var buffer = __require2("node:buffer"); + var assert = __require2("node:assert"); var kImpl = Symbol("kImpl"); var MAX_STRING = buffer.constants.MAX_STRING_LENGTH; var FakeWeakRef = class { @@ -2448,9 +2448,9 @@ var require_thread_stream = __commonJS({ var require_transport = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/transport.js"(exports, module) { "use strict"; - var { createRequire } = __require2("module"); + var { createRequire } = __require2("node:module"); var getCallers = require_caller(); - var { join, isAbsolute, sep } = __require2("path"); + var { join, isAbsolute, sep } = __require2("node:path"); var sleep = require_atomic_sleep(); var onExit = require_on_exit_leak_free(); var ThreadStream = require_thread_stream(); @@ -2584,7 +2584,7 @@ var require_tools = __commonJS({ nestedKeyStrSym, msgPrefixSym } = require_symbols(); - var { isMainThread } = __require2("worker_threads"); + var { isMainThread } = __require2("node:worker_threads"); var transport = require_transport(); function noop() { } @@ -3096,7 +3096,7 @@ var require_meta = __commonJS({ var require_proto = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/lib/proto.js"(exports, module) { "use strict"; - var { EventEmitter } = __require2("events"); + var { EventEmitter } = __require2("node:events"); var { lsCacheSym, levelValSym, @@ -4043,7 +4043,7 @@ var require_multistream = __commonJS({ var require_pino = __commonJS({ "node_modules/.deno/pino@8.19.0/node_modules/pino/pino.js"(exports, module) { "use strict"; - var os = __require2("os"); + var os = __require2("node:os"); var stdSerializers = require_pino_std_serializers(); var caller = require_caller(); var redaction = require_redaction(); diff --git a/scripts/build.ts b/scripts/build.ts index 45453f5..df6d779 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -2,9 +2,12 @@ import * as esbuild from 'npm:esbuild@0.25.6' import * as colors from 'jsr:@std/fmt/colors' +import { builtinModules } from 'node:module' const { default: { version } } = await import('../package.json', { with: { type: 'json' } }) +const nodeBuiltins = new Set(builtinModules.filter((m: string) => !m.startsWith('_'))) + const options: esbuild.BuildOptions = { entryPoints: [ './src/main.ts', @@ -29,6 +32,17 @@ const options: esbuild.BuildOptions = { build.onResolve({ filter: /^npm:/, namespace: 'file' }, ({ path, ...args }) => build.resolve(path.slice(4), args)) } }, + { + name: 'node-builtins', + setup (build) { + build.onResolve({ filter: /^[a-zA-Z]/, namespace: 'file' }, ({ path }) => { + if (nodeBuiltins.has(path)) { + return { path: `node:${path}`, external: true } + } + return null + }) + } + }, { name: 'skip', setup (build) { @@ -49,23 +63,10 @@ if (result.errors.length) { } console.log(colors.green('built:'), options.outdir) -import { builtinModules } from 'node:module' - -const nodeBuiltins = new Set(builtinModules.filter((m: string) => !m.startsWith('_'))) -const bareBuiltinRe = /\bfrom\s+(["'])([^"']+)\1/g - -function addNodePrefix (source: string): string { - return source.replace(bareBuiltinRe, (match, _, specifier) => { - return nodeBuiltins.has(specifier) ? `from "node:${specifier}"` : match - }) -} - for (const outfile of result.outputFiles!) { const tmpFile = outfile.path + '-tmp' try { - const text = new TextDecoder().decode(outfile.contents) - const patched = addNodePrefix(text) - Deno.writeFileSync(tmpFile, new TextEncoder().encode(patched)) + Deno.writeFileSync(tmpFile, outfile.contents) try { Deno.removeSync(outfile.path) } catch (e) { diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 83559e0..e6b9847 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -29,6 +29,17 @@ import { authMiddleware, type AuthCredentials } from './auth.ts' const MEGABYTE = 1048576 // TODO: add settings for these const SECOND = 1000 +// Joi-compatible boolean coercion for query parameters +// Matches Joi.boolean().truthy('1', 'on', 'yes').falsy('0', 'off', 'no') +function parseBooleanParam (value: string | undefined): boolean { + if (value === undefined) return false + const normalized = value.toLowerCase() + if (normalized === '' || normalized === 'true' || normalized === 'yes' || normalized === 'on' || normalized === '1') { + return true + } + return false +} + // Regexes validated as safe with const CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/ // deno-lint-ignore no-control-regex @@ -494,7 +505,7 @@ export function registerRoutes (app: Hono): void { throw new HTTPException(400) } - const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: keyOps === 'true' }) as Readable + const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: parseBooleanParam(keyOps) }) as Readable // "On an HTTP server, make sure to manually close your streams if a request is aborted." // From: http://knexjs.org/#Interfaces-Streams // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams From 8b4b325da10142a99fe9c06fd23ef63b5f148577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:11:05 +0000 Subject: [PATCH 36/71] build --- build/main.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/build/main.js b/build/main.js index eeaf48a..cbe029c 100644 --- a/build/main.js +++ b/build/main.js @@ -108742,12 +108742,14 @@ var init_server = __esm({ }, "backend/server/stop": async function() { clearInterval(pushHeartbeatIntervalID); - ownerSizeTotalWorker?.terminate(); - creditsWorker?.terminate(); if (esm_default("sbp/selectors/fn", "backend/server/stopRateLimiters")) { await esm_default("backend/server/stopRateLimiters"); } - return hapi.stop(); + await hapi.stop(); + await Promise.all([ + ownerSizeTotalWorker?.terminate(), + creditsWorker?.terminate() + ]); }, async "backend/deleteFile"(cid, ultimateOwnerID, skipIfDeleted) { const owner = await esm_default("chelonia.db/get", `_private_owner_${cid}`); From ede943fb897d328183141d9ee0b71bddfd209231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 02:51:44 +0000 Subject: [PATCH 37/71] Change name for consistency --- src/pin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pin.ts b/src/pin.ts index 78e1b8d..dc2cafe 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -84,7 +84,7 @@ export async function pin (args: ArgumentsCamelCase): Promise { await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${contractName} to version ${manifestVersion}`)) + console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } catch (error) { exit(error) From 6a40a04f8c2f5bdc5c99b2228e7634af8b38b577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:24:00 +0000 Subject: [PATCH 38/71] Update README.md --- README.md | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9d88ca5..c018d76 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,12 @@ chel pin 2.0.0 dist/contracts/2.0.0/group.2.0.0.manifest.json **Configuration (`chelonia.json`):** ```json { - "contracts": { + "gi.contracts/chatroom": { "chatroom": { "version": "2.0.6", "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" }, - "group": { + "gi.contracts/group": { "version": "2.0.0", "path": "contracts/gi.contracts_group/2.0.0/group.2.0.0.manifest.json" } @@ -278,6 +278,73 @@ chel migrate --from sqlite --to redis --to-config redis.toml chel migrate --from sqlite --from-config sqlite.toml --to redis --to-config redis.toml ``` +## Configuration Files + +The project uses two separate configuration files for different purposes: + +### `chel.toml` — Runtime CLI Configuration + +`chel.toml` configures the `chel` command itself at runtime. It is read by `nconf` with priority: CLI arguments > environment variables > `chel.toml` > defaults. It controls things like server host/port, database backend selection, and other operational settings. + +```toml +# Example chel.toml +[server] +host = "0.0.0.0" +port = 8000 +dashboardPort = 8888 + +[database] +backend = "sqlite" +``` + +### `chelonia.json` — App Properties + +`chelonia.json` is an **app-level properties file** that describes which +contracts make up the application and their pinned versions. It is **not** +runtime configuration for `chel`. Instead, it is: + +- **Created and updated** by `chel pin` when pinning contracts to specific + versions. +- **Read by the server** (`chel serve`) at startup to provide version + information and other app-specific settings to clients. + +The file contains a `contracts` object keyed by the full contract name +(e.g. `gi.contracts/chatroom`), where each entry has: + +| Field | Description | +|-------|-------------| +| `version` | The pinned version string for this contract | +| `path` | Relative path to the manifest file in the `contracts/` directory | + +It may also contain an `appVersion` field for the overall application version. + +**Example:** +```json +{ + "appVersion": "2.0.0", + "contracts": { + "gi.contracts/chatroom": { + "version": "2.0.6", + "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" + }, + "gi.contracts/group": { + "version": "2.0.0", + "path": "contracts/gi.contracts_group/2.0.0/group.2.0.0.manifest.json" + } + } +} +``` + +**Summary of differences:** + +| | `chel.toml` | `chelonia.json` | +|---|---|---| +| **Purpose** | Runtime configuration of the `chel` CLI | App properties (e.g., contract versions) | +| **Managed by** | Manually by the developer / system administrator | Automatically by `chel pin` | +| **Read by** | `chel` commands (via `nconf`) | The server (at startup), values exposed to clients | +| **Format** | TOML | JSON | +| **Example content** | Database configuration | Contract versions | + ## History See [HISTORY.md](HISTORY.md) From b78b26ec4f1c9c8c1492eca4529e65e3baf3ee6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:40:18 +0000 Subject: [PATCH 39/71] Fixes --- src/serve/routes-test-helpers.ts | 99 ++++++++++----- src/serve/routes-zkpp.test.ts | 208 ++++++++++++------------------- src/serve/server.ts | 2 +- 3 files changed, 147 insertions(+), 162 deletions(-) diff --git a/src/serve/routes-test-helpers.ts b/src/serve/routes-test-helpers.ts index 9a4de5d..091e5e9 100644 --- a/src/serve/routes-test-helpers.ts +++ b/src/serve/routes-test-helpers.ts @@ -103,48 +103,78 @@ export function buildShelterAuthHeader (contractID: string, SAK: ReturnType { - process.env.NODE_ENV = 'development' - process.env.CI = 'true' - - nconf.defaults({ - server: { - host: '127.0.0.1', - port: TEST_PORT, - appDir: '.', - fileUploadMaxBytes: 31457280, - signup: { - disabled: false, - limit: { disabled: false, minute: 100, hour: 1000, day: 10000 } - }, - logLevel: 'error', - messages: [{ type: 'info', text: 'test message' }], - maxEventsBatchSize: 500, - archiveMode: false - }, - database: { - lruNumItems: 100, - backend: 'mem', - backendOptions: {} - } - }) +let cachedServerAddress: Promise | undefined +let serverStartRefCount: number = 0 +export function startTestServer (): Promise { + serverStartRefCount++ + if (cachedServerAddress !== undefined) { + return cachedServerAddress + } - const serverAddress = await new Promise((resolve, reject) => { - const unregister = sbp('okTurtles.events/once', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { - resolve(hapi.info.uri) + const internal = async () => { + process.env.NODE_ENV = 'development' + process.env.CI = 'true' + + nconf.defaults({ + server: { + host: '127.0.0.1', + port: TEST_PORT, + appDir: '.', + fileUploadMaxBytes: 31457280, + signup: { + disabled: false, + limit: { disabled: false, minute: 100, hour: 1000, day: 10000 } + }, + logLevel: 'error', + messages: [{ type: 'info', text: 'test message' }], + maxEventsBatchSize: 500, + archiveMode: false + }, + database: { + lruNumItems: 100, + backend: 'mem', + backendOptions: {} + } }) - import('./index.ts').then(({ default: start }) => { - return start() - }).catch((e) => { - unregister() - reject(e) + + const serverAddress = await new Promise((resolve, reject) => { + const unregister = sbp('okTurtles.events/once', SERVER_RUNNING, function (hapi: { info: { uri: string } }) { + resolve(hapi.info.uri) + }) + import('./index.ts').then(({ default: start }) => { + return start() + }).catch((e) => { + unregister() + reject(e) + }) }) + + return serverAddress + } + + cachedServerAddress = internal().catch(e => { + cachedServerAddress = undefined + serverStartRefCount = 0 + throw e }) - return serverAddress + return cachedServerAddress } export async function stopTestServer (): Promise { + if (cachedServerAddress === undefined) { + throw new Error('Server has not yet started') + } + try { + await cachedServerAddress + } catch { + // If the server was starting and it encountered an error, this function + // technically succeeded (server is not runnign). + return + } + if (--serverStartRefCount > 0) { + return + } await new Promise((resolve) => { sbp('okTurtles.events/once', SERVER_EXITING, () => { sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { @@ -153,4 +183,5 @@ export async function stopTestServer (): Promise { }) sbp('okTurtles.events/emit', SERVER_EXITING) }) + cachedServerAddress = undefined } diff --git a/src/serve/routes-zkpp.test.ts b/src/serve/routes-zkpp.test.ts index b9a2faf..2655dc8 100644 --- a/src/serve/routes-zkpp.test.ts +++ b/src/serve/routes-zkpp.test.ts @@ -12,6 +12,85 @@ import { } from './routes-test-helpers.ts' import { CS } from 'npm:@chelonia/lib/zkppConstants' +async function zkppFullFlow (baseURL: string, contentType: 'json' | 'form'): Promise { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + const hash = contentType === 'json' ? 'myhash' : 'myhash-form' + const name = contentType === 'json' ? 'zkppfullflow' : 'zkppformfull' + const suffix = contentType === 'json' ? '' : '-form' + + const contentTypeHeader = contentType === 'json' + ? 'application/json' + : 'application/x-www-form-urlencoded' + const postBody1 = contentType === 'json' + ? JSON.stringify({ b: publicKeyHash }) + : `b=${encodeURIComponent(publicKeyHash)}` + + const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': contentTypeHeader }, + body: postBody1 + }) + if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) + const step1 = await res1.json() + + const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) + const step2Payload: Record = { + r: publicKey, s: step1.s, sig: step1.sig, Eh: encryptedHashedPassword + } + const postBody2 = contentType === 'json' + ? JSON.stringify(step2Payload) + : new URLSearchParams(step2Payload).toString() + const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { + method: 'POST', + headers: { 'content-type': contentTypeHeader }, + body: postBody2 + }) + if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) + const encryptedToken = await res2.text() + if (/[^\da-zA-Z_-]/.test(encryptedToken)) throw new Error('Invalid characters in encrypted token') + const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) + + const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) + await sbp('backend/db/registerName', name, contractCID) + + const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') + await redeemSaltRegistrationToken(name, contractCID, token) + + const r = `challenge-r${suffix}` + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) + if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) + const challenge = await challengeRes.json() + if (!challenge.authSalt) throw new Error('Expected authSalt') + if (!challenge.s) throw new Error('Expected s') + if (!challenge.sig) throw new Error('Expected sig') + if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const saltRes = await fetch( + `${baseURL}/zkpp/${contractCID}/contract_hash?` + + `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + + `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` + ) + if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) + const encryptedSalt = await saltRes.text() + if (!encryptedSalt) throw new Error('Expected encrypted salt response') + if (/[^\da-zA-Z_-]/.test(encryptedSalt)) throw new Error('Invalid characters in encrypted salt') + + const saltBuf = Buffer.from(encryptedSalt, 'base64url') + const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) + const decrypted = nacl.secretbox.open(saltBuf.subarray(nacl.secretbox.nonceLength), nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt contract salt') + const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) + if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') +} + Deno.test({ name: 'routes: ZKPP endpoints', async fn (t: Deno.TestContext) { @@ -125,68 +204,7 @@ Deno.test({ }) await t.step('ZKPP full flow: register, challenge, get contract salt', async () => { - const keyPair = nacl.box.keyPair() - const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') - const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') - const hash = 'myhash' - const name = 'zkppfullflow' - - const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ b: publicKeyHash }) - }) - if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) - const step1 = await res1.json() - - const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) - const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ r: publicKey, s: step1.s, sig: step1.sig, Eh: encryptedHashedPassword }) - }) - if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) - const encryptedToken = await res2.text() - if (/[^\dA-Za-z_-]/.test(encryptedToken)) throw new Error('Invalid characters in encrypted token') - const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) - - const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) - await sbp('backend/db/registerName', name, contractCID) - - const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') - await redeemSaltRegistrationToken(name, contractCID, token) - - const r = 'challenge-r' - const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') - const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) - if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) - const challenge = await challengeRes.json() - if (!challenge.authSalt) throw new Error('Expected authSalt') - if (!challenge.s) throw new Error('Expected s') - if (!challenge.sig) throw new Error('Expected sig') - if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) - - const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) - const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) - const hc = nacl.hash(c) - - const saltRes = await fetch( - `${baseURL}/zkpp/${contractCID}/contract_hash?` + - `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + - `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` - ) - if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) - const encryptedSalt = await saltRes.text() - if (/[^\dA-Za-z_-]/.test(encryptedSalt)) throw new Error('Invalid characters in encrypted salt') - if (!encryptedSalt) throw new Error('Expected encrypted salt response') - - const saltBuf = Buffer.from(encryptedSalt, 'base64url') - const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) - const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) - const decrypted = nacl.secretbox.open(saltBuf.subarray(nacl.secretbox.nonceLength), nonce, encryptionKey) - if (!decrypted) throw new Error('Failed to decrypt contract salt') - const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) - if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') + await zkppFullFlow(baseURL, 'json') }) await t.step('POST /zkpp/register step 1 with form-urlencoded body', async () => { @@ -248,71 +266,7 @@ Deno.test({ }) await t.step('ZKPP full flow with form-urlencoded registration', async () => { - const keyPair = nacl.box.keyPair() - const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') - const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') - const hash = 'myhash-form' - const name = 'zkppformfull' - - const res1 = await fetch(`${baseURL}/zkpp/register/${name}`, { - method: 'POST', - headers: { 'content-type': 'application/x-www-form-urlencoded' }, - body: `b=${encodeURIComponent(publicKeyHash)}` - }) - if (res1.status !== 200) throw new Error(`Reg step 1 failed: ${res1.status}`) - const step1 = await res1.json() - - const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(step1.p, keyPair.secretKey, hash) - const res2 = await fetch(`${baseURL}/zkpp/register/${name}`, { - method: 'POST', - headers: { 'content-type': 'application/x-www-form-urlencoded' }, - body: new URLSearchParams({ - r: publicKey, - s: step1.s, - sig: step1.sig, - Eh: encryptedHashedPassword - }).toString() - }) - if (res2.status !== 200) throw new Error(`Reg step 2 failed: ${res2.status}`) - const encryptedToken = (await res2.text()) - if (/[^\da-zA-Z_-]/.test(encryptedToken)) throw new Error('Unexpected characters in encrypted token') - const token = decryptRegistrationRedemptionToken(step1.p, keyPair.secretKey, encryptedToken) - - const contractCID = createCID(`${name}-contract`, multicodes.SHELTER_CONTRACT_DATA) - await sbp('backend/db/registerName', name, contractCID) - - const { redeemSaltRegistrationToken } = await import('./zkppSalt.ts') - await redeemSaltRegistrationToken(name, contractCID, token) - - const r = 'challenge-r-form' - const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') - const challengeRes = await fetch(`${baseURL}/zkpp/${contractCID}/auth_hash?b=${encodeURIComponent(b)}`) - if (challengeRes.status !== 200) throw new Error(`auth_hash failed: ${challengeRes.status}`) - const challenge = await challengeRes.json() - if (!challenge.authSalt) throw new Error('Expected authSalt') - if (challenge.authSalt !== authSalt) throw new Error(`authSalt mismatch: ${challenge.authSalt} !== ${authSalt}`) - - const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) - const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) - const hc = nacl.hash(c) - - const saltRes = await fetch( - `${baseURL}/zkpp/${contractCID}/contract_hash?` + - `r=${encodeURIComponent(r)}&s=${encodeURIComponent(challenge.s)}` + - `&sig=${encodeURIComponent(challenge.sig)}&hc=${encodeURIComponent(Buffer.from(hc).toString('base64url'))}` - ) - if (saltRes.status !== 200) throw new Error(`contract_hash failed: ${saltRes.status}`) - const encryptedSalt = await saltRes.text() - if (!encryptedSalt) throw new Error('Expected encrypted salt response') - if (/[^\da-zA-Z_-]/.test(encryptedSalt)) throw new Error('Unexpected characters in encrypted salt') - - const saltBuf = Buffer.from(encryptedSalt, 'base64url') - const nonce = saltBuf.subarray(0, nacl.secretbox.nonceLength) - const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) - const decrypted = nacl.secretbox.open(saltBuf.subarray(nacl.secretbox.nonceLength), nonce, encryptionKey) - if (!decrypted) throw new Error('Failed to decrypt contract salt') - const [retrievedContractSalt] = JSON.parse(Buffer.from(decrypted).toString()) - if (!retrievedContractSalt) throw new Error('Expected non-empty contract salt') + await zkppFullFlow(baseURL, 'form') }) } finally { await stopTestServer() diff --git a/src/serve/server.ts b/src/serve/server.ts index 6381357..98319b4 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -35,6 +35,7 @@ import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pus import nconf from 'npm:nconf' const ARCHIVE_MODE = nconf.get('server:archiveMode') +let pushHeartbeatIntervalID: ReturnType if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { process.stderr.write('The size calculation worker must run more frequently than the credits worker for accurate billing') @@ -589,7 +590,6 @@ sbp('okTurtles.data/set', PUBSUB_INSTANCE, createServer(hapi.listener, { })() // Recurring task to send messages to push clients (for periodic notifications) -let pushHeartbeatIntervalID: ReturnType ;(() => { const map = new WeakMap() From 7e432ec9e70be8fa74501f6df91c56c4a76a6732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:51:02 +0000 Subject: [PATCH 40/71] Fix example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c018d76..b4c7b3f 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ chel pin 2.0.0 dist/contracts/2.0.0/group.2.0.0.manifest.json **Configuration (`chelonia.json`):** ```json { - "gi.contracts/chatroom": { - "chatroom": { + "contracts": { + "gi.contracts/chatroom": { "version": "2.0.6", "path": "contracts/gi.contracts_chatroom/2.0.6/chatroom.2.0.6.manifest.json" }, From 740ec9b6e1f22c9f91d692fd01bfb93c26389b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:22:54 +0000 Subject: [PATCH 41/71] Fixes --- build/main.js | 8 ++++---- src/pin.ts | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/build/main.js b/build/main.js index 5ba947c..bad5562 100644 --- a/build/main.js +++ b/build/main.js @@ -110617,8 +110617,8 @@ var module9 = { return migrate(argv); } }; -var RESERVED_FILE_CHARS = /[/\\:*?"<>|]/; -var RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g; +var VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/; +var RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g; var projectRoot; var cheloniaConfig; function sanitizeContractName(contractName) { @@ -110641,7 +110641,7 @@ async function pin(args) { exit(`Manifest file not found: ${manifestPath}`); } const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { exit(`Invalid manifest version: ${manifestVersion}`); } console.log(blue(`Contract name: ${fullContractName}`)); @@ -110675,7 +110675,7 @@ async function pin(args) { } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${contractName} to version ${manifestVersion}`)); + console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } catch (error2) { exit(error2); diff --git a/src/pin.ts b/src/pin.ts index dc2cafe..51baf52 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -6,8 +6,9 @@ import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' -const RESERVED_FILE_CHARS = /[/\\:*?"<>|]/ -const RESERVED_FILE_CHARS_REPLACE = /[/\\:*?"<>|]/g +const VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/ +// deno-lint-ignore no-control-regex +const RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } @@ -41,7 +42,7 @@ export async function pin (args: ArgumentsCamelCase): Promise { const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - if (RESERVED_FILE_CHARS.test(manifestVersion)) { + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { exit(`Invalid manifest version: ${manifestVersion}`) } From dd2571b0b594f1d61a3b58bf0928be813ed397b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:36:37 +0000 Subject: [PATCH 42/71] Improvements --- build/main.js | 399 +++++++++++++------------ src/eventsAfter.ts | 8 +- src/get.ts | 8 +- src/main.ts | 14 +- src/migrate.ts | 4 +- src/serve/index.ts | 33 +- src/serve/ownerSizeTotalWorker.test.ts | 3 +- src/serve/routes.ts | 8 +- src/serve/server.ts | 2 + src/serve/zkppSalt.test.ts | 4 +- src/upload.ts | 70 +++-- 11 files changed, 281 insertions(+), 272 deletions(-) diff --git a/build/main.js b/build/main.js index 8794bf9..7d4366b 100644 --- a/build/main.js +++ b/build/main.js @@ -4178,143 +4178,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); -function sbp(selector, ...data) { - const domain = domainFromSelector(selector); - const starSelector = `${domain}/*`; - const selExists = !!selectors[selector]; - let sel = selector; - if (!selExists) { - if (selectors[starSelector]) { - sel = starSelector; - } else { - throw new Error(`SBP: selector not registered: ${selector}`); - } - } - for (const filters of [selectorFilters[selector], domainFilters[domain], globalFilters]) { - if (filters) { - for (const filter of filters) { - if (filter(domain, selector, data) === false) - return; - } - } - } - if (!selExists) { - data.unshift(selector); - } - return selectors[sel].apply(domains[domain].state, data); -} -function domainFromSelector(selector) { - const domainLookup = DOMAIN_REGEX.exec(selector); - if (domainLookup === null) { - throw new Error(`SBP: selector missing domain: ${selector}`); - } - return domainLookup[0]; -} -var selectors; -var domains; -var globalFilters; -var domainFilters; -var selectorFilters; -var unsafeSelectors; -var DOMAIN_REGEX; -var SBP_BASE_SELECTORS; -var esm_default; -var init_esm = __esm({ - "node_modules/.deno/@sbp+sbp@2.4.1/node_modules/@sbp/sbp/dist/esm/index.js"() { - selectors = /* @__PURE__ */ Object.create(null); - domains = /* @__PURE__ */ Object.create(null); - globalFilters = []; - domainFilters = /* @__PURE__ */ Object.create(null); - selectorFilters = /* @__PURE__ */ Object.create(null); - unsafeSelectors = /* @__PURE__ */ Object.create(null); - DOMAIN_REGEX = /^[^/]+/; - SBP_BASE_SELECTORS = { - "sbp/selectors/register": (sels) => { - const registered = []; - for (const selector in sels) { - const domainName = domainFromSelector(selector); - const domain = domainName in domains ? domains[domainName] : domains[domainName] = { state: /* @__PURE__ */ Object.create(null), locked: false }; - if (domain.locked) { - (console.warn || console.log)(`[SBP WARN]: not registering selector on locked domain: '${selector}'`); - } else if (selectors[selector]) { - (console.warn || console.log)(`[SBP WARN]: not registering already registered selector: '${selector}'`); - } else if (typeof sels[selector] === "function") { - if (unsafeSelectors[selector]) { - (console.warn || console.log)(`[SBP WARN]: registering unsafe selector: '${selector}' (remember to lock after overwriting)`); - } - const fn = selectors[selector] = sels[selector]; - registered.push(selector); - if (selector === `${domainName}/_init`) { - fn.call(domain.state); - } - } - } - return registered; - }, - "sbp/selectors/unregister": (sels) => { - var _a2; - for (const selector of sels) { - if (!unsafeSelectors[selector]) { - throw new Error(`SBP: can't unregister locked selector: ${selector}`); - } - if ((_a2 = domains[domainFromSelector(selector)]) === null || _a2 === void 0 ? void 0 : _a2.locked) { - throw new Error(`SBP: can't unregister selector on a locked domain: '${selector}'`); - } - delete selectors[selector]; - } - }, - "sbp/selectors/overwrite": (sels) => { - sbp("sbp/selectors/unregister", Object.keys(sels)); - return sbp("sbp/selectors/register", sels); - }, - "sbp/selectors/unsafe": (sels) => { - for (const selector of sels) { - if (selectors[selector]) { - throw new Error("unsafe must be called before registering selector"); - } - unsafeSelectors[selector] = true; - } - }, - "sbp/selectors/lock": (sels) => { - for (const selector of sels) { - delete unsafeSelectors[selector]; - } - }, - "sbp/selectors/fn": (sel) => { - return selectors[sel]; - }, - "sbp/filters/global/add": (filter) => { - globalFilters.push(filter); - }, - "sbp/filters/domain/add": (domain, filter) => { - if (!domainFilters[domain]) - domainFilters[domain] = []; - domainFilters[domain].push(filter); - }, - "sbp/filters/selector/add": (selector, filter) => { - if (!selectorFilters[selector]) - selectorFilters[selector] = []; - selectorFilters[selector].push(filter); - }, - "sbp/domains/lock": (domainNames) => { - if (!domainNames) { - for (const name in domains) { - domains[name].locked = true; - } - } else { - for (const name of domainNames) { - if (!domains[name]) { - throw new Error(`SBP: cannot lock non-existent domain: ${name}`); - } - domains[name].locked = true; - } - } - } - }; - SBP_BASE_SELECTORS["sbp/selectors/register"](SBP_BASE_SELECTORS); - esm_default = sbp; - } -}); var require_async = __commonJS({ "node_modules/.deno/async@3.2.6/node_modules/async/dist/async.js"(exports2, module14) { (function(global2, factory) { @@ -19129,6 +18992,143 @@ var init_functions = __esm({ }; } }); +function sbp(selector, ...data) { + const domain = domainFromSelector(selector); + const starSelector = `${domain}/*`; + const selExists = !!selectors[selector]; + let sel = selector; + if (!selExists) { + if (selectors[starSelector]) { + sel = starSelector; + } else { + throw new Error(`SBP: selector not registered: ${selector}`); + } + } + for (const filters of [selectorFilters[selector], domainFilters[domain], globalFilters]) { + if (filters) { + for (const filter of filters) { + if (filter(domain, selector, data) === false) + return; + } + } + } + if (!selExists) { + data.unshift(selector); + } + return selectors[sel].apply(domains[domain].state, data); +} +function domainFromSelector(selector) { + const domainLookup = DOMAIN_REGEX.exec(selector); + if (domainLookup === null) { + throw new Error(`SBP: selector missing domain: ${selector}`); + } + return domainLookup[0]; +} +var selectors; +var domains; +var globalFilters; +var domainFilters; +var selectorFilters; +var unsafeSelectors; +var DOMAIN_REGEX; +var SBP_BASE_SELECTORS; +var esm_default; +var init_esm = __esm({ + "node_modules/.deno/@sbp+sbp@2.4.1/node_modules/@sbp/sbp/dist/esm/index.js"() { + selectors = /* @__PURE__ */ Object.create(null); + domains = /* @__PURE__ */ Object.create(null); + globalFilters = []; + domainFilters = /* @__PURE__ */ Object.create(null); + selectorFilters = /* @__PURE__ */ Object.create(null); + unsafeSelectors = /* @__PURE__ */ Object.create(null); + DOMAIN_REGEX = /^[^/]+/; + SBP_BASE_SELECTORS = { + "sbp/selectors/register": (sels) => { + const registered = []; + for (const selector in sels) { + const domainName = domainFromSelector(selector); + const domain = domainName in domains ? domains[domainName] : domains[domainName] = { state: /* @__PURE__ */ Object.create(null), locked: false }; + if (domain.locked) { + (console.warn || console.log)(`[SBP WARN]: not registering selector on locked domain: '${selector}'`); + } else if (selectors[selector]) { + (console.warn || console.log)(`[SBP WARN]: not registering already registered selector: '${selector}'`); + } else if (typeof sels[selector] === "function") { + if (unsafeSelectors[selector]) { + (console.warn || console.log)(`[SBP WARN]: registering unsafe selector: '${selector}' (remember to lock after overwriting)`); + } + const fn = selectors[selector] = sels[selector]; + registered.push(selector); + if (selector === `${domainName}/_init`) { + fn.call(domain.state); + } + } + } + return registered; + }, + "sbp/selectors/unregister": (sels) => { + var _a2; + for (const selector of sels) { + if (!unsafeSelectors[selector]) { + throw new Error(`SBP: can't unregister locked selector: ${selector}`); + } + if ((_a2 = domains[domainFromSelector(selector)]) === null || _a2 === void 0 ? void 0 : _a2.locked) { + throw new Error(`SBP: can't unregister selector on a locked domain: '${selector}'`); + } + delete selectors[selector]; + } + }, + "sbp/selectors/overwrite": (sels) => { + sbp("sbp/selectors/unregister", Object.keys(sels)); + return sbp("sbp/selectors/register", sels); + }, + "sbp/selectors/unsafe": (sels) => { + for (const selector of sels) { + if (selectors[selector]) { + throw new Error("unsafe must be called before registering selector"); + } + unsafeSelectors[selector] = true; + } + }, + "sbp/selectors/lock": (sels) => { + for (const selector of sels) { + delete unsafeSelectors[selector]; + } + }, + "sbp/selectors/fn": (sel) => { + return selectors[sel]; + }, + "sbp/filters/global/add": (filter) => { + globalFilters.push(filter); + }, + "sbp/filters/domain/add": (domain, filter) => { + if (!domainFilters[domain]) + domainFilters[domain] = []; + domainFilters[domain].push(filter); + }, + "sbp/filters/selector/add": (selector, filter) => { + if (!selectorFilters[selector]) + selectorFilters[selector] = []; + selectorFilters[selector].push(filter); + }, + "sbp/domains/lock": (domainNames) => { + if (!domainNames) { + for (const name in domains) { + domains[name].locked = true; + } + } else { + for (const name of domainNames) { + if (!domains[name]) { + throw new Error(`SBP: cannot lock non-existent domain: ${name}`); + } + domains[name].locked = true; + } + } + } + }; + SBP_BASE_SELECTORS["sbp/selectors/register"](SBP_BASE_SELECTORS); + esm_default = sbp; + } +}); var isEventQueueSbpEvent; var esm_default2; var init_esm2 = __esm({ @@ -61443,7 +61443,6 @@ var require_websocket_server = __commonJS({ } } }); -init_esm(); var import_npm_nconf7 = __toESM(require_nconf()); function getLineColFromPtr(string3, ptr) { let lines = string3.slice(0, ptr).split(/\r\n|\n|\r/g); @@ -68574,40 +68573,48 @@ var findManifestFiles = async (path8) => { }; async function upload(args, internal = false) { const { url: url2, files } = args; + let dbOpen = false; if (!url2) { await initDB({ skipDbPreloading: true }); + dbOpen = true; } - const uploaded = []; - const uploaderFn = url2 ? uploadEntryToURL : uploadEntryToDB; - for (const filepath_ of files) { - let type = multicodes.RAW; - let filepath = filepath_; - if (internal) { - if (filepath_[1] !== "|") throw new Error("Invalid path format"); - switch (filepath_[0]) { - case "r": - break; - case "m": - type = multicodes.SHELTER_CONTRACT_MANIFEST; - break; - case "t": - type = multicodes.SHELTER_CONTRACT_TEXT; - break; - default: - throw new Error("Unknown file type: " + filepath_[0]); + try { + const uploaded = []; + const uploaderFn = url2 ? uploadEntryToURL : uploadEntryToDB; + for (const filepath_ of files) { + let type = multicodes.RAW; + let filepath = filepath_; + if (internal) { + if (filepath_[1] !== "|") throw new Error("Invalid path format"); + switch (filepath_[0]) { + case "r": + break; + case "m": + type = multicodes.SHELTER_CONTRACT_MANIFEST; + break; + case "t": + type = multicodes.SHELTER_CONTRACT_TEXT; + break; + default: + throw new Error("Unknown file type: " + filepath_[0]); + } + filepath = filepath_.slice(2); } - filepath = filepath_.slice(2); + const entry = await createEntryFromFile(filepath, type); + const destination = await uploaderFn(entry, url2); + if (!internal) { + console.log(green("uploaded:"), destination); + } else { + console.log(green(`${relative7(".", filepath)}:`), destination); + } + uploaded.push([filepath, destination]); } - const entry = await createEntryFromFile(filepath, type); - const destination = await uploaderFn(entry, url2); - if (!internal) { - console.log(green("uploaded:"), destination); - } else { - console.log(green(`${relative7(".", filepath)}:`), destination); + return uploaded; + } finally { + if (dbOpen) { + await closeDB(); } - uploaded.push([filepath, destination]); } - return uploaded; } async function uploadEntryToURL([cid, buffer], url2) { const form = new FormData(); @@ -68709,17 +68716,23 @@ var module3 = { }; init_esm(); async function eventsAfter2({ limit, url: url2, contractID, height }) { + let dbOpen = false; try { let messages; if (url2) { messages = await getRemoteMessagesSince(url2, contractID, height, limit); } else { await initDB({ skipDbPreloading: true }); + dbOpen = true; messages = await getMessagesSince(contractID, height, limit); } console.log(JSON.stringify(messages, null, 2)); } catch (error2) { exit(error2); + } finally { + if (dbOpen) { + await closeDB(); + } } } async function getMessagesSince(contractID, sinceHeight, limit) { @@ -68787,8 +68800,10 @@ var module4 = { }; init_esm(); async function get({ key, url: url2 }) { + let dbOpen = false; if (!url2) { await initDB({ skipDbPreloading: true }); + dbOpen = true; } try { const data = url2 ? await readRemoteData(url2, key) : await esm_default("chelonia.db/get", key); @@ -68800,6 +68815,10 @@ async function get({ key, url: url2 }) { } } catch (error2) { exit(error2); + } finally { + if (dbOpen) { + await closeDB(); + } } } var module5 = { @@ -69021,6 +69040,8 @@ async function migrate(args) { console.error("Error setting up database"); exit(e2); throw e2; + } finally { + closeDB(); } let backendTo; try { @@ -69450,8 +69471,6 @@ init_esm(); var import_npm_chalk4 = __toESM(require_source()); var SERVER_EXITING = "server-exiting"; var SERVER_RUNNING = "server-running"; -var SERVER_INSTANCE = "@instance/server"; -var PUBSUB_INSTANCE = "@instance/pubsub"; init_SPMessage(); init_functions(); init_esm(); @@ -73127,9 +73146,9 @@ function registerRoutes(app2) { const staticServeConfig = getStaticServeConfig(); app2.post( "/event", + zValidator("header", eventHeaderSchema), bodyLimit({ maxSize: MEGABYTE }), authMiddleware("chel-shelter", "optional"), - zValidator("header", eventHeaderSchema), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const ip = getClientIP(c); @@ -73355,8 +73374,8 @@ function registerRoutes(app2) { } app2.post( "/file", - bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), authMiddleware("chel-shelter", "required"), + bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { @@ -73562,9 +73581,9 @@ function registerRoutes(app2) { ); app2.post( "/kv/:contractID/:key", - bodyLimit({ maxSize: 6 * MEGABYTE }), - authMiddleware("chel-shelter", "required"), zValidator("param", kvParamSchema), + authMiddleware("chel-shelter", "required"), + bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const { contractID, key } = c.req.valid("param"); @@ -73774,6 +73793,8 @@ function registerRoutes(app2) { } var CREDITS_WORKER_TASK_TIME_INTERVAL = 3e5; var OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL = 3e4; +var SERVER_INSTANCE = "@instance/server"; +var PUBSUB_INSTANCE = "@instance/pubsub"; init_esm4(); init_functions(); init_esm(); @@ -74947,27 +74968,15 @@ async function startServer2(options2 = {}) { installGlobalExceptionHandlers(); installSignalHandlers(); } - esm_default("okTurtles.events/once", SERVER_EXITING, () => { - esm_default("okTurtles.data/apply", PUBSUB_INSTANCE, function(pubsub) { - esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { - return new Promise((resolve82) => { - pubsub.on("close", async function() { - try { - removeSignalHandlers(); - await esm_default("chelonia.persistentActions/unload"); - await stopServer2(); - console.info("Server down"); - } catch (err) { - console.error(err, "Error during shutdown"); - } finally { - resolve82(); - } - }); - pubsub.close(); - pubsub.clients.forEach((client) => client.terminate()); - }); - }); - }); + esm_default("okTurtles.events/once", SERVER_EXITING, async () => { + try { + removeSignalHandlers(); + await esm_default("chelonia.persistentActions/unload"); + await stopServer2(); + console.info("Server down"); + } catch (err) { + console.error(err, "Error during shutdown"); + } }); return await new Promise((resolve82, reject) => { esm_default("okTurtles.events/on", SERVER_RUNNING, function onRunning(info) { @@ -79691,11 +79700,7 @@ var parseConfig = () => { }; var parseConfig_default = parseConfig; parseConfig_default(); -try { - await handlerState.postHandler(); -} finally { - esm_default("okTurtles.events/emit", SERVER_EXITING); -} +await handlerState.postHandler(); /*! Bundled license information: scrypt-async/scrypt-async.js: diff --git a/src/eventsAfter.ts b/src/eventsAfter.ts index b8bc8bd..d420a88 100644 --- a/src/eventsAfter.ts +++ b/src/eventsAfter.ts @@ -3,12 +3,13 @@ import * as base64 from 'jsr:@std/encoding/base64' import sbp from 'npm:@sbp/sbp' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' -import { initDB } from './serve/database.ts' +import { closeDB, initDB } from './serve/database.ts' import { exit } from './utils.ts' type Params = { limit: number, url: string | undefined, contractID: string, height: number } export async function eventsAfter ({ limit, url, contractID, height }: ArgumentsCamelCase): Promise { + let dbOpen = false try { let messages @@ -16,11 +17,16 @@ export async function eventsAfter ({ limit, url, contractID, height }: Arguments messages = await getRemoteMessagesSince(url, contractID, height, limit) } else { await initDB({ skipDbPreloading: true }) + dbOpen = true messages = await getMessagesSince(contractID, height, limit) } console.log(JSON.stringify(messages, null, 2)) } catch (error) { exit(error) + } finally { + if (dbOpen) { + await closeDB() + } } } diff --git a/src/get.ts b/src/get.ts index 4e89536..591e065 100644 --- a/src/get.ts +++ b/src/get.ts @@ -10,14 +10,16 @@ chel get https://url.com mygreatlongkey > file.png import { writeAll } from 'jsr:@std/io/' import sbp from 'npm:@sbp/sbp' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' -import { initDB } from './serve/database.ts' +import { closeDB, initDB } from './serve/database.ts' import { exit, readRemoteData } from './utils.ts' type Params = { url?: string, key: string } export async function get ({ key, url }: ArgumentsCamelCase): Promise { + let dbOpen = false if (!url) { await initDB({ skipDbPreloading: true }) + dbOpen = true } try { @@ -35,6 +37,10 @@ export async function get ({ key, url }: ArgumentsCamelCase): Promise): Promise console.error('Error setting up database') exit(e) throw e + } finally { + closeDB() } let backendTo: DatabaseBackend diff --git a/src/serve/index.ts b/src/serve/index.ts index 3d07584..e97ad36 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -5,7 +5,6 @@ import 'npm:@sbp/okturtles.events' import sbp from 'npm:@sbp/sbp' import chalk from 'npm:chalk' import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' -import { PUBSUB_INSTANCE } from './instance-keys.ts' import { startServer as startServerImpl, stopServer as stopServerImpl } from './server.ts' import { initializeLogger } from './logger.ts' @@ -121,29 +120,15 @@ export async function startServer (options: StartServerOptions = {}): Promise<{ // Register a SERVER_EXITING handler for this startServer call // This handler self-removes when it fires - sbp('okTurtles.events/once', SERVER_EXITING, () => { - sbp('okTurtles.data/apply', PUBSUB_INSTANCE, function (pubsub: { on: (event: string, callback: () => void) => void; close: () => void; clients: { forEach: (callback: (client: { terminate: () => void }) => void) => void } }) { - sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { - return new Promise((resolve) => { - pubsub.on('close', async function () { - try { - removeSignalHandlers() - await sbp('chelonia.persistentActions/unload') - await stopServer() - console.info('Server down') - } catch (err) { - console.error(err, 'Error during shutdown') - } finally { - resolve() - } - }) - pubsub.close() - // Since `ws` v8.0, `WebSocketServer.close()` no longer closes remaining connections. - // See https://github.com/websockets/ws/commit/df7de574a07115e2321fdb5fc9b2d0fea55d27e8 - pubsub.clients.forEach((client: { terminate: () => void }) => client.terminate()) - }) - }) - }) + sbp('okTurtles.events/once', SERVER_EXITING, async () => { + try { + removeSignalHandlers() + await sbp('chelonia.persistentActions/unload') + await stopServer() + console.info('Server down') + } catch (err) { + console.error(err, 'Error during shutdown') + } }) // Start the server and wait for it to be running diff --git a/src/serve/ownerSizeTotalWorker.test.ts b/src/serve/ownerSizeTotalWorker.test.ts index ee3e3c6..daa0312 100644 --- a/src/serve/ownerSizeTotalWorker.test.ts +++ b/src/serve/ownerSizeTotalWorker.test.ts @@ -2,7 +2,7 @@ import { createCID } from 'npm:@chelonia/lib/functions' import sbp from 'npm:@sbp/sbp' // import { assert } from 'jsr:@std/assert' // TODO: Use for additional test assertions import createWorker from './createWorker.ts' -import { appendToIndexFactory, initDB, updateSize as updateSize_ } from './database.ts' +import { appendToIndexFactory, closeDB, initDB, updateSize as updateSize_ } from './database.ts' let worker = createWorker(new URL('./ownerSizeTotalWorker.ts', import.meta.url).toString()) @@ -263,6 +263,7 @@ Deno.test({ }) } finally { // Teardown + await closeDB() await worker.terminate() } } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index e6b9847..2bbe187 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -372,9 +372,9 @@ export function registerRoutes (app: Hono): void { // —BUT HTTP2 might be better than websockets and so we keep this around. // See related TODO in pubsub.js and the reddit discussion link. app.post('/event', + zValidator('header', eventHeaderSchema), bodyLimit({ maxSize: MEGABYTE }), authMiddleware('chel-shelter', 'optional'), - zValidator('header', eventHeaderSchema), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) // IMPORTANT: IT IS A REQUIREMENT THAT ANY PROXY SERVERS (E.G. nginx) IN FRONT OF US SET THE @@ -667,8 +667,8 @@ app.post('/name', async function (c) { // File upload route. // If accepted, the file will be stored in Chelonia DB. app.post('/file', - bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), authMiddleware('chel-shelter', 'required'), + bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) try { @@ -929,9 +929,9 @@ app.post('/name', async function (c) { }) app.post('/kv/:contractID/:key', - bodyLimit({ maxSize: 6 * MEGABYTE }), - authMiddleware('chel-shelter', 'required'), zValidator('param', kvParamSchema), + authMiddleware('chel-shelter', 'required'), + bodyLimit({ maxSize: 6 * MEGABYTE }), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) const { contractID, key } = c.req.valid('param') diff --git a/src/serve/server.ts b/src/serve/server.ts index 1379d7e..3b210f8 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -657,6 +657,8 @@ export async function stopServer (): Promise { // Close pubsub server (clears its ping interval) const pubsub = sbp('okTurtles.data/get', PUBSUB_INSTANCE) as { close: () => void; clients: Set<{ terminate: () => void }> } | undefined if (pubsub) { + // Since `ws` v8.0, `WebSocketServer.close()` no longer closes remaining connections. + // See https://github.com/websockets/ws/commit/df7de574a07115e2321fdb5fc9b2d0fea55d27e8 pubsub.clients.forEach((client) => client.terminate()) pubsub.close() sbp('okTurtles.data/delete', PUBSUB_INSTANCE) diff --git a/src/serve/zkppSalt.test.ts b/src/serve/zkppSalt.test.ts index 8a78365..cdda52a 100644 --- a/src/serve/zkppSalt.test.ts +++ b/src/serve/zkppSalt.test.ts @@ -1,7 +1,7 @@ import { Buffer } from 'node:buffer' import { AUTHSALT, CONTRACTSALT, CS, SALT_LENGTH_IN_OCTETS, SU } from 'npm:@chelonia/lib/zkppConstants' import tweetnacl from 'npm:tweetnacl' -import { initDB } from './database.ts' +import { closeDB, initDB } from './database.ts' const nacl = tweetnacl @@ -144,5 +144,7 @@ Deno.test({ const updateRes = await updateContractSalt(contract, r, challenge.s, challenge.sig, Buffer.from(hc).toString('base64url'), encryptedArgs) if (!updateRes) throw new Error('updateContractSalt should be successful') }) + + await closeDB() } }) diff --git a/src/upload.ts b/src/upload.ts index 20068cf..5016e14 100644 --- a/src/upload.ts +++ b/src/upload.ts @@ -4,51 +4,59 @@ import { Buffer } from 'node:buffer' import { multicodes } from 'npm:@chelonia/lib/functions' import sbp from 'npm:@sbp/sbp' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' -import { initDB } from './serve/database.ts' +import { closeDB, initDB } from './serve/database.ts' import { createEntryFromFile, type Entry } from './utils.ts' type Params = { url?: string, files: string[] } export async function upload (args: ArgumentsCamelCase, internal = false): Promise<[string, string][]> { const { url, files } = args + let dbOpen = false if (!url) { await initDB({ skipDbPreloading: true }) + dbOpen = true } - const uploaded: Array<[string, string]> = [] - const uploaderFn = url - ? uploadEntryToURL - : uploadEntryToDB - for (const filepath_ of files) { - let type = multicodes.RAW - let filepath = filepath_ - if (internal) { + try { + const uploaded: Array<[string, string]> = [] + const uploaderFn = url + ? uploadEntryToURL + : uploadEntryToDB + for (const filepath_ of files) { + let type = multicodes.RAW + let filepath = filepath_ + if (internal) { // The `{type}|` prefix is used to determine which kind of CID is needed - if (filepath_[1] !== '|') throw new Error('Invalid path format') - switch (filepath_[0]) { - case 'r': - // raw file type - break - case 'm': - type = multicodes.SHELTER_CONTRACT_MANIFEST - break - case 't': - type = multicodes.SHELTER_CONTRACT_TEXT - break - default: - throw new Error('Unknown file type: ' + filepath_[0]) + if (filepath_[1] !== '|') throw new Error('Invalid path format') + switch (filepath_[0]) { + case 'r': + // raw file type + break + case 'm': + type = multicodes.SHELTER_CONTRACT_MANIFEST + break + case 't': + type = multicodes.SHELTER_CONTRACT_TEXT + break + default: + throw new Error('Unknown file type: ' + filepath_[0]) + } + filepath = filepath_.slice(2) } - filepath = filepath_.slice(2) + const entry = await createEntryFromFile(filepath, type) + const destination = await uploaderFn(entry, url!) + if (!internal) { + console.log(colors.green('uploaded:'), destination) + } else { + console.log(colors.green(`${path.relative('.', filepath)}:`), destination) + } + uploaded.push([filepath, destination]) } - const entry = await createEntryFromFile(filepath, type) - const destination = await uploaderFn(entry, url!) - if (!internal) { - console.log(colors.green('uploaded:'), destination) - } else { - console.log(colors.green(`${path.relative('.', filepath)}:`), destination) + return uploaded + } finally { + if (dbOpen) { + await closeDB() } - uploaded.push([filepath, destination]) } - return uploaded } async function uploadEntryToURL ([cid, buffer]: Entry, url: string): Promise { From 6b1317db0f276bc5f3b8e7522c9ca2c0a568a261 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 17:08:54 +0000 Subject: [PATCH 43/71] Feedback --- build/main.js | 185 ++++++++++++++++--------------- scripts/build.ts | 2 +- src/migrate.ts | 197 +++++++++++++++++---------------- src/serve/database.ts | 4 +- src/serve/zkppSalt.test.ts | 218 +++++++++++++++++++------------------ 5 files changed, 303 insertions(+), 303 deletions(-) diff --git a/build/main.js b/build/main.js index 7d4366b..0607441 100644 --- a/build/main.js +++ b/build/main.js @@ -68400,8 +68400,8 @@ function installBaseSelectorsOnce() { yield "]"; }(), { encoding: "utf-8", objectMode: false }); stream.headers = { - "shelter-headinfo-head": latestHEADinfo.HEAD, - "shelter-headinfo-height": latestHEADinfo.height + "shelter-headinfo-head": String(latestHEADinfo.HEAD), + "shelter-headinfo-height": String(latestHEADinfo.height) }; return stream; }, @@ -69040,108 +69040,107 @@ async function migrate(args) { console.error("Error setting up database"); exit(e2); throw e2; - } finally { - closeDB(); } let backendTo; try { - let toConfigOpts; - if (args.toConfig) { - const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); - const toBackend = toConfig?.database?.backend; - if (toBackend !== to) { - console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); - } - toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; - } else { - toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; + try { + let toConfigOpts; + if (args.toConfig) { + const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); + const toBackend = toConfig?.database?.backend; + if (toBackend !== to) { + console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); + } + toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; + } else { + toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; + } + const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; + backendTo = new Ctor(toConfigOpts); + await backendTo.init(); + } catch (error2) { + exit(error2); + throw error2; } - const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; - backendTo = new Ctor(toConfigOpts); - await backendTo.init(); - } catch (error2) { - exit(error2); - throw error2; - } - const numKeys2 = await esm_default("chelonia.db/keyCount"); - let numMigratedKeys = 0; - let numVisitedKeys = 0; - const reportStatus = () => { - console.log(`${green("Migrated:")} ${numMigratedKeys} entries`); - }; - const checkAndExit = (() => { - let interruptCount = 0; - let shouldExit = 0; - const handleSignal = (signal, code2) => { - process3.on(signal, () => { - shouldExit = 128 + code2; - if (++interruptCount < 3) { - console.error(`Received signal ${signal} (${code2}). Finishing current operation.`); - } else { - console.error(`Received signal ${signal} (${code2}). Force quitting.`); + const numKeys2 = await esm_default("chelonia.db/keyCount"); + let numMigratedKeys = 0; + let numVisitedKeys = 0; + const reportStatus = () => { + console.log(`${green("Migrated:")} ${numMigratedKeys} entries`); + }; + const checkAndExit = (() => { + let interruptCount = 0; + let shouldExit = 0; + const handleSignal = (signal, code2) => { + process3.on(signal, () => { + shouldExit = 128 + code2; + if (++interruptCount < 3) { + console.error(`Received signal ${signal} (${code2}). Finishing current operation.`); + } else { + console.error(`Received signal ${signal} (${code2}). Force quitting.`); + reportStatus(); + exit(shouldExit); + } + }); + }; + const checkAndExit2 = async () => { + if (shouldExit) { + await backendTo.close(); reportStatus(); exit(shouldExit); } - }); - }; - const checkAndExit2 = async () => { - if (shouldExit) { - await backendTo.close(); + }; + [ + ["SIGHUP", 1], + ["SIGINT", 2], + ["SIGQUIT", 3], + ["SIGTERM", 15], + ["SIGUSR1", 10], + ["SIGUSR2", 11] + ].forEach(([signal, code2]) => handleSignal(signal, code2)); + return checkAndExit2; + })(); + let lastReportedPercentage = 0; + for await (const key of esm_default("chelonia.db/iterKeys")) { + numVisitedKeys++; + if (!isValidKey(key)) { + console.debug("Skipping invalid key", key); + continue; + } + let value; + try { + value = await esm_default("chelonia.db/get", `any:${key}`); + } catch (e2) { + reportStatus(); + console.error(`Error reading from source database key '${key}'`, e2); + exit(1); + throw e2; + } + await checkAndExit(); + if (value === void 0) { + console.debug("Skipping empty key", key); + continue; + } + try { + await backendTo.writeData(key, value); + } catch (e2) { reportStatus(); - exit(shouldExit); + console.error(`Error writing to target database key '${key}'`, e2); + exit(1); + throw e2; + } + await checkAndExit(); + ++numMigratedKeys; + const percentage = Math.floor(numVisitedKeys / numKeys2 * 100); + if (percentage - lastReportedPercentage >= 10) { + lastReportedPercentage = percentage; + console.log(`Migrating... ${percentage}% done`); } - }; - [ - ["SIGHUP", 1], - ["SIGINT", 2], - ["SIGQUIT", 3], - ["SIGTERM", 15], - ["SIGUSR1", 10], - ["SIGUSR2", 11] - ].forEach(([signal, code2]) => handleSignal(signal, code2)); - return checkAndExit2; - })(); - let lastReportedPercentage = 0; - for await (const key of esm_default("chelonia.db/iterKeys")) { - numVisitedKeys++; - if (!isValidKey(key)) { - console.debug("Skipping invalid key", key); - continue; - } - let value; - try { - value = await esm_default("chelonia.db/get", `any:${key}`); - } catch (e2) { - reportStatus(); - console.error(`Error reading from source database key '${key}'`, e2); - await backendTo.close(); - exit(1); - throw e2; - } - await checkAndExit(); - if (value === void 0) { - console.debug("Skipping empty key", key); - continue; - } - try { - await backendTo.writeData(key, value); - } catch (e2) { - reportStatus(); - console.error(`Error writing to target database key '${key}'`, e2); - await backendTo.close(); - exit(1); - throw e2; - } - await checkAndExit(); - ++numMigratedKeys; - const percentage = Math.floor(numVisitedKeys / numKeys2 * 100); - if (percentage - lastReportedPercentage >= 10) { - lastReportedPercentage = percentage; - console.log(`Migrating... ${percentage}% done`); } + reportStatus(); + } finally { + await Promise.all([backendTo.close(), closeDB()]); } - reportStatus(); - await backendTo.close(); } var module9 = { builder: (yargs) => { diff --git a/scripts/build.ts b/scripts/build.ts index df6d779..57cddba 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -35,7 +35,7 @@ const options: esbuild.BuildOptions = { { name: 'node-builtins', setup (build) { - build.onResolve({ filter: /^[a-zA-Z]/, namespace: 'file' }, ({ path }) => { + build.onResolve({ filter: /^[0-9a-zA-Z_/]+$/, namespace: 'file' }, ({ path }) => { if (nodeBuiltins.has(path)) { return { path: `node:${path}`, external: true } } diff --git a/src/migrate.ts b/src/migrate.ts index c315994..a698de0 100644 --- a/src/migrate.ts +++ b/src/migrate.ts @@ -35,126 +35,125 @@ export async function migrate (args: ArgumentsCamelCase): Promise console.error('Error setting up database') exit(e) throw e - } finally { - closeDB() } - let backendTo: DatabaseBackend + let backendTo: DatabaseBackend | undefined try { - let toConfigOpts: unknown - if (args.toConfig) { - const toConfig = parse(await readFile(args.toConfig, { encoding: 'utf-8', flag: 'r' })) - const toBackend = (toConfig?.database as TomlTable)?.backend as string - if (toBackend !== to) { - console.warn(`--to-config has backend ${toBackend} but --to is ${to}`) + try { + let toConfigOpts: unknown + if (args.toConfig) { + const toConfig = parse(await readFile(args.toConfig, { encoding: 'utf-8', flag: 'r' })) + const toBackend = (toConfig?.database as TomlTable)?.backend as string + if (toBackend !== to) { + console.warn(`--to-config has backend ${toBackend} but --to is ${to}`) + } + toConfigOpts = ((toConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[to] || {} + } else { + toConfigOpts = nconf.get(`database:backendOptions:${to}`) || {} } - toConfigOpts = ((toConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[to] || {} - } else { - toConfigOpts = nconf.get(`database:backendOptions:${to}`) || {} - } - const Ctor = (await import(`./serve/database-${to}.ts`)).default - backendTo = new Ctor(toConfigOpts) - await backendTo.init() - } catch (error) { - exit(error) - throw error - } + const Ctor = (await import(`./serve/database-${to}.ts`)).default + backendTo = new Ctor(toConfigOpts) + await backendTo!.init() + } catch (error) { + exit(error) + throw error + } - const numKeys = await sbp('chelonia.db/keyCount') - let numMigratedKeys = 0 - let numVisitedKeys = 0 + const numKeys = await sbp('chelonia.db/keyCount') + let numMigratedKeys = 0 + let numVisitedKeys = 0 - const reportStatus = () => { - console.log(`${colors.green('Migrated:')} ${numMigratedKeys} entries`) - } + const reportStatus = () => { + console.log(`${colors.green('Migrated:')} ${numMigratedKeys} entries`) + } - const checkAndExit = (() => { - let interruptCount = 0 - let shouldExit = 0 + const checkAndExit = (() => { + let interruptCount = 0 + let shouldExit = 0 - const handleSignal = (signal: string, code: number) => { - process.on(signal, () => { + const handleSignal = (signal: string, code: number) => { + process.on(signal, () => { // Exit codes follow the 128 + signal code convention. // See - shouldExit = 128 + code + shouldExit = 128 + code + + if (++interruptCount < 3) { + console.error(`Received signal ${signal} (${code}). Finishing current operation.`) + } else { + console.error(`Received signal ${signal} (${code}). Force quitting.`) + reportStatus() + exit(shouldExit) + } + }) + } - if (++interruptCount < 3) { - console.error(`Received signal ${signal} (${code}). Finishing current operation.`) - } else { - console.error(`Received signal ${signal} (${code}). Force quitting.`) + const checkAndExit = async () => { + if (shouldExit) { + await backendTo!.close() reportStatus() exit(shouldExit) } - }) - } - - const checkAndExit = async () => { - if (shouldExit) { - await backendTo.close() - reportStatus() - exit(shouldExit) } - } // Codes from ;([ - ['SIGHUP', 1], - ['SIGINT', 2], - ['SIGQUIT', 3], - ['SIGTERM', 15], - ['SIGUSR1', 10], - ['SIGUSR2', 11] - ] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) - - return checkAndExit - })() - - let lastReportedPercentage = 0 - for await (const key of sbp('chelonia.db/iterKeys')) { - numVisitedKeys++ - if (!isValidKey(key)) { - console.debug('Skipping invalid key', key) - continue - } - // `any:` prefix needed to get the raw value, else the default is getting - // a string, which will be encoded as UTF-8. This can cause data loss. - let value: Buffer | string | undefined - try { - value = await sbp('chelonia.db/get', `any:${key}`) - } catch (e) { - reportStatus() - console.error(`Error reading from source database key '${key}'`, e) - await backendTo.close() - exit(1) - throw e - } - await checkAndExit() - // Make `deno check` happy. - if (value === undefined) { - console.debug('Skipping empty key', key) - continue - } - try { - await backendTo.writeData(key, value) - } catch (e) { - reportStatus() - console.error(`Error writing to target database key '${key}'`, e) - await backendTo.close() - exit(1) - throw e - } - await checkAndExit() - ++numMigratedKeys - // Prints a message roughly every 10% of progress. - const percentage = Math.floor((numVisitedKeys / numKeys) * 100) - if (percentage - lastReportedPercentage >= 10) { - lastReportedPercentage = percentage - console.log(`Migrating... ${percentage}% done`) + ['SIGHUP', 1], + ['SIGINT', 2], + ['SIGQUIT', 3], + ['SIGTERM', 15], + ['SIGUSR1', 10], + ['SIGUSR2', 11] + ] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) + + return checkAndExit + })() + + let lastReportedPercentage = 0 + for await (const key of sbp('chelonia.db/iterKeys')) { + numVisitedKeys++ + if (!isValidKey(key)) { + console.debug('Skipping invalid key', key) + continue + } + // `any:` prefix needed to get the raw value, else the default is getting + // a string, which will be encoded as UTF-8. This can cause data loss. + let value: Buffer | string | undefined + try { + value = await sbp('chelonia.db/get', `any:${key}`) + } catch (e) { + reportStatus() + console.error(`Error reading from source database key '${key}'`, e) + exit(1) + throw e + } + await checkAndExit() + // Make `deno check` happy. + if (value === undefined) { + console.debug('Skipping empty key', key) + continue + } + try { + await backendTo!.writeData(key, value) + } catch (e) { + reportStatus() + console.error(`Error writing to target database key '${key}'`, e) + exit(1) + throw e + } + await checkAndExit() + ++numMigratedKeys + // Prints a message roughly every 10% of progress. + const percentage = Math.floor((numVisitedKeys / numKeys) * 100) + if (percentage - lastReportedPercentage >= 10) { + lastReportedPercentage = percentage + console.log(`Migrating... ${percentage}% done`) + } } + reportStatus() + } finally { + await Promise.all([backendTo!.close(), closeDB()]) } - reportStatus() - await backendTo.close() } export const module = { diff --git a/src/serve/database.ts b/src/serve/database.ts index 080eab6..33f0bb3 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -158,8 +158,8 @@ function installBaseSelectorsOnce () { // Add headers to stream (TypeScript workaround) ;(stream as { headers?: Record }).headers = { - 'shelter-headinfo-head': latestHEADinfo.HEAD, - 'shelter-headinfo-height': latestHEADinfo.height + 'shelter-headinfo-head': String(latestHEADinfo.HEAD), + 'shelter-headinfo-height': String(latestHEADinfo.height) } return stream }, diff --git a/src/serve/zkppSalt.test.ts b/src/serve/zkppSalt.test.ts index cdda52a..deb7284 100644 --- a/src/serve/zkppSalt.test.ts +++ b/src/serve/zkppSalt.test.ts @@ -38,113 +38,115 @@ Deno.test({ async fn (t: Deno.TestContext) { // Setup await initDB() - await t.step('register() conforms to the API to register a new salt', async () => { - const keyPair = nacl.box.keyPair() - const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') - const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') - - const regKeyAlice1 = registrationKey('alice', publicKeyHash) - const regKeyAlice2 = registrationKey('alice', publicKeyHash) - if (typeof regKeyAlice1 !== 'object') throw new Error('regKeyAlice1 should be object') - if (typeof regKeyAlice2 !== 'object') throw new Error('regKeyAlice2 should be object') - const [, , encryptedHashedPasswordAlice1] = saltsAndEncryptedHashedPassword(regKeyAlice1.p, keyPair.secretKey, 'hash') - const res1 = register('alice', publicKey, regKeyAlice1.s, regKeyAlice1.sig, encryptedHashedPasswordAlice1) - if (typeof res1 !== 'string') throw new Error('register should return a token (alice)') - const token = decryptRegistrationRedemptionToken(regKeyAlice1.p, keyPair.secretKey, res1) - await redeemSaltRegistrationToken('alice', 'alice', token) - - const [, , encryptedHashedPasswordAlice2] = saltsAndEncryptedHashedPassword(regKeyAlice1.p, keyPair.secretKey, 'hash') - const res2 = register('alice', publicKey, regKeyAlice2.s, regKeyAlice2.sig, encryptedHashedPasswordAlice2) - if (res2 !== false) throw new Error('register should not overwrite entry (alice)') - - const regKeyBob1 = registrationKey('bob', publicKeyHash) - if (typeof regKeyBob1 !== 'object') throw new Error('regKeyBob1 should be object') - const [, , encryptedHashedPasswordBob1] = saltsAndEncryptedHashedPassword(regKeyBob1.p, keyPair.secretKey, 'hash') - const res3 = register('bob', publicKey, regKeyBob1.s, regKeyBob1.sig, encryptedHashedPasswordBob1) - if (typeof res3 !== 'string') throw new Error('register should return a token (bob)') - }) - - await t.step('getContractSalt() conforms to the API to obtain salt', async () => { - const keyPair = nacl.box.keyPair() - const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') - const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') - - const [contract, hash, r] = ['getContractSalt', 'hash', 'r'] - const regKey = registrationKey(contract, publicKeyHash) - if (typeof regKey !== 'object') throw new Error('regKey should be object') - if (!regKey) throw new Error('regKey should not be false') - - const [authSalt, contractSalt, encryptedHashedPassword] = saltsAndEncryptedHashedPassword(regKey.p, keyPair.secretKey, hash) - - const res = register(contract, publicKey, regKey.s, regKey.sig, encryptedHashedPassword) - if (typeof res !== 'string') throw new Error('register should allow new entry (' + contract + ')') - const token = decryptRegistrationRedemptionToken(regKey.p, keyPair.secretKey, res as string) - await redeemSaltRegistrationToken(contract, contract, token) - - const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') - const challenge = await getChallenge(contract, b) - if (typeof challenge !== 'object') throw new Error('challenge should be object') - if (!challenge) throw new Error('challenge should not be false') - if (challenge.authSalt !== authSalt) throw new Error('mismatched authSalt') - - const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) - const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) - const hc = nacl.hash(c) - - const salt = await getContractSalt(contract, r, challenge.s, challenge.sig, Buffer.from(hc).toString('base64url')) - if (typeof salt !== 'string') throw new Error('salt response should be string') - if (!salt) throw new Error('salt should not be false') - - const saltBuf = Buffer.from(salt, 'base64url') - const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) - const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) - const [retrievedContractSalt] = JSON.parse( - (() => { - const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) - if (!decrypted) throw new Error('Failed to decrypt salt') - return Buffer.from(decrypted).toString() - })() - ) - if (retrievedContractSalt !== contractSalt) throw new Error('mismatched contractSalt') - }) - - await t.step('updateContractSalt() conforms to the API to update salt', async () => { - const keyPair = nacl.box.keyPair() - const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') - const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') - - const [contract, hash, r] = ['update', 'hash', 'r'] - const regKey = registrationKey(contract, publicKeyHash) - if (typeof regKey !== 'object') throw new Error('regKey should be object') - if (!regKey) throw new Error('regKey should not be false') - - const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(regKey.p, keyPair.secretKey, hash) - - const res = register(contract, publicKey, regKey.s, regKey.sig, encryptedHashedPassword) - if (typeof res !== 'string') throw new Error('register should allow new entry (' + contract + ')') - const token = decryptRegistrationRedemptionToken(regKey.p, keyPair.secretKey, res as string) - await redeemSaltRegistrationToken(contract, contract, token) - - const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') - const challenge = await getChallenge(contract, b) - if (typeof challenge !== 'object') throw new Error('challenge should be object') - if (challenge.authSalt !== authSalt) throw new Error('mismatched authSalt') - - const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) - const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) - const hc = nacl.hash(c) - - const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(SU), c])).slice(0, nacl.secretbox.keyLength) - const nonce = nacl.randomBytes(nacl.secretbox.nonceLength) - - const encryptedArgsCiphertext = nacl.secretbox(Buffer.from(JSON.stringify(['a', 'b', 'c'])), nonce, encryptionKey) - - const encryptedArgs = Buffer.concat([nonce, encryptedArgsCiphertext]).toString('base64url') - - const updateRes = await updateContractSalt(contract, r, challenge.s, challenge.sig, Buffer.from(hc).toString('base64url'), encryptedArgs) - if (!updateRes) throw new Error('updateContractSalt should be successful') - }) - - await closeDB() + try { + await t.step('register() conforms to the API to register a new salt', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const regKeyAlice1 = registrationKey('alice', publicKeyHash) + const regKeyAlice2 = registrationKey('alice', publicKeyHash) + if (typeof regKeyAlice1 !== 'object') throw new Error('regKeyAlice1 should be object') + if (typeof regKeyAlice2 !== 'object') throw new Error('regKeyAlice2 should be object') + const [, , encryptedHashedPasswordAlice1] = saltsAndEncryptedHashedPassword(regKeyAlice1.p, keyPair.secretKey, 'hash') + const res1 = register('alice', publicKey, regKeyAlice1.s, regKeyAlice1.sig, encryptedHashedPasswordAlice1) + if (typeof res1 !== 'string') throw new Error('register should return a token (alice)') + const token = decryptRegistrationRedemptionToken(regKeyAlice1.p, keyPair.secretKey, res1) + await redeemSaltRegistrationToken('alice', 'alice', token) + + const [, , encryptedHashedPasswordAlice2] = saltsAndEncryptedHashedPassword(regKeyAlice1.p, keyPair.secretKey, 'hash') + const res2 = register('alice', publicKey, regKeyAlice2.s, regKeyAlice2.sig, encryptedHashedPasswordAlice2) + if (res2 !== false) throw new Error('register should not overwrite entry (alice)') + + const regKeyBob1 = registrationKey('bob', publicKeyHash) + if (typeof regKeyBob1 !== 'object') throw new Error('regKeyBob1 should be object') + const [, , encryptedHashedPasswordBob1] = saltsAndEncryptedHashedPassword(regKeyBob1.p, keyPair.secretKey, 'hash') + const res3 = register('bob', publicKey, regKeyBob1.s, regKeyBob1.sig, encryptedHashedPasswordBob1) + if (typeof res3 !== 'string') throw new Error('register should return a token (bob)') + }) + + await t.step('getContractSalt() conforms to the API to obtain salt', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const [contract, hash, r] = ['getContractSalt', 'hash', 'r'] + const regKey = registrationKey(contract, publicKeyHash) + if (typeof regKey !== 'object') throw new Error('regKey should be object') + if (!regKey) throw new Error('regKey should not be false') + + const [authSalt, contractSalt, encryptedHashedPassword] = saltsAndEncryptedHashedPassword(regKey.p, keyPair.secretKey, hash) + + const res = register(contract, publicKey, regKey.s, regKey.sig, encryptedHashedPassword) + if (typeof res !== 'string') throw new Error('register should allow new entry (' + contract + ')') + const token = decryptRegistrationRedemptionToken(regKey.p, keyPair.secretKey, res as string) + await redeemSaltRegistrationToken(contract, contract, token) + + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challenge = await getChallenge(contract, b) + if (typeof challenge !== 'object') throw new Error('challenge should be object') + if (!challenge) throw new Error('challenge should not be false') + if (challenge.authSalt !== authSalt) throw new Error('mismatched authSalt') + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const salt = await getContractSalt(contract, r, challenge.s, challenge.sig, Buffer.from(hc).toString('base64url')) + if (typeof salt !== 'string') throw new Error('salt response should be string') + if (!salt) throw new Error('salt should not be false') + + const saltBuf = Buffer.from(salt, 'base64url') + const nonce = saltBuf.slice(0, nacl.secretbox.nonceLength) + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(CS), c])).slice(0, nacl.secretbox.keyLength) + const [retrievedContractSalt] = JSON.parse( + (() => { + const decrypted = nacl.secretbox.open(saltBuf.slice(nacl.secretbox.nonceLength), nonce, encryptionKey) + if (!decrypted) throw new Error('Failed to decrypt salt') + return Buffer.from(decrypted).toString() + })() + ) + if (retrievedContractSalt !== contractSalt) throw new Error('mismatched contractSalt') + }) + + await t.step('updateContractSalt() conforms to the API to update salt', async () => { + const keyPair = nacl.box.keyPair() + const publicKey = Buffer.from(keyPair.publicKey).toString('base64url') + const publicKeyHash = Buffer.from(nacl.hash(Buffer.from(publicKey))).toString('base64url') + + const [contract, hash, r] = ['update', 'hash', 'r'] + const regKey = registrationKey(contract, publicKeyHash) + if (typeof regKey !== 'object') throw new Error('regKey should be object') + if (!regKey) throw new Error('regKey should not be false') + + const [authSalt, , encryptedHashedPassword] = saltsAndEncryptedHashedPassword(regKey.p, keyPair.secretKey, hash) + + const res = register(contract, publicKey, regKey.s, regKey.sig, encryptedHashedPassword) + if (typeof res !== 'string') throw new Error('register should allow new entry (' + contract + ')') + const token = decryptRegistrationRedemptionToken(regKey.p, keyPair.secretKey, res as string) + await redeemSaltRegistrationToken(contract, contract, token) + + const b = Buffer.from(nacl.hash(Buffer.from(r))).toString('base64url') + const challenge = await getChallenge(contract, b) + if (typeof challenge !== 'object') throw new Error('challenge should be object') + if (challenge.authSalt !== authSalt) throw new Error('mismatched authSalt') + + const ħ = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(r)), nacl.hash(Buffer.from(challenge.s))])) + const c = nacl.hash(Buffer.concat([nacl.hash(Buffer.from(hash)), nacl.hash(ħ)])) + const hc = nacl.hash(c) + + const encryptionKey = nacl.hash(Buffer.concat([Buffer.from(SU), c])).slice(0, nacl.secretbox.keyLength) + const nonce = nacl.randomBytes(nacl.secretbox.nonceLength) + + const encryptedArgsCiphertext = nacl.secretbox(Buffer.from(JSON.stringify(['a', 'b', 'c'])), nonce, encryptionKey) + + const encryptedArgs = Buffer.concat([nonce, encryptedArgsCiphertext]).toString('base64url') + + const updateRes = await updateContractSalt(contract, r, challenge.s, challenge.sig, Buffer.from(hc).toString('base64url'), encryptedArgs) + if (!updateRes) throw new Error('updateContractSalt should be successful') + }) + } finally { + await closeDB() + } } }) From e33f433c07d6d6f18ed268c2fc02044f1ac3a9a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:56:57 +0000 Subject: [PATCH 44/71] Feedback --- build/main.js | 214 ++++++++++++++++++++-------------------- src/migrate.ts | 2 +- src/serve/routes.ts | 232 +++++++++++++++++++++++--------------------- 3 files changed, 230 insertions(+), 218 deletions(-) diff --git a/build/main.js b/build/main.js index 0607441..cc19b71 100644 --- a/build/main.js +++ b/build/main.js @@ -69139,7 +69139,7 @@ async function migrate(args) { } reportStatus(); } finally { - await Promise.all([backendTo.close(), closeDB()]); + await Promise.all([backendTo?.close(), closeDB()]); } } var module9 = { @@ -72893,7 +72893,7 @@ function parseBooleanParam(value) { var CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; var KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; var NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? { - const contentType = c.req.header("content-type") || ""; + const contentType = (c.req.header("content-type") || "").trim().toLowerCase(); let data; try { - if (contentType.includes("application/x-www-form-urlencoded")) { + if (contentType.startsWith("application/x-www-form-urlencoded")) { const form = await c.req.parseBody(); data = Object.fromEntries( Object.entries(form).filter(([, v2]) => typeof v2 === "string") ); - } else { + } else if (contentType.startsWith("application/json")) { data = await c.req.json(); + } else { + throw new HTTPException(415, { message: "Content-Type header expected with form or JSON data" }); } } catch { throw new HTTPException(400, { message: "Invalid request body" }); @@ -73145,7 +73113,12 @@ function registerRoutes(app2) { const staticServeConfig = getStaticServeConfig(); app2.post( "/event", - zValidator("header", eventHeaderSchema), + zValidator("header", object({ + "shelter-namespace-registration": nameSchema.optional(), + "shelter-salt-update-token": string2().optional(), + "shelter-salt-registration-token": string2().optional(), + "shelter-deletion-token-digest": string2().optional() + }).strict()), bodyLimit({ maxSize: MEGABYTE }), authMiddleware("chel-shelter", "optional"), async function(c) { @@ -73249,7 +73222,11 @@ function registerRoutes(app2) { ); app2.get( "/eventsAfter/:contractID/:since/:limit?", - zValidator("param", eventsAfterParamSchema), + zValidator("param", object({ + contractID: cidSchema, + since: nonNegativeIntegerSchema, + limit: nonNegativeIntegerSchema.optional() + }).strict()), async function(c) { const { contractID, since, limit } = c.req.valid("param"); const keyOps2 = c.req.query("keyOps"); @@ -73260,6 +73237,7 @@ function registerRoutes(app2) { throw new HTTPException(400); } const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: parseBooleanParam(keyOps2) }); + stream.on("error", (err) => logger_default.error("eventsAfter stream error", err)); c.req.raw.signal.addEventListener("abort", () => stream.destroy()); const streamHeaders = stream.headers || {}; const webStream = Readable3.toWeb(stream); @@ -73301,36 +73279,44 @@ function registerRoutes(app2) { return c.body(null, 200); }); } - app2.get("/name/:name", zValidator("param", nameParamSchema), async function(c) { - const { name } = c.req.valid("param"); - try { - const lookupResult = await esm_default("backend/db/lookupName", name); - return lookupResult ? c.text(lookupResult) : notFoundNoCache(c); - } catch (err) { - logger_default.error(err, `GET /name/${name}`, err.message); - throw err; - } - }); - app2.get("/latestHEADinfo/:contractID", zValidator("param", cidParamSchema), async function(c) { - const { contractID } = c.req.valid("param"); - try { - const parsed = maybeParseCID(contractID); - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400); - const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); - if (HEADinfo === "") { - throw new HTTPException(410); + app2.get( + "/name/:name", + zValidator("param", object({ name: nameSchema }).strict()), + async function(c) { + const { name } = c.req.valid("param"); + try { + const lookupResult = await esm_default("backend/db/lookupName", name); + return lookupResult ? c.text(lookupResult) : notFoundNoCache(c); + } catch (err) { + logger_default.error(err, `GET /name/${name}`, err.message); + throw err; } - if (!HEADinfo) { - console.warn(`[backend] latestHEADinfo not found for ${contractID}`); - return notFoundNoCache(c); + } + ); + app2.get( + "/latestHEADinfo/:contractID", + zValidator("param", object({ contractID: cidSchema }).strict()), + async function(c) { + const { contractID } = c.req.valid("param"); + try { + const parsed = maybeParseCID(contractID); + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400); + const HEADinfo = await esm_default("chelonia/db/latestHEADinfo", contractID); + if (HEADinfo === "") { + throw new HTTPException(410); + } + if (!HEADinfo) { + console.warn(`[backend] latestHEADinfo not found for ${contractID}`); + return notFoundNoCache(c); + } + return c.json(HEADinfo, 200, { "Cache-Control": "no-store" }); + } catch (err) { + if (err instanceof HTTPException) throw err; + logger_default.error(err, `GET /latestHEADinfo/${contractID}`, err.message); + throw err; } - return c.json(HEADinfo, 200, { "Cache-Control": "no-store" }); - } catch (err) { - if (err instanceof HTTPException) throw err; - logger_default.error(err, `GET /latestHEADinfo/${contractID}`, err.message); - throw err; } - }); + ); app2.get("/time", function(c) { return c.text((/* @__PURE__ */ new Date()).toISOString(), 200, { "Cache-Control": "no-store" @@ -73457,36 +73443,40 @@ function registerRoutes(app2) { } } ); - app2.get("/file/:hash", zValidator("param", cidHashParamSchema), async function(c) { - const { hash: hash3 } = c.req.valid("param"); - const parsed = maybeParseCID(hash3); - if (!parsed) { - throw new HTTPException(400); - } - const blobOrString = await esm_default("chelonia.db/get", `any:${hash3}`); - if (blobOrString?.length === 0) { - throw new HTTPException(410); - } else if (!blobOrString) { - return notFoundNoCache(c); + app2.get( + "/file/:hash", + zValidator("param", object({ hash: cidSchema }).strict()), + async function(c) { + const { hash: hash3 } = c.req.valid("param"); + const parsed = maybeParseCID(hash3); + if (!parsed) { + throw new HTTPException(400); + } + const blobOrString = await esm_default("chelonia.db/get", `any:${hash3}`); + if (blobOrString?.length === 0) { + throw new HTTPException(410); + } else if (!blobOrString) { + return notFoundNoCache(c); + } + const type = cidLookupTable[parsed.code] || "application/octet-stream"; + return c.body(blobOrString, 200, { + "ETag": `"${hash3}"`, + "Cache-Control": "public,max-age=31536000,immutable", + // CSP to disable everything -- this only affects direct navigation to the + // `/file` URL. + // The CSP below prevents any sort of resource loading or script execution + // on direct navigation. The `nosniff` header instructs the browser to + // honour the provided content-type. + "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox", + "X-Content-Type-Options": "nosniff", + "Content-Type": type + }); } - const type = cidLookupTable[parsed.code] || "application/octet-stream"; - return c.body(blobOrString, 200, { - "ETag": `"${hash3}"`, - "Cache-Control": "public,max-age=31536000,immutable", - // CSP to disable everything -- this only affects direct navigation to the - // `/file` URL. - // The CSP below prevents any sort of resource loading or script execution - // on direct navigation. The `nosniff` header instructs the browser to - // honour the provided content-type. - "Content-Security-Policy": "default-src 'none'; frame-ancestors 'none'; form-action 'none'; upgrade-insecure-requests; sandbox", - "X-Content-Type-Options": "nosniff", - "Content-Type": type - }); - }); + ); app2.post( "/deleteFile/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), - zValidator("param", cidHashParamSchema), + zValidator("param", object({ hash: cidSchema }).strict()), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const { hash: hash3 } = c.req.valid("param"); @@ -73533,7 +73523,7 @@ function registerRoutes(app2) { app2.post( "/deleteContract/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), - zValidator("param", cidHashParamSchema), + zValidator("param", object({ hash: cidSchema }).strict()), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const { hash: hash3 } = c.req.valid("param"); @@ -73580,7 +73570,7 @@ function registerRoutes(app2) { ); app2.post( "/kv/:contractID/:key", - zValidator("param", kvParamSchema), + zValidator("param", object({ contractID: cidSchema, key: kvKeySchema }).strict()), authMiddleware("chel-shelter", "required"), bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { @@ -73647,7 +73637,7 @@ function registerRoutes(app2) { app2.get( "/kv/:contractID/:key", authMiddleware("chel-shelter", "required"), - zValidator("param", kvParamSchema), + zValidator("param", object({ contractID: cidSchema, key: kvKeySchema }).strict()), async function(c) { const { contractID, key } = c.req.valid("param"); const parsed = maybeParseCID(contractID); @@ -73698,9 +73688,13 @@ function registerRoutes(app2) { app2.get("/", function(c) { return c.redirect(staticServeConfig.redirect); }); + const zkppRegisterBodySchema = union([ + object({ b: string2() }).strict(), + object({ r: string2(), s: string2(), sig: string2(), Eh: string2() }).strict() + ]); app2.post( "/zkpp/register/:name", - zValidator("param", nameParamSchema), + zValidator("param", object({ name: nameSchema }).strict()), zValidatorFormOrJson(zkppRegisterBodySchema), async function(c) { const { name } = c.req.valid("param"); @@ -73732,8 +73726,8 @@ function registerRoutes(app2) { ); app2.get( "/zkpp/:contractID/auth_hash", - zValidator("param", zkppContractParamSchema), - zValidator("query", zkppAuthHashQuerySchema), + zValidator("param", object({ contractID: cidSchema }).strict()), + zValidator("query", object({ b: string2().min(1, "b is required") })), async function(c) { const { contractID } = c.req.valid("param"); const { b } = c.req.valid("query"); @@ -73750,8 +73744,13 @@ function registerRoutes(app2) { ); app2.get( "/zkpp/:contractID/contract_hash", - zValidator("param", zkppContractParamSchema), - zValidator("query", zkppContractHashQuerySchema), + zValidator("param", object({ contractID: cidSchema }).strict()), + zValidator("query", object({ + r: string2().min(1, "r is required"), + s: string2().min(1, "s is required"), + sig: string2().min(1, "sig is required"), + hc: string2().min(1, "hc is required") + }).strict()), async function(c) { const { contractID } = c.req.valid("param"); const { r, s, sig, hc } = c.req.valid("query"); @@ -73768,9 +73767,16 @@ function registerRoutes(app2) { throw new HTTPException(500, { message: "internal error" }); } ); + const zkppUpdatePasswordBodySchema = object({ + r: string2().min(1, "r is required"), + s: string2().min(1, "s is required"), + sig: string2().min(1, "sig is required"), + hc: string2().min(1, "hc is required"), + Ea: string2().min(1, "Ea is required") + }).strict(); app2.post( "/zkpp/:contractID/updatePasswordHash", - zValidator("param", zkppContractParamSchema), + zValidator("param", object({ contractID: cidSchema }).strict()), zValidatorFormOrJson(zkppUpdatePasswordBodySchema), async function(c) { const { contractID } = c.req.valid("param"); diff --git a/src/migrate.ts b/src/migrate.ts index a698de0..570c806 100644 --- a/src/migrate.ts +++ b/src/migrate.ts @@ -152,7 +152,7 @@ export async function migrate (args: ArgumentsCamelCase): Promise } reportStatus() } finally { - await Promise.all([backendTo!.close(), closeDB()]) + await Promise.all([backendTo?.close(), closeDB()]) } } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 2bbe187..bf8778c 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -50,7 +50,7 @@ const KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/ // - No two consecutive - or _ // - Allowed characters: lowercase letters, numbers, underscore and dashes const NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? = { @@ -79,60 +79,27 @@ const MIME_TYPES: Record = { const cidSchema = z.string().regex(CID_REGEX, 'Invalid CID') const nameSchema = z.string().regex(NAME_REGEX, 'Invalid name') const kvKeySchema = z.string().regex(KV_KEY_REGEX, 'Invalid key') -const positiveIntegerSchema = z.string().regex(POSITIVE_INTEGER_REGEX, 'Invalid positive integer') - -const cidParamSchema = z.object({ contractID: cidSchema }) -const cidHashParamSchema = z.object({ hash: cidSchema }) -const nameParamSchema = z.object({ name: nameSchema }) -const kvParamSchema = z.object({ contractID: cidSchema, key: kvKeySchema }) -const eventsAfterParamSchema = z.object({ - contractID: cidSchema, - since: positiveIntegerSchema, - limit: positiveIntegerSchema.optional() -}) -const zkppContractParamSchema = z.object({ contractID: cidSchema }) -const zkppAuthHashQuerySchema = z.object({ b: z.string().min(1, 'b is required') }) -const zkppContractHashQuerySchema = z.object({ - r: z.string().min(1, 'r is required'), - s: z.string().min(1, 's is required'), - sig: z.string().min(1, 'sig is required'), - hc: z.string().min(1, 'hc is required') -}) -const eventHeaderSchema = z.object({ - 'shelter-namespace-registration': nameSchema.optional(), - 'shelter-salt-update-token': z.string().optional(), - 'shelter-salt-registration-token': z.string().optional(), - 'shelter-deletion-token-digest': z.string().optional() -}) -const zkppRegisterBodySchema = z.union([ - z.object({ b: z.string() }), - z.object({ r: z.string(), s: z.string(), sig: z.string(), Eh: z.string() }) -]) -const zkppUpdatePasswordBodySchema = z.object({ - r: z.string().min(1, 'r is required'), - s: z.string().min(1, 's is required'), - sig: z.string().min(1, 'sig is required'), - hc: z.string().min(1, 'hc is required'), - Ea: z.string().min(1, 'Ea is required') -}) +const nonNegativeIntegerSchema = z.string().regex(NON_NEGATIVE_INTEGER_REGEX, 'Invalid positive integer') // Custom validator for endpoints that accept both JSON and form-urlencoded bodies function zValidatorFormOrJson ( schema: T ): MiddlewareHandler { return async (c, next) => { - const contentType = c.req.header('content-type') || '' + const contentType = (c.req.header('content-type') || '').trim().toLowerCase() let data: unknown try { - if (contentType.includes('application/x-www-form-urlencoded')) { + if (contentType.startsWith('application/x-www-form-urlencoded')) { const form = await c.req.parseBody() data = Object.fromEntries( Object.entries(form as Record) .filter(([, v]) => typeof v === 'string') ) - } else { + } else if (contentType.startsWith('application/json')) { data = await c.req.json() + } else { + throw new HTTPException(415, { message: 'Content-Type header expected with form or JSON data' }) } } catch { throw new HTTPException(400, { message: 'Invalid request body' }) @@ -372,7 +339,12 @@ export function registerRoutes (app: Hono): void { // —BUT HTTP2 might be better than websockets and so we keep this around. // See related TODO in pubsub.js and the reddit discussion link. app.post('/event', - zValidator('header', eventHeaderSchema), + zValidator('header', z.object({ + 'shelter-namespace-registration': nameSchema.optional(), + 'shelter-salt-update-token': z.string().optional(), + 'shelter-salt-registration-token': z.string().optional(), + 'shelter-deletion-token-digest': z.string().optional() + }).strict()), bodyLimit({ maxSize: MEGABYTE }), authMiddleware('chel-shelter', 'optional'), async function (c) { @@ -493,7 +465,11 @@ export function registerRoutes (app: Hono): void { }) app.get('/eventsAfter/:contractID/:since/:limit?', - zValidator('param', eventsAfterParamSchema), + zValidator('param', z.object({ + contractID: cidSchema, + since: nonNegativeIntegerSchema, + limit: nonNegativeIntegerSchema.optional() + }).strict()), async function (c) { const { contractID, since, limit } = c.req.valid('param') @@ -506,6 +482,7 @@ export function registerRoutes (app: Hono): void { } const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: parseBooleanParam(keyOps) }) as Readable + stream.on('error', (err) => logger.error('eventsAfter stream error', err)) // "On an HTTP server, make sure to manually close your streams if a request is aborted." // From: http://knexjs.org/#Interfaces-Streams // https://github.com/tgriesser/knex/wiki/Manually-Closing-Streams @@ -575,40 +552,46 @@ app.post('/name', async function (c) { }) */ - app.get('/name/:name', zValidator('param', nameParamSchema), async function (c) { - const { name } = c.req.valid('param') - try { - const lookupResult = await sbp('backend/db/lookupName', name) - return lookupResult - ? c.text(lookupResult) - : notFoundNoCache(c) - } catch (err) { - logger.error(err, `GET /name/${name}`, (err as Error).message) - throw err + app.get('/name/:name', + zValidator('param', z.object({ name: nameSchema }).strict()), + async function (c) { + const { name } = c.req.valid('param') + try { + const lookupResult = await sbp('backend/db/lookupName', name) + return lookupResult + ? c.text(lookupResult) + : notFoundNoCache(c) + } catch (err) { + logger.error(err, `GET /name/${name}`, (err as Error).message) + throw err + } } - }) + ) - app.get('/latestHEADinfo/:contractID', zValidator('param', cidParamSchema), async function (c) { - const { contractID } = c.req.valid('param') - try { - const parsed = maybeParseCID(contractID) - if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) + app.get('/latestHEADinfo/:contractID', + zValidator('param', z.object({ contractID: cidSchema }).strict()), + async function (c) { + const { contractID } = c.req.valid('param') + try { + const parsed = maybeParseCID(contractID) + if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) throw new HTTPException(400) - const HEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) - if (HEADinfo === '') { - throw new HTTPException(410) - } - if (!HEADinfo) { - console.warn(`[backend] latestHEADinfo not found for ${contractID}`) - return notFoundNoCache(c) + const HEADinfo = await sbp('chelonia/db/latestHEADinfo', contractID) + if (HEADinfo === '') { + throw new HTTPException(410) + } + if (!HEADinfo) { + console.warn(`[backend] latestHEADinfo not found for ${contractID}`) + return notFoundNoCache(c) + } + return c.json(HEADinfo, 200, { 'Cache-Control': 'no-store' }) + } catch (err) { + if (err instanceof HTTPException) throw err + logger.error(err, `GET /latestHEADinfo/${contractID}`, (err as Error).message) + throw err } - return c.json(HEADinfo, 200, { 'Cache-Control': 'no-store' }) - } catch (err) { - if (err instanceof HTTPException) throw err - logger.error(err, `GET /latestHEADinfo/${contractID}`, (err as Error).message) - throw err } - }) + ) app.get('/time', function (c) { return c.text(new Date().toISOString(), 200, { @@ -784,40 +767,43 @@ app.post('/name', async function (c) { // Serve data from Chelonia DB. // Note that a `Last-Modified` header isn't included in the response. - app.get('/file/:hash', zValidator('param', cidHashParamSchema), async function (c) { - const { hash } = c.req.valid('param') + app.get('/file/:hash', + zValidator('param', z.object({ hash: cidSchema }).strict()), + async function (c) { + const { hash } = c.req.valid('param') - const parsed = maybeParseCID(hash) - if (!parsed) { - throw new HTTPException(400) - } + const parsed = maybeParseCID(hash) + if (!parsed) { + throw new HTTPException(400) + } - const blobOrString = await sbp('chelonia.db/get', `any:${hash}`) - if (blobOrString?.length === 0) { - throw new HTTPException(410) - } else if (!blobOrString) { - return notFoundNoCache(c) - } + const blobOrString = await sbp('chelonia.db/get', `any:${hash}`) + if (blobOrString?.length === 0) { + throw new HTTPException(410) + } else if (!blobOrString) { + return notFoundNoCache(c) + } - const type = cidLookupTable[parsed.code] || 'application/octet-stream' - - return c.body(blobOrString, 200, { - 'ETag': `"${hash}"`, - 'Cache-Control': 'public,max-age=31536000,immutable', - // CSP to disable everything -- this only affects direct navigation to the - // `/file` URL. - // The CSP below prevents any sort of resource loading or script execution - // on direct navigation. The `nosniff` header instructs the browser to - // honour the provided content-type. - 'Content-Security-Policy': 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox', - 'X-Content-Type-Options': 'nosniff', - 'Content-Type': type - }) - }) + const type = cidLookupTable[parsed.code] || 'application/octet-stream' + + return c.body(blobOrString, 200, { + 'ETag': `"${hash}"`, + 'Cache-Control': 'public,max-age=31536000,immutable', + // CSP to disable everything -- this only affects direct navigation to the + // `/file` URL. + // The CSP below prevents any sort of resource loading or script execution + // on direct navigation. The `nosniff` header instructs the browser to + // honour the provided content-type. + 'Content-Security-Policy': 'default-src \'none\'; frame-ancestors \'none\'; form-action \'none\'; upgrade-insecure-requests; sandbox', + 'X-Content-Type-Options': 'nosniff', + 'Content-Type': type + }) + } + ) app.post('/deleteFile/:hash', authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), - zValidator('param', cidHashParamSchema), + zValidator('param', z.object({ hash: cidSchema }).strict()), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) const { hash } = c.req.valid('param') @@ -872,7 +858,7 @@ app.post('/name', async function (c) { app.post('/deleteContract/:hash', authMiddleware(['chel-shelter', 'chel-bearer'], 'required'), - zValidator('param', cidHashParamSchema), + zValidator('param', z.object({ hash: cidSchema }).strict()), async function (c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: 'Server in archive mode' }) const { hash } = c.req.valid('param') @@ -929,7 +915,7 @@ app.post('/name', async function (c) { }) app.post('/kv/:contractID/:key', - zValidator('param', kvParamSchema), + zValidator('param', z.object({ contractID: cidSchema, key: kvKeySchema }).strict()), authMiddleware('chel-shelter', 'required'), bodyLimit({ maxSize: 6 * MEGABYTE }), async function (c) { @@ -1013,7 +999,7 @@ app.post('/name', async function (c) { app.get('/kv/:contractID/:key', authMiddleware('chel-shelter', 'required'), - zValidator('param', kvParamSchema), + zValidator('param', z.object({ contractID: cidSchema, key: kvKeySchema }).strict()), async function (c) { const { contractID, key } = c.req.valid('param') @@ -1077,8 +1063,12 @@ app.post('/name', async function (c) { return c.redirect(staticServeConfig.redirect) }) + const zkppRegisterBodySchema = z.union([ + z.object({ b: z.string() }).strict(), + z.object({ r: z.string(), s: z.string(), sig: z.string(), Eh: z.string() }).strict() +]) app.post('/zkpp/register/:name', - zValidator('param', nameParamSchema), + zValidator('param', z.object({ name: nameSchema }).strict()), zValidatorFormOrJson(zkppRegisterBodySchema), async function (c) { const { name } = c.req.valid('param') @@ -1112,11 +1102,12 @@ app.post('/name', async function (c) { } throw new HTTPException(500, { message: 'internal error' }) - }) + } + ) app.get('/zkpp/:contractID/auth_hash', - zValidator('param', zkppContractParamSchema), - zValidator('query', zkppAuthHashQuerySchema), + zValidator('param', z.object({ contractID: cidSchema }).strict()), + zValidator('query', z.object({ b: z.string().min(1, 'b is required') })), async function (c) { const { contractID } = c.req.valid('param') const { b } = c.req.valid('query') @@ -1130,11 +1121,17 @@ app.post('/name', async function (c) { } throw new HTTPException(500, { message: 'internal error' }) - }) + } + ) app.get('/zkpp/:contractID/contract_hash', - zValidator('param', zkppContractParamSchema), - zValidator('query', zkppContractHashQuerySchema), + zValidator('param', z.object({ contractID: cidSchema }).strict()), + zValidator('query', z.object({ + r: z.string().min(1, 'r is required'), + s: z.string().min(1, 's is required'), + sig: z.string().min(1, 'sig is required'), + hc: z.string().min(1, 'hc is required') + }).strict()), async function (c) { const { contractID } = c.req.valid('param') const { r, s, sig, hc } = c.req.valid('query') @@ -1150,10 +1147,18 @@ app.post('/name', async function (c) { } throw new HTTPException(500, { message: 'internal error' }) - }) - + } + ) + + const zkppUpdatePasswordBodySchema = z.object({ + r: z.string().min(1, 'r is required'), + s: z.string().min(1, 's is required'), + sig: z.string().min(1, 'sig is required'), + hc: z.string().min(1, 'hc is required'), + Ea: z.string().min(1, 'Ea is required') + }).strict() app.post('/zkpp/:contractID/updatePasswordHash', - zValidator('param', zkppContractParamSchema), + zValidator('param', z.object({ contractID: cidSchema }).strict()), zValidatorFormOrJson(zkppUpdatePasswordBodySchema), async function (c) { const { contractID } = c.req.valid('param') @@ -1172,5 +1177,6 @@ app.post('/name', async function (c) { } throw new HTTPException(500, { message: 'internal error' }) - }) + } + ) } From fb6fa01b868ea8f93c0addf5557c98cf5c9fa544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:58:30 +0000 Subject: [PATCH 45/71] lint --- src/serve/routes.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serve/routes.ts b/src/serve/routes.ts index bf8778c..2b7baf9 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -1064,9 +1064,9 @@ app.post('/name', async function (c) { }) const zkppRegisterBodySchema = z.union([ - z.object({ b: z.string() }).strict(), - z.object({ r: z.string(), s: z.string(), sig: z.string(), Eh: z.string() }).strict() -]) + z.object({ b: z.string() }).strict(), + z.object({ r: z.string(), s: z.string(), sig: z.string(), Eh: z.string() }).strict() + ]) app.post('/zkpp/register/:name', zValidator('param', z.object({ name: nameSchema }).strict()), zValidatorFormOrJson(zkppRegisterBodySchema), From db9d982392867e0529763ffcdcb22aa182a0f0fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 19:07:38 +0000 Subject: [PATCH 46/71] Fixes --- src/serve/routes-writes.test.ts | 4 ++-- src/serve/routes.ts | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/serve/routes-writes.test.ts b/src/serve/routes-writes.test.ts index 2bc21cb..e70e20c 100644 --- a/src/serve/routes-writes.test.ts +++ b/src/serve/routes-writes.test.ts @@ -366,14 +366,14 @@ Deno.test({ if (res.status !== 400) throw new Error(`Expected 400 but got ${res.status}`) }) - await t.step('POST /event with non-JSON payload returns 500', async () => { + await t.step('POST /event with non-JSON payload returns 415', async () => { const res = await fetch(`${baseURL}/event`, { method: 'POST', headers: { 'content-type': 'text/plain' }, body: 'not-json-at-all' }) await res.body?.cancel() - if (res.status !== 500) throw new Error(`Expected 500 but got ${res.status}`) + if (res.status !== 415) throw new Error(`Expected 415 but got ${res.status}`) }) await t.step('POST /file without auth returns 401', async () => { diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 2b7baf9..71b6f32 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -344,7 +344,7 @@ export function registerRoutes (app: Hono): void { 'shelter-salt-update-token': z.string().optional(), 'shelter-salt-registration-token': z.string().optional(), 'shelter-deletion-token-digest': z.string().optional() - }).strict()), + })), bodyLimit({ maxSize: MEGABYTE }), authMiddleware('chel-shelter', 'optional'), async function (c) { @@ -356,6 +356,10 @@ export function registerRoutes (app: Hono): void { const payload = await c.req.text() if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) const validatedHeaders = c.req.valid('header') + const contentType = c.req.header('content-type') + if (contentType && !contentType.toLowerCase().startsWith('application/json')) { + throw new HTTPException(415, { message: 'Expected JSON body' }) + } const deserializedHEAD = SPMessage.deserializeHEAD(payload) try { const parsed = maybeParseCID(deserializedHEAD.head.manifest) From ac7c33d942799116788360e63334cddd6fa76969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:11:04 +0000 Subject: [PATCH 47/71] Feedback --- AGENTS.md | 1 + build/main.js | 97 ++++++++++++++++++++++++++++++++++++------- scripts/build.ts | 1 + src/serve/database.ts | 8 +++- src/serve/routes.ts | 25 ++++------- src/serve/server.ts | 4 +- 6 files changed, 102 insertions(+), 34 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e2a83e6..8d3453d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -264,6 +264,7 @@ Build process injects: - `import.meta.VERSION` - Package version from package.json - `import.meta.ownerSizeTotalWorker` - 'Owner size total' worker path - `import.meta.creditsWorker` - 'Credits' worker path +- `import.meta.initDbOnce` - Allow the DB to only be set up once ### 6. No Network After Key Loading diff --git a/build/main.js b/build/main.js index cc19b71..75109bd 100644 --- a/build/main.js +++ b/build/main.js @@ -15878,9 +15878,64 @@ function _refine(Class2, fn, _params) { }); return schema; } +function _stringbool(Classes, _params) { + const params = normalizeParams(_params); + let truthyArray = params.truthy ?? ["true", "1", "yes", "on", "y", "enabled"]; + let falsyArray = params.falsy ?? ["false", "0", "no", "off", "n", "disabled"]; + if (params.case !== "sensitive") { + truthyArray = truthyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2); + falsyArray = falsyArray.map((v2) => typeof v2 === "string" ? v2.toLowerCase() : v2); + } + const truthySet = new Set(truthyArray); + const falsySet = new Set(falsyArray); + const _Pipe = Classes.Pipe ?? $ZodPipe; + const _Boolean = Classes.Boolean ?? $ZodBoolean; + const _String = Classes.String ?? $ZodString; + const _Transform = Classes.Transform ?? $ZodTransform; + const tx = new _Transform({ + type: "transform", + transform: (input, payload) => { + let data = input; + if (params.case !== "sensitive") + data = data.toLowerCase(); + if (truthySet.has(data)) { + return true; + } else if (falsySet.has(data)) { + return false; + } else { + payload.issues.push({ + code: "invalid_value", + expected: "stringbool", + values: [...truthySet, ...falsySet], + input: payload.value, + inst: tx + }); + return {}; + } + }, + error: params.error + }); + const innerPipe = new _Pipe({ + type: "pipe", + in: new _String({ type: "string", error: params.error }), + out: tx, + error: params.error + }); + const outerPipe = new _Pipe({ + type: "pipe", + in: innerPipe, + out: new _Boolean({ + type: "boolean", + error: params.error + }), + error: params.error + }); + return outerPipe; +} var init_api = __esm({ "node_modules/.deno/zod@4.0.5/node_modules/zod/v4/core/api.js"() { init_checks(); + init_schemas(); init_util(); } }); @@ -16228,6 +16283,7 @@ var ZodCatch; var ZodPipe; var ZodReadonly; var ZodCustom; +var stringbool; var init_schemas2 = __esm({ "node_modules/.deno/zod@4.0.5/node_modules/zod/v4/classic/schemas.js"() { init_core2(); @@ -16631,6 +16687,12 @@ var init_schemas2 = __esm({ $ZodCustom.init(inst, def); ZodType.init(inst, def); }); + stringbool = (...args) => _stringbool({ + Pipe: ZodPipe, + Boolean: ZodBoolean, + String: ZodString, + Transform: ZodTransform + }, ...args); } }); var ZodFirstPartyTypeKind; @@ -68495,6 +68557,9 @@ var initDB = async ({ skipDbPreloading } = {}) => { }); } initedDB = true; + if (true) { + esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + } } if (skipDbPreloading || initedDB === "preloaded") return; await Promise.all([initVapid(), initZkpp()]); @@ -68514,7 +68579,9 @@ async function closeDB() { } currentCache?.clear(); currentCache = null; - initedDB = false; + if (true) { + initedDB = false; + } } finally { isClosing = false; } @@ -72882,14 +72949,6 @@ function authMiddleware(strategies, mode = "required") { } var MEGABYTE = 1048576; var SECOND = 1e3; -function parseBooleanParam(value) { - if (value === void 0) return false; - const normalized = value.toLowerCase(); - if (normalized === "" || normalized === "true" || normalized === "yes" || normalized === "on" || normalized === "1") { - return true; - } - return false; -} var CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/; var KV_KEY_REGEX = /^(?!_private)[^\x00]{1,256}$/; var NAME_REGEX = /^(?![_-])((?!([_-])\2)[a-z\d_-]){1,80}(? { const contentType = (c.req.header("content-type") || "").trim().toLowerCase(); @@ -72934,7 +72993,8 @@ function zValidatorFormOrJson(schema) { } else { throw new HTTPException(415, { message: "Content-Type header expected with form or JSON data" }); } - } catch { + } catch (e2) { + if (e2 instanceof HTTPException) throw e2; throw new HTTPException(400, { message: "Invalid request body" }); } const result = schema.safeParse(data); @@ -73118,7 +73178,7 @@ function registerRoutes(app2) { "shelter-salt-update-token": string2().optional(), "shelter-salt-registration-token": string2().optional(), "shelter-deletion-token-digest": string2().optional() - }).strict()), + })), bodyLimit({ maxSize: MEGABYTE }), authMiddleware("chel-shelter", "optional"), async function(c) { @@ -73128,6 +73188,10 @@ function registerRoutes(app2) { const payload = await c.req.text(); if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); const validatedHeaders = c.req.valid("header"); + const contentType = c.req.header("content-type"); + if (contentType && !contentType.toLowerCase().startsWith("application/json")) { + throw new HTTPException(415, { message: "Expected JSON body" }); + } const deserializedHEAD = SPMessage.deserializeHEAD(payload); try { const parsed = maybeParseCID(deserializedHEAD.head.manifest); @@ -73227,16 +73291,19 @@ function registerRoutes(app2) { since: nonNegativeIntegerSchema, limit: nonNegativeIntegerSchema.optional() }).strict()), + zValidator("query", object({ + keyOps: stringbool().optional() + }).strict()), async function(c) { const { contractID, since, limit } = c.req.valid("param"); - const keyOps2 = c.req.query("keyOps"); + const keyOps2 = c.req.valid("query").keyOps; const ip = getClientIP(c); try { const parsed = maybeParseCID(contractID); if (parsed?.code !== multicodes.SHELTER_CONTRACT_DATA) { throw new HTTPException(400); } - const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: parseBooleanParam(keyOps2) }); + const stream = await esm_default("backend/db/streamEntriesAfter", contractID, Number(since), limit == null ? void 0 : Number(limit), { keyOps: keyOps2 }); stream.on("error", (err) => logger_default.error("eventsAfter stream error", err)); c.req.raw.signal.addEventListener("abort", () => stream.destroy()); const streamHeaders = stream.headers || {}; @@ -74682,7 +74749,7 @@ async function startServer() { if (process9.env.NODE_ENV === "development" && !process9.env.CI) { currentApp.use("*", async (c, next) => { await next(); - const ip = c.req.header("x-real-ip") || c.req.header("x-forwarded-for")?.split(",")[0].trim() || "unknown"; + const ip = getClientIP(c) || "unknown"; console.debug(import_npm_chalk3.default`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`); }); } diff --git a/scripts/build.ts b/scripts/build.ts index 57cddba..74faad3 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -19,6 +19,7 @@ const options: esbuild.BuildOptions = { 'import.meta.VERSION': JSON.stringify(version), 'import.meta.ownerSizeTotalWorker': '"./serve/ownerSizeTotalWorker.js"', 'import.meta.creditsWorker': '"./serve/creditsWorker.js"', + 'import.meta.initDbOnce': 'true' }, format: 'esm', platform: 'node', diff --git a/src/serve/database.ts b/src/serve/database.ts index 33f0bb3..72c5cd7 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -12,6 +12,7 @@ import { initVapid } from './vapid.ts' import { initZkpp } from './zkppSalt.ts' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' +import type { ImportMeta } from '../types/build.d.ts' import type DatabaseBackend from './DatabaseBackend.ts' import { KEYOP_SEGMENT_LENGTH, appendToNamesIndex, namespaceKey } from './db-utils.ts' @@ -277,6 +278,9 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean }) } initedDB = true + if ((import.meta as ImportMeta).initDbOnce) { + sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + } } if (skipDbPreloading || initedDB === 'preloaded') return /* @@ -349,7 +353,9 @@ export async function closeDB (): Promise { } currentCache?.clear() currentCache = null - initedDB = false + if ((import.meta as ImportMeta).initDbOnce) { + initedDB = false + } } finally { isClosing = false } diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 71b6f32..734b110 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -29,17 +29,6 @@ import { authMiddleware, type AuthCredentials } from './auth.ts' const MEGABYTE = 1048576 // TODO: add settings for these const SECOND = 1000 -// Joi-compatible boolean coercion for query parameters -// Matches Joi.boolean().truthy('1', 'on', 'yes').falsy('0', 'off', 'no') -function parseBooleanParam (value: string | undefined): boolean { - if (value === undefined) return false - const normalized = value.toLowerCase() - if (normalized === '' || normalized === 'true' || normalized === 'yes' || normalized === 'on' || normalized === '1') { - return true - } - return false -} - // Regexes validated as safe with const CID_REGEX = /^z[1-9A-HJ-NP-Za-km-z]{8,72}$/ // deno-lint-ignore no-control-regex @@ -79,7 +68,7 @@ const MIME_TYPES: Record = { const cidSchema = z.string().regex(CID_REGEX, 'Invalid CID') const nameSchema = z.string().regex(NAME_REGEX, 'Invalid name') const kvKeySchema = z.string().regex(KV_KEY_REGEX, 'Invalid key') -const nonNegativeIntegerSchema = z.string().regex(NON_NEGATIVE_INTEGER_REGEX, 'Invalid positive integer') +const nonNegativeIntegerSchema = z.string().regex(NON_NEGATIVE_INTEGER_REGEX, 'Invalid non-negative integer') // Custom validator for endpoints that accept both JSON and form-urlencoded bodies function zValidatorFormOrJson ( @@ -101,7 +90,8 @@ function zValidatorFormOrJson ( } else { throw new HTTPException(415, { message: 'Content-Type header expected with form or JSON data' }) } - } catch { + } catch (e) { + if (e instanceof HTTPException) throw e throw new HTTPException(400, { message: 'Invalid request body' }) } @@ -240,7 +230,7 @@ const errorMapper = (e: Error): HTTPException => { } } -function getClientIP (c: Context): string { +export function getClientIP (c: Context): string { const headerIP = c.req.header('x-real-ip') if (headerIP) return headerIP try { @@ -474,10 +464,13 @@ export function registerRoutes (app: Hono): void { since: nonNegativeIntegerSchema, limit: nonNegativeIntegerSchema.optional() }).strict()), + zValidator('query', z.object({ + keyOps: z.stringbool().optional() + }).strict()), async function (c) { const { contractID, since, limit } = c.req.valid('param') - const keyOps = c.req.query('keyOps') + const keyOps = c.req.valid('query').keyOps const ip = getClientIP(c) try { const parsed = maybeParseCID(contractID) @@ -485,7 +478,7 @@ export function registerRoutes (app: Hono): void { throw new HTTPException(400) } - const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps: parseBooleanParam(keyOps) }) as Readable + const stream = await sbp('backend/db/streamEntriesAfter', contractID, Number(since), limit == null ? undefined : Number(limit), { keyOps }) as Readable stream.on('error', (err) => logger.error('eventsAfter stream error', err)) // "On an HTTP server, make sure to manually close your streams if a request is aborted." // From: http://knexjs.org/#Interfaces-Streams diff --git a/src/serve/server.ts b/src/serve/server.ts index 3b210f8..3fdc916 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -15,7 +15,7 @@ import type { ImportMeta } from '../types/build.d.ts' import createWorker from './createWorker.ts' import { join } from 'node:path' import process from 'node:process' -import { registerRoutes } from './routes.ts' +import { getClientIP, registerRoutes } from './routes.ts' import { CREDITS_WORKER_TASK_TIME_INTERVAL, OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL } from './constants.ts' import { KEYOP_SEGMENT_LENGTH, appendToIndexFactory, closeDB, initDB, lookupUltimateOwner, removeFromIndexFactory, updateSize } from './database.ts' import { BackendErrorBadData, BackendErrorGone, BackendErrorNotFound } from './errors.ts' @@ -428,7 +428,7 @@ export async function startServer (): Promise<{ uri: string }> { if (process.env.NODE_ENV === 'development' && !process.env.CI) { currentApp.use('*', async (c, next) => { await next() - const ip = c.req.header('x-real-ip') || c.req.header('x-forwarded-for')?.split(',')[0].trim() || 'unknown' + const ip = getClientIP(c) || 'unknown' console.debug(chalk`{grey ${ip}: ${c.req.method} ${c.req.path} --> ${c.res.status}}`) }) } From 6b203be81c0f5c6273acca80d91e71b4d9d5bef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:14:38 +0000 Subject: [PATCH 48/71] Remove proxy compat --- build/main.js | 78 ++++++++++++++++++++------------------------- src/serve/server.ts | 10 ------ 2 files changed, 35 insertions(+), 53 deletions(-) diff --git a/build/main.js b/build/main.js index 75109bd..0544b87 100644 --- a/build/main.js +++ b/build/main.js @@ -70918,14 +70918,14 @@ var Hono = class _Hono { * app.route("/api", app2) // GET /api/user * ``` */ - route(path8, app2) { + route(path8, app) { const subApp = this.basePath(path8); - app2.routes.map((r) => { + app.routes.map((r) => { let handler; - if (app2.errorHandler === errorHandler) { + if (app.errorHandler === errorHandler) { handler = r.handler; } else { - handler = async (c, next) => (await compose([], app2.errorHandler)(c, () => r.handler(c, next))).res; + handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res; handler[COMPOSED_HANDLER] = r.handler; } subApp.#addRoute(r.method, r.path, handler); @@ -73135,7 +73135,7 @@ function serveAsset(c, subpath, assetsDir) { return c.body(file, 200, headers); }).catch(() => notFoundNoCache(c)); } -function registerRoutes(app2) { +function registerRoutes(app) { for (const limiter of currentLimiters) { limiter.disconnect(); clearInterval(limiter.interval); @@ -73171,7 +73171,7 @@ function registerRoutes(app2) { installRateLimiterSelectorsOnce(); const isCheloniaDashboard = process7.env.IS_CHELONIA_DASHBOARD_DEV; const staticServeConfig = getStaticServeConfig(); - app2.post( + app.post( "/event", zValidator("header", object({ "shelter-namespace-registration": nameSchema.optional(), @@ -73284,7 +73284,7 @@ function registerRoutes(app2) { } } ); - app2.get( + app.get( "/eventsAfter/:contractID/:since/:limit?", zValidator("param", object({ contractID: cidSchema, @@ -73319,7 +73319,7 @@ function registerRoutes(app2) { } } ); - app2.get( + app.get( "/ownResources", authMiddleware("chel-shelter", "required"), async function(c) { @@ -73336,7 +73336,7 @@ function registerRoutes(app2) { info: import_npm_chalk.default.green, debug: import_npm_chalk.default.blue }; - app2.post("/log", async function(c) { + app.post("/log", async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const body = await c.req.json(); if (!body.level || !body.value) throw new HTTPException(400, { message: "level and value are required" }); @@ -73346,7 +73346,7 @@ function registerRoutes(app2) { return c.body(null, 200); }); } - app2.get( + app.get( "/name/:name", zValidator("param", object({ name: nameSchema }).strict()), async function(c) { @@ -73360,7 +73360,7 @@ function registerRoutes(app2) { } } ); - app2.get( + app.get( "/latestHEADinfo/:contractID", zValidator("param", object({ contractID: cidSchema }).strict()), async function(c) { @@ -73384,12 +73384,12 @@ function registerRoutes(app2) { } } ); - app2.get("/time", function(c) { + app.get("/time", function(c) { return c.text((/* @__PURE__ */ new Date()).toISOString(), 200, { "Cache-Control": "no-store" }); }); - app2.post("/streams-test", async function(c) { + app.post("/streams-test", async function(c) { const raw2 = await c.req.arrayBuffer(); const buf2 = Buffer14.from(raw2); if (buf2.byteLength === 2 && buf2.toString() === "ok") { @@ -73399,7 +73399,7 @@ function registerRoutes(app2) { } }); if (process7.env.NODE_ENV === "development") { - app2.post("/dev-file", bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { + app.post("/dev-file", bodyLimit({ maxSize: 6 * MEGABYTE }), async function(c) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); try { console.log("FILE UPLOAD!"); @@ -73424,7 +73424,7 @@ function registerRoutes(app2) { } }); } - app2.post( + app.post( "/file", authMiddleware("chel-shelter", "required"), bodyLimit({ maxSize: FILE_UPLOAD_MAX_BYTES }), @@ -73510,7 +73510,7 @@ function registerRoutes(app2) { } } ); - app2.get( + app.get( "/file/:hash", zValidator("param", object({ hash: cidSchema }).strict()), async function(c) { @@ -73540,7 +73540,7 @@ function registerRoutes(app2) { }); } ); - app2.post( + app.post( "/deleteFile/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), zValidator("param", object({ hash: cidSchema }).strict()), @@ -73587,7 +73587,7 @@ function registerRoutes(app2) { } } ); - app2.post( + app.post( "/deleteContract/:hash", authMiddleware(["chel-shelter", "chel-bearer"], "required"), zValidator("param", object({ hash: cidSchema }).strict()), @@ -73635,7 +73635,7 @@ function registerRoutes(app2) { } } ); - app2.post( + app.post( "/kv/:contractID/:key", zValidator("param", object({ contractID: cidSchema, key: kvKeySchema }).strict()), authMiddleware("chel-shelter", "required"), @@ -73701,7 +73701,7 @@ function registerRoutes(app2) { }); } ); - app2.get( + app.get( "/kv/:contractID/:key", authMiddleware("chel-shelter", "required"), zValidator("param", object({ contractID: cidSchema, key: kvKeySchema }).strict()), @@ -73729,22 +73729,22 @@ function registerRoutes(app2) { }); } ); - app2.get("/serverMessages", function(c) { + app.get("/serverMessages", function(c) { const messages = import_npm_nconf4.default.get("server:messages"); if (!messages) return c.json([]); return c.json(messages, 200, { "Cache-Control": "no-store" }); }); - app2.get("/assets/:subpath{.+}", function(c) { + app.get("/assets/:subpath{.+}", function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); if (isCheloniaDashboard) { - app2.get("/dashboard/assets/:subpath{.+}", function(c) { + app.get("/dashboard/assets/:subpath{.+}", function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); } - app2.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { + app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { try { const file = await Deno.readFile(staticServeConfig.distIndexHtml); return c.body(file, 200, { "Content-Type": "text/html" }); @@ -73752,14 +73752,14 @@ function registerRoutes(app2) { return notFoundNoCache(c); } }); - app2.get("/", function(c) { + app.get("/", function(c) { return c.redirect(staticServeConfig.redirect); }); const zkppRegisterBodySchema = union([ object({ b: string2() }).strict(), object({ r: string2(), s: string2(), sig: string2(), Eh: string2() }).strict() ]); - app2.post( + app.post( "/zkpp/register/:name", zValidator("param", object({ name: nameSchema }).strict()), zValidatorFormOrJson(zkppRegisterBodySchema), @@ -73791,7 +73791,7 @@ function registerRoutes(app2) { throw new HTTPException(500, { message: "internal error" }); } ); - app2.get( + app.get( "/zkpp/:contractID/auth_hash", zValidator("param", object({ contractID: cidSchema }).strict()), zValidator("query", object({ b: string2().min(1, "b is required") })), @@ -73809,7 +73809,7 @@ function registerRoutes(app2) { throw new HTTPException(500, { message: "internal error" }); } ); - app2.get( + app.get( "/zkpp/:contractID/contract_hash", zValidator("param", object({ contractID: cidSchema }).strict()), zValidator("query", object({ @@ -73841,7 +73841,7 @@ function registerRoutes(app2) { hc: string2().min(1, "hc is required"), Ea: string2().min(1, "Ea is required") }).strict(); - app2.post( + app.post( "/zkpp/:contractID/updatePasswordHash", zValidator("param", object({ contractID: cidSchema }).strict()), zValidatorFormOrJson(zkppUpdatePasswordBodySchema), @@ -74957,14 +74957,6 @@ async function stopServer() { isStopping = false; } } -var app = new Proxy({}, { - get(_target, prop) { - if (currentApp) { - return Reflect.get(currentApp, prop); - } - return void 0; - } -}); console.info("NODE_ENV =", process10.env.NODE_ENV); var dontLog = { "backend/server/broadcastEntry": true, @@ -75341,13 +75333,13 @@ async function startDashboard() { const port = import_npm_nconf6.default.get("server:dashboardPort"); const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; const dashboardRoot = getDashboardPath(); - const app2 = new Hono2(); + const app = new Hono2(); const staticMiddleware = serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p }); const indexMiddleware = serveStatic2({ path: path6.join(dashboardRoot, "index.html") }); - app2.get("/assets/*", staticMiddleware); - app2.get("/dashboard", indexMiddleware); - app2.get("/dashboard/", indexMiddleware); - app2.get("/*", async (c) => { + app.get("/assets/*", staticMiddleware); + app.get("/dashboard", indexMiddleware); + app.get("/dashboard/", indexMiddleware); + app.get("/*", async (c) => { const staticResponse = await staticMiddleware(c, async () => { }); if (staticResponse) { @@ -75358,7 +75350,7 @@ async function startDashboard() { return indexResponse || c.text("Not Found", 404); }); await new Promise((resolve82) => { - Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app2.fetch); + Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app.fetch); }); } async function watch(args) { diff --git a/src/serve/server.ts b/src/serve/server.ts index 3fdc916..45d8db9 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -696,13 +696,3 @@ export async function stopServer (): Promise { isStopping = false } } - -// Legacy: export the Hono app for backwards compatibility (deprecated) -export const app = new Proxy({} as Hono, { - get (_target, prop) { - if (currentApp) { - return Reflect.get(currentApp, prop) - } - return undefined - } -}) From 33514a589fb039640edd7dfc2b4dce9030cc6d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:25:57 +0000 Subject: [PATCH 49/71] Fixes --- build/main.js | 14 +++++++------- src/serve/database.ts | 2 +- src/serve/index.ts | 1 - src/serve/routes-writes.test.ts | 2 +- src/serve/routes.ts | 10 +++++----- src/serve/server.ts | 3 +++ 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/build/main.js b/build/main.js index 0544b87..c00c5ed 100644 --- a/build/main.js +++ b/build/main.js @@ -68579,7 +68579,7 @@ async function closeDB() { } currentCache?.clear(); currentCache = null; - if (true) { + if (false) { initedDB = false; } } finally { @@ -73185,13 +73185,13 @@ function registerRoutes(app) { if (ARCHIVE_MODE) throw new HTTPException(501, { message: "Server in archive mode" }); const ip = getClientIP(c); try { - const payload = await c.req.text(); - if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); - const validatedHeaders = c.req.valid("header"); const contentType = c.req.header("content-type"); if (contentType && !contentType.toLowerCase().startsWith("application/json")) { throw new HTTPException(415, { message: "Expected JSON body" }); } + const payload = await c.req.text(); + const validatedHeaders = c.req.valid("header"); + if (!payload) throw new HTTPException(400, { message: "Invalid request payload input" }); const deserializedHEAD = SPMessage.deserializeHEAD(payload); try { const parsed = maybeParseCID(deserializedHEAD.head.manifest); @@ -73309,7 +73309,7 @@ function registerRoutes(app) { const streamHeaders = stream.headers || {}; const webStream = Readable3.toWeb(stream); return new Response(webStream, { - headers: { "content-type": "application/octet-stream", ...streamHeaders } + headers: { "content-type": "application/json", ...streamHeaders } }); } catch (err) { if (err instanceof HTTPException) throw err; @@ -73452,7 +73452,7 @@ function registerRoutes(app) { throw new HTTPException(422, { message: "Error parsing manifest" }); } })(); - if (typeof manifest2 !== "object") throw new HTTPException(422, { message: "manifest format is invalid" }); + if (!manifest2 || typeof manifest2 !== "object") throw new HTTPException(422, { message: "manifest format is invalid" }); if (manifest2.version !== "1.0.0") throw new HTTPException(422, { message: "unsupported manifest version" }); if (manifest2.cipher !== "aes256gcm") throw new HTTPException(422, { message: "unsupported cipher" }); if (!Array.isArray(manifest2.chunks) || !manifest2.chunks.length) throw new HTTPException(422, { message: "missing chunks" }); @@ -74950,6 +74950,7 @@ async function stopServer() { ]); currentOwnerSizeTotalWorker = void 0; currentCreditsWorker = void 0; + await esm_default("chelonia.persistentActions/unload"); await closeDB(); currentApp = null; currentManifest = void 0; @@ -75035,7 +75036,6 @@ async function startServer2(options2 = {}) { esm_default("okTurtles.events/once", SERVER_EXITING, async () => { try { removeSignalHandlers(); - await esm_default("chelonia.persistentActions/unload"); await stopServer2(); console.info("Server down"); } catch (err) { diff --git a/src/serve/database.ts b/src/serve/database.ts index 72c5cd7..c8a23c5 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -353,7 +353,7 @@ export async function closeDB (): Promise { } currentCache?.clear() currentCache = null - if ((import.meta as ImportMeta).initDbOnce) { + if (!(import.meta as ImportMeta).initDbOnce) { initedDB = false } } finally { diff --git a/src/serve/index.ts b/src/serve/index.ts index e97ad36..0bdfe3b 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -123,7 +123,6 @@ export async function startServer (options: StartServerOptions = {}): Promise<{ sbp('okTurtles.events/once', SERVER_EXITING, async () => { try { removeSignalHandlers() - await sbp('chelonia.persistentActions/unload') await stopServer() console.info('Server down') } catch (err) { diff --git a/src/serve/routes-writes.test.ts b/src/serve/routes-writes.test.ts index e70e20c..4cf81ff 100644 --- a/src/serve/routes-writes.test.ts +++ b/src/serve/routes-writes.test.ts @@ -359,7 +359,7 @@ Deno.test({ await t.step('POST /event with invalid payload returns 400', async () => { const res = await fetch(`${baseURL}/event`, { method: 'POST', - headers: { 'content-type': 'text/plain' }, + headers: { 'content-type': 'application/json' }, body: '' }) await res.body?.cancel() diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 734b110..bb6def7 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -343,13 +343,13 @@ export function registerRoutes (app: Hono): void { // X-Real-IP HEADER! OTHERWISE THIS IS EASILY SPOOFED! const ip = getClientIP(c) try { - const payload = await c.req.text() - if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) - const validatedHeaders = c.req.valid('header') const contentType = c.req.header('content-type') if (contentType && !contentType.toLowerCase().startsWith('application/json')) { throw new HTTPException(415, { message: 'Expected JSON body' }) } + const payload = await c.req.text() + const validatedHeaders = c.req.valid('header') + if (!payload) throw new HTTPException(400, { message: 'Invalid request payload input' }) const deserializedHEAD = SPMessage.deserializeHEAD(payload) try { const parsed = maybeParseCID(deserializedHEAD.head.manifest) @@ -489,7 +489,7 @@ export function registerRoutes (app: Hono): void { const streamHeaders = (stream as { headers?: Record }).headers || {} const webStream = Readable.toWeb(stream) as ReadableStream return new Response(webStream, { - headers: { 'content-type': 'application/octet-stream', ...streamHeaders } + headers: { 'content-type': 'application/json', ...streamHeaders } }) } catch (err) { if (err instanceof HTTPException) throw err @@ -676,7 +676,7 @@ app.post('/name', async function (c) { throw new HTTPException(422, { message: 'Error parsing manifest' }) } })() - if (typeof manifest !== 'object') throw new HTTPException(422, { message: 'manifest format is invalid' }) + if (!manifest || typeof manifest !== 'object') throw new HTTPException(422, { message: 'manifest format is invalid' }) if (manifest.version !== '1.0.0') throw new HTTPException(422, { message: 'unsupported manifest version' }) if (manifest.cipher !== 'aes256gcm') throw new HTTPException(422, { message: 'unsupported cipher' }) if (!Array.isArray(manifest.chunks) || !manifest.chunks.length) throw new HTTPException(422, { message: 'missing chunks' }) diff --git a/src/serve/server.ts b/src/serve/server.ts index 45d8db9..b5bf6bf 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -686,6 +686,9 @@ export async function stopServer (): Promise { currentOwnerSizeTotalWorker = undefined currentCreditsWorker = undefined + // Unload persistent actions + await sbp('chelonia.persistentActions/unload') + // Close database await closeDB() From b2445278233cf341ef6416289deb0c9cd8401489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 20 Apr 2026 20:31:26 +0000 Subject: [PATCH 50/71] Remove new `.parse()` --- build/main.js | 1 - src/parseArgs.ts | 3 --- 2 files changed, 4 deletions(-) diff --git a/build/main.js b/build/main.js index c00c5ed..64fb1b0 100644 --- a/build/main.js +++ b/build/main.js @@ -79723,7 +79723,6 @@ var parseArgs = () => { (c) => handlerWrapper(c) ); const yargsInstance = yargs_default(hideBin(process13.argv)).version("3.2.1").strict().command(commandModules).demandCommand().help(); - yargsInstance.parse(); return yargsInstance; }; var parseArgs_default = parseArgs; diff --git a/src/parseArgs.ts b/src/parseArgs.ts index 8e292cf..81d1a70 100644 --- a/src/parseArgs.ts +++ b/src/parseArgs.ts @@ -35,9 +35,6 @@ const parseArgs = () => { .demandCommand() .help() - // Explicitly parse to trigger command handlers - yargsInstance.parse() - return yargsInstance } From 4835d49a8a463e0ab36953ff682f5ea36dda994d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 00:11:53 +0000 Subject: [PATCH 51/71] Review --- build/main.js | 1130 ++++++++++++++++++++++++++++++++----------- deno.json | 2 +- deno.lock | 16 +- scripts/build.ts | 1 + src/main.ts | 5 +- src/serve/routes.ts | 15 +- 6 files changed, 861 insertions(+), 308 deletions(-) diff --git a/build/main.js b/build/main.js index 64fb1b0..ec9f0de 100644 --- a/build/main.js +++ b/build/main.js @@ -18989,7 +18989,7 @@ var strToBuf; var strToB64; var getSubscriptionId; var init_functions = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/functions.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/functions.mjs"() { init_base58(); init_blake2b(); init_blake2bstream(); @@ -19310,15 +19310,6 @@ var init_esm3 = __esm({ }); } }); -function pick2(o2, props) { - const x3 = /* @__PURE__ */ Object.create(null); - for (const k of props) { - if (has(o2, k)) { - x3[k] = o2[k]; - } - } - return x3; -} function omit2(o2, props) { const x3 = /* @__PURE__ */ Object.create(null); for (const k in o2) { @@ -19370,6 +19361,9 @@ function randomIntFromRange(min, max) { function uniq(array2) { return Array.from(new Set(array2)); } +function union2(...arrays) { + return uniq(Array.prototype.concat.apply([], arrays)); +} function intersection2(a1, ...arrays) { return uniq(a1).filter((v1) => arrays.every((v2) => v2.indexOf(v1) >= 0)); } @@ -22544,7 +22538,7 @@ var ChelErrorFetchServerTimeFailed; var ChelErrorUnexpectedHttpResponseCode; var ChelErrorResourceGone; var init_errors3 = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/errors.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/errors.mjs"() { ChelErrorGenerator = (name, base2 = Error) => class extends base2 { constructor(...params) { super(...params); @@ -22583,11 +22577,12 @@ var serdesTagSymbol; var serdesSerializeSymbol; var serdesDeserializeSymbol; var rawResult; +var portDestructor; var serializer; var deserializerTable; var deserializer; var init_esm7 = __esm({ - "node_modules/.deno/@chelonia+serdes@1.0.0/node_modules/@chelonia/serdes/dist/esm/index.js"() { + "node_modules/.deno/@chelonia+serdes@1.0.1/node_modules/@chelonia/serdes/dist/esm/index.js"() { serdesTagSymbol = Symbol("tag"); serdesSerializeSymbol = Symbol("serialize"); serdesDeserializeSymbol = Symbol("deserialize"); @@ -22595,87 +22590,138 @@ var init_esm7 = __esm({ rawResultSet.add(obj); return obj; }; - serializer = (data) => { + portDestructor = (() => { + if (typeof FinalizationRegistry !== "function") { + return () => { + }; + } + const registry2 = new FinalizationRegistry((heldValue) => { + heldValue.close(); + }); + return (fn, port) => { + registry2.register(fn, port); + }; + })(); + serializer = (data, noFn) => { const rawResultSet = /* @__PURE__ */ new WeakSet(); const verbatim = []; const transferables = /* @__PURE__ */ new Set(); const revokables = /* @__PURE__ */ new Set(); - const result = JSON.parse(JSON.stringify(data, (_key, value) => { - if (value && typeof value === "object" && rawResultSet.has(value)) - return value; - if (value === void 0) - return rawResult(rawResultSet, ["_", "_"]); - if (!value) - return value; - if (Array.isArray(value) && value[0] === "_") - return rawResult(rawResultSet, ["_", "_", ...value]); - if (value instanceof Map) { - return rawResult(rawResultSet, ["_", "Map", Array.from(value.entries())]); - } - if (value instanceof Set) { - return rawResult(rawResultSet, ["_", "Set", Array.from(value.values())]); - } - if (value instanceof Blob || value instanceof File) { - const pos = verbatim.length; - verbatim[verbatim.length] = value; - return rawResult(rawResultSet, ["_", "_ref", pos]); - } - if (value instanceof Error) { - const pos = verbatim.length; - verbatim[verbatim.length] = value; - if (value.cause) { - value.cause = serializer(value.cause).data; + try { + const result = JSON.parse(JSON.stringify(data, (_key, value) => { + if (value && typeof value === "object" && rawResultSet.has(value)) + return value; + if (value === void 0) + return rawResult(rawResultSet, ["_", "_"]); + if (!value) + return value; + if (Array.isArray(value) && value[0] === "_") + return rawResult(rawResultSet, ["_", "_", ...value]); + if (value instanceof Map) { + return rawResult(rawResultSet, ["_", "Map", Array.from(value.entries())]); + } + if (value instanceof Set) { + return rawResult(rawResultSet, ["_", "Set", Array.from(value.values())]); + } + if (value instanceof Blob || value instanceof File) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + return rawResult(rawResultSet, ["_", "_ref", pos]); + } + if (value instanceof Error) { + const obj = (() => { + if (value.cause) { + const causeCopy = value.cause; + let serialized; + try { + serialized = serializer(value.cause, true); + value.cause = serialized.data; + const copy2 = structuredClone(value); + serialized.transferables.forEach((t) => transferables.add(t)); + serialized.revokables.forEach((r) => revokables.add(r)); + return copy2; + } catch (e2) { + console.error("Error serializing error cause", e2); + serialized?.revokables.forEach((r) => r.close()); + const fallback = new Error(value.message); + return fallback; + } finally { + value.cause = causeCopy; + } + } else { + return value; + } + })(); + const pos = verbatim.length; + verbatim[verbatim.length] = obj; + return rawResult(rawResultSet, ["_", "_err", rawResult(rawResultSet, ["_", "_ref", pos]), value.name]); + } + if (value instanceof MessagePort || value instanceof ReadableStream || value instanceof WritableStream || value instanceof ArrayBuffer) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + transferables.add(value); + return rawResult(rawResultSet, ["_", "_ref", pos]); + } + if (ArrayBuffer.isView(value)) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + if (!(typeof SharedArrayBuffer === "function" && value.buffer instanceof SharedArrayBuffer)) { + transferables.add(value.buffer); + } + return rawResult(rawResultSet, ["_", "_ref", pos]); } - return rawResult(rawResultSet, ["_", "_err", rawResult(rawResultSet, ["_", "_ref", pos]), value.name]); - } - if (value instanceof MessagePort || value instanceof ReadableStream || value instanceof WritableStream || value instanceof ArrayBuffer) { - const pos = verbatim.length; - verbatim[verbatim.length] = value; - transferables.add(value); - return rawResult(rawResultSet, ["_", "_ref", pos]); - } - if (ArrayBuffer.isView(value)) { - const pos = verbatim.length; - verbatim[verbatim.length] = value; - transferables.add(value.buffer); - return rawResult(rawResultSet, ["_", "_ref", pos]); - } - if (typeof value === "function") { - const mc = new MessageChannel(); - mc.port1.onmessage = async (ev) => { - try { + if (typeof value === "function" && !noFn) { + const mc = new MessageChannel(); + mc.port1.onmessage = async (ev) => { try { - const result2 = await value(...deserializer(ev.data[1])); - const { data: data2, transferables: transferables2 } = serializer(result2); - ev.data[0].postMessage([true, data2], transferables2); + try { + const result2 = await value(...deserializer(ev.data[1])); + const { data: data2, transferables: transferables2, revokables: revokables2 } = serializer(result2); + try { + ev.data[0].postMessage([true, data2], transferables2); + } catch (e2) { + revokables2.forEach((port) => port.close()); + throw e2; + } + } catch (e2) { + try { + const { data: data2, transferables: transferables2 } = serializer(e2, true); + ev.data[0].postMessage([false, data2], transferables2); + } catch (e3) { + console.error("Error on onmessage handler trying to transmit error", e3); + ev.data[0].postMessage([false]); + } + } } catch (e2) { - const { data: data2, transferables: transferables2 } = serializer(e2); - ev.data[0].postMessage([false, data2], transferables2); + console.error("Async error on onmessage handler", e2); + } finally { + ev.data[0].close(); } - } catch (e2) { - console.error("Async error on onmessage handler", e2); - } - }; - transferables.add(mc.port2); - revokables.add(mc.port1); - return rawResult(rawResultSet, ["_", "_fn", mc.port2]); - } - const proto3 = Object.getPrototypeOf(value); - if (proto3?.constructor?.[serdesTagSymbol] && proto3.constructor[serdesSerializeSymbol]) { - return rawResult(rawResultSet, ["_", "_custom", proto3.constructor[serdesTagSymbol], proto3.constructor[serdesSerializeSymbol](value)]); - } - return value; - }), (_key, value) => { - if (Array.isArray(value) && value[0] === "_" && value[1] === "_ref") { - return verbatim[value[2]]; - } - return value; - }); - return { - data: result, - transferables: Array.from(transferables), - revokables: Array.from(revokables) - }; + }; + transferables.add(mc.port2); + revokables.add(mc.port1); + return rawResult(rawResultSet, ["_", "_fn", mc.port2]); + } + const proto3 = Object.getPrototypeOf(value); + if (proto3?.constructor?.[serdesTagSymbol] && proto3.constructor[serdesSerializeSymbol]) { + return rawResult(rawResultSet, ["_", "_custom", proto3.constructor[serdesTagSymbol], proto3.constructor[serdesSerializeSymbol](value)]); + } + return value; + }), (_key, value) => { + if (Array.isArray(value) && value[0] === "_" && value[1] === "_ref") { + return verbatim[value[2]]; + } + return value; + }); + return { + data: result, + transferables: Array.from(transferables), + revokables: Array.from(revokables) + }; + } catch (e2) { + revokables.forEach((port) => port.close()); + throw e2; + } }; deserializerTable = /* @__PURE__ */ Object.create(null); deserializer = (data) => { @@ -22726,20 +22772,45 @@ var init_esm7 = __esm({ // end back into functions using that port. case "_fn": { const mp = value[2]; - return (...args) => { + const fn = (...args) => { return new Promise((resolve82, reject) => { const mc = new MessageChannel(); - const { data: data2, transferables } = serializer(args); - mc.port1.onmessage = (ev) => { - if (ev.data[0]) { - resolve82(deserializer(ev.data[1])); - } else { - reject(deserializer(ev.data[1])); + const { data: data2, transferables, revokables } = serializer(args); + const rcvPort = mc.port1; + const sendingPort = mc.port2; + rcvPort.onmessage = (ev) => { + try { + if (ev.data[0]) { + resolve82(deserializer(ev.data[1])); + } else { + reject(ev.data.length > 1 ? deserializer(ev.data[1]) : new Error("Message error")); + } + } catch (e2) { + reject(e2); + } finally { + rcvPort.close(); + revokables.forEach((port) => port.close()); } }; - mp.postMessage([mc.port2, data2], [mc.port2, ...transferables]); + rcvPort.onmessageerror = () => { + try { + reject(new Error("Message error")); + } finally { + rcvPort.close(); + revokables.forEach((port) => port.close()); + } + }; + try { + mp.postMessage([sendingPort, data2], [sendingPort, ...transferables]); + } catch (e2) { + rcvPort.close(); + revokables.forEach((port) => port.close()); + reject(e2); + } }); }; + portDestructor(fn, mp); + return fn; } } } @@ -22766,7 +22837,7 @@ var signedDataKeyId; var isRawSignedData; var rawSignedIncomingData; var init_signedData = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/signedData.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/signedData.mjs"() { init_esm6(); init_esm(); init_esm4(); @@ -23039,7 +23110,7 @@ var isRawEncryptedData; var unwrapMaybeEncryptedData; var maybeEncryptedIncomingData; var init_encryptedData = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/encryptedData.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/encryptedData.mjs"() { init_esm6(); init_esm(); init_esm4(); @@ -23304,7 +23375,7 @@ var decryptedAndVerifiedDeserializedMessage; var SPMessage; var keyOps; var init_SPMessage = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/SPMessage.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/SPMessage.mjs"() { init_esm6(); init_esm7(); init_esm4(); @@ -23376,8 +23447,14 @@ var init_SPMessage = __esm({ }); } if (op === SPMessage.OP_KEY_REQUEST) { - return maybeEncryptedIncomingData(contractID, state, message, height, additionalKeys, headJSON, (msg) => { - msg.replyWith = signedIncomingData(msg.contractID, void 0, msg.replyWith, msg.height, headJSON); + return maybeEncryptedIncomingData(contractID, state, message, height, additionalKeys, headJSON, (msg, id) => { + if (!id && has(msg, "innerData")) { + msg.innerData = maybeEncryptedIncomingData(contractID, state, msg.innerData, height, additionalKeys, headJSON, (innerMsg) => { + innerMsg.replyWith = signedIncomingData(innerMsg.contractID, void 0, innerMsg.replyWith, innerMsg.height, headJSON); + }); + } else { + msg.replyWith = signedIncomingData(msg.contractID, void 0, msg.replyWith, msg.height, headJSON); + } }); } if (op === SPMessage.OP_ACTION_UNENCRYPTED && isRawSignedData(message)) { @@ -23392,7 +23469,14 @@ var init_SPMessage = __esm({ }); } if (op === SPMessage.OP_KEY_REQUEST_SEEN) { - return maybeEncryptedIncomingData(contractID, state, parsedMessage, height, additionalKeys, headJSON, void 0); + return maybeEncryptedIncomingData(contractID, state, parsedMessage, height, additionalKeys, headJSON, (data, id) => { + if (!id && has(data, "innerData")) { + const dataV2 = data; + if (dataV2.innerData) { + dataV2.innerData = maybeEncryptedIncomingData(contractID, state, dataV2.innerData, height, additionalKeys, headJSON); + } + } + }); } if (op === SPMessage.OP_ATOMIC) { return message.map(([opT, opV]) => [ @@ -23709,7 +23793,7 @@ var prefixHandlers; var dbPrimitiveSelectors; var db_default; var init_db = __esm({ - "node_modules/.deno/@chelonia+lib@1.2.9/node_modules/@chelonia/lib/dist/esm/db.mjs"() { + "node_modules/.deno/@chelonia+lib@1.4.3/node_modules/@chelonia/lib/dist/esm/db.mjs"() { init_esm3(); init_esm2(); init_esm(); @@ -23813,7 +23897,9 @@ var init_db = __esm({ return; return JSON.parse(entryMetaJson); }, - "chelonia/db/setEntryMeta": async (contractID, height, entryMeta) => { + async "chelonia/db/setEntryMeta"(contractID, height, entryMeta) { + if (!this.config.saveMessageMetadata) + return; const entryMetaJson = JSON.stringify(entryMeta); await esm_default("chelonia.db/set", `_private_hidx=${contractID}#${height}`, entryMetaJson); }, @@ -63867,9 +63953,9 @@ function eventsAfter(contractID, { sinceHeight, limit, sinceHash, stream = true const height = SPMessage.deserializeHEAD(currentEvent).head.height; if (height !== sinceHeight || sinceHash && sinceHash !== hash3) { if (height === sinceHeight && sinceHash && sinceHash !== hash3) { - throw new ChelErrorForkedChain(`Forked chain: hash(${hash3}) !== since(${sinceHash})`); + throw new ChelErrorForkedChain(`Forked chain ${contractID}: hash(${hash3}) !== since(${sinceHash})`); } else { - throw new Error(`Unexpected data: hash(${hash3}) !== since(${sinceHash || ""}) or height(${height}) !== since(${sinceHeight})`); + throw new Error(`Unexpected data in ${contractID}: hash(${hash3}) !== since(${sinceHash || ""}) or height(${height}) !== since(${sinceHeight})`); } } } @@ -64000,10 +64086,11 @@ var collectEventStream = async (s) => { return r; }; var logEvtError = (msg, ...args) => { + const extra = `(contractID ${msg.contractID()}, hash ${msg.hash()})`; if (msg._direction === "outgoing") { - console.warn(...args); + console.warn(...args, extra); } else { - console.error(...args); + console.error(...args, extra); } }; var handleFetchResult = (type) => { @@ -64018,6 +64105,49 @@ var handleFetchResult = (type) => { return r[type](); }; }; +var deleteKeyHelper = (state, height, keyIds) => { + const namesToCheck = new Set(keyIds.map((id) => state._vm.authorizedKeys[id]?.name).filter((name) => name != null)); + const allIdsForNames = Object.values(state._vm.authorizedKeys).filter(({ name }) => namesToCheck.has(name)).reduce((acc, { id, name }) => { + if (!acc[name]) { + acc[name] = [id]; + } else { + acc[name].push(id); + } + return acc; + }, /* @__PURE__ */ Object.create(null)); + for (const keyId2 of keyIds) { + const key = state._vm.authorizedKeys[keyId2]; + if (!key) { + console.error("[deleteKeyHelper] Key not found in authorizedKeys:", keyId2); + continue; + } + const name = key.name; + for (const id of allIdsForNames[name]) { + if (has(state._volatile.pendingKeyRevocations, id)) { + delete state._volatile.pendingKeyRevocations[id]; + } + } + state._vm.authorizedKeys[keyId2]._notAfterHeight = height; + } +}; +var extendKeyField = (a, b) => { + if (a === "*" || b === "*") + return "*"; + return union2(a || [], b); +}; +var updateKey = (key, updatedKey) => { + return { + ...key, + ...updatedKey.purpose ? { purpose: union2(key.purpose, updatedKey.purpose) } : {}, + ...updatedKey.permissions ? { + permissions: extendKeyField(key.permissions, updatedKey.permissions) + } : {}, + ...updatedKey.allowedActions ? { + allowedActions: extendKeyField(key.allowedActions, updatedKey.allowedActions) + } : {}, + ...updatedKey.meta ? { meta: updatedKey.meta } : {} + }; +}; var supportsRequestStreams = typeof window !== "object" || (() => { let duplexAccessed = false; const hasContentType = new Request("", { @@ -64350,14 +64480,14 @@ var files_default = esm_default("sbp/selectors/register", { })); } }); +init_esm6(); init_esm(); -init_functions(); init_esm4(); init_SPMessage(); -init_esm6(); init_db(); init_encryptedData(); init_errors3(); +init_functions(); init_signedData(); var missingDecryptionKeyIdsMap = /* @__PURE__ */ new WeakMap(); var getMsgMeta = function(message, contractID, state, index) { @@ -64678,7 +64808,8 @@ var internals_default = esm_default("sbp/selectors/register", { this.manifestToContract[manifestHash] = { slim: contractInfo === body.contractSlim, info: contractInfo, - contract: this.defContract + contract: this.defContract, + name: contractName }; }, // Warning: avoid using this unless you know what you're doing. Prefer using /remove. @@ -64801,7 +64932,7 @@ var internals_default = esm_default("sbp/selectors/register", { ...billableContractID && { Authorization: buildShelterAuthorizationHeader.call(this, billableContractID) }, - "Content-Type": "text/plain" + "Content-Type": "application/json" }, signal: this.abortController.signal }); @@ -64880,6 +65011,34 @@ var internals_default = esm_default("sbp/selectors/register", { return; this.config.reactiveSet(targetState._volatile, "pendingKeyRequests", targetState._volatile.pendingKeyRequests.filter((pkr) => pkr?.name !== signingKey.name)); }, + "chelonia/private/operationHook": function(contractID, message, state) { + if (this.config.skipActionProcessing) + return; + const manifestHash = message.manifest(); + const contractName = this.manifestToContract[manifestHash]?.name; + if (!contractName) + return; + const callHook = (op, atomic) => { + const hook = `${manifestHash}/${contractName}/_postOpHook/${op}`; + if (esm_default("sbp/selectors/fn", hook)) { + try { + esm_default(hook, { contractID, message, state, atomic }); + } catch (e2) { + console.error(`[${hook}] hook error for message ${message.hash()} on contract ${contractID}:`, e2); + } + } + }; + if (message.opType() === SPMessage.OP_ATOMIC) { + const opsSet = /* @__PURE__ */ new Set(); + for (const [op] of message.opValue()) { + if (opsSet.has(op)) + continue; + opsSet.add(op); + callHook(op, true); + } + } + callHook(message.opType()); + }, "chelonia/private/in/processMessage": async function(message, state, internalSideEffectStack, contractName) { const [opT, opV] = message.op(); const hash3 = message.hash(); @@ -65012,14 +65171,29 @@ var internals_default = esm_default("sbp/selectors/register", { if (key.id && key.meta?.private?.content) { if (!has(state._vm, "sharedKeyIds")) state._vm.sharedKeyIds = []; - if (!state._vm.sharedKeyIds.some((sK) => sK.id === key.id)) { + const sharedKeyId = state._vm.sharedKeyIds.find((sK) => sK.id === key.id); + if (!sharedKeyId) { state._vm.sharedKeyIds.push({ id: key.id, + // Contract ID this key is for contractID: v2.contractID, + // Contract ID used for encrypting the key + foreignContractIDs: v2.foreignContractID ? [[v2.foreignContractID, height]] : [], height, keyRequestHash: v2.keyRequestHash, keyRequestHeight: v2.keyRequestHeight }); + } else if (v2.foreignContractID) { + if (!sharedKeyId.foreignContractIDs) { + sharedKeyId.foreignContractIDs = [[v2.foreignContractID, height]]; + } else { + const tuple = sharedKeyId.foreignContractIDs.find(([id]) => id === v2.foreignContractID); + if (tuple) { + tuple[2] = height; + } else { + sharedKeyId.foreignContractIDs.push([v2.foreignContractID, height]); + } + } } } } @@ -65151,24 +65325,42 @@ var internals_default = esm_default("sbp/selectors/register", { }, [SPMessage.OP_KEY_REQUEST](wv) { const data = config2.unwrapMaybeEncryptedData(wv); - const v2 = data?.data || { + let skipInviteAccounting = false; + let encryptedRequest = false; + const v2 = (() => { + if (!data) + return; + if (!data.encryptionKeyId && has(data.data, "innerData")) { + skipInviteAccounting = !!data.data.skipInviteAccounting; + const innerData = config2.unwrapMaybeEncryptedData(data.data.innerData); + encryptedRequest = !!innerData?.encryptionKeyId; + return innerData?.data; + } else { + encryptedRequest = !!data.encryptionKeyId; + return data.data; + } + })() || { contractID: "(private)", replyWith: { context: void 0 }, - request: "*" + request: "(private)" }; const originatingContractID = v2.contractID; - if (state._vm?.invites?.[signingKeyId]?.quantity != null) { - if (state._vm.invites[signingKeyId].quantity > 0) { - if (--state._vm.invites[signingKeyId].quantity <= 0) { - state._vm.invites[signingKeyId].status = INVITE_STATUS.USED; - } - } else { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it exceeds allowed quantity: " + originatingContractID); + if (state._vm?.invites?.[signingKeyId] && !skipInviteAccounting) { + if (state._vm.invites[signingKeyId].status !== INVITE_STATUS.VALID) { + logEvtError(message, "[processMessage] Ignoring OP_KEY_REQUEST because it is not valid: " + originatingContractID); return; } - } - if (state._vm?.invites?.[signingKeyId]?.expires != null) { - if (state._vm.invites[signingKeyId].expires < Date.now()) { + if (state._vm?.invites?.[signingKeyId]?.quantity != null) { + if (state._vm.invites[signingKeyId].quantity > 0) { + if (--state._vm.invites[signingKeyId].quantity <= 0) { + state._vm.invites[signingKeyId].status = INVITE_STATUS.USED; + } + } else { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it exceeds allowed quantity: " + originatingContractID); + return; + } + } + if (state._vm.invites[signingKeyId].expires != null && state._vm.invites[signingKeyId].expires < Date.now()) { logEvtError(message, "Ignoring OP_KEY_REQUEST because it expired at " + state._vm.invites[signingKeyId].expires + ": " + originatingContractID); return; } @@ -65181,12 +65373,8 @@ var internals_default = esm_default("sbp/selectors/register", { return; } const context = v2.replyWith.context; - if (data && (!Array.isArray(context) || context[0] !== originatingContractID)) { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it is signed by the wrong contract"); - return; - } - if (v2.request !== "*") { - logEvtError(message, "Ignoring OP_KEY_REQUEST because it has an unsupported request attribute", v2.request); + if (Array.isArray(context) && context[0] !== originatingContractID) { + logEvtError(message, "Ignoring OP_KEY_REQUEST because it is signed by the wrong contract", originatingContractID + " !== " + context[0]); return; } if (!state._vm.pendingKeyshares) @@ -65194,12 +65382,15 @@ var internals_default = esm_default("sbp/selectors/register", { state._vm.pendingKeyshares[message.hash()] = context ? [ // Full-encryption (i.e., KRS encryption) requires that this request // was encrypted and that the invite is marked as private - !!data?.encryptionKeyId, + encryptedRequest, message.height(), signingKeyId, - context - ] : [!!data?.encryptionKeyId, message.height(), signingKeyId]; - if (data) { + context, + v2.request, + message.manifest(), + skipInviteAccounting + ] : [encryptedRequest, message.height(), signingKeyId]; + if (context) { internalSideEffectStack?.push(() => { self2.setPostSyncOp(contractID, "respondToAllKeyRequests-" + message.contractID(), [ "chelonia/private/respondToAllKeyRequests", @@ -65220,7 +65411,7 @@ var internals_default = esm_default("sbp/selectors/register", { const hash4 = v2.keyRequestHash; const pending = state._vm.pendingKeyshares[hash4]; delete state._vm.pendingKeyshares[hash4]; - if (pending.length !== 4) + if (pending.length !== 4 && pending.length !== 7) return; const keyId2 = pending[2]; const originatingContractID = pending[3][0]; @@ -65229,13 +65420,18 @@ var internals_default = esm_default("sbp/selectors/register", { } if (!has(state._vm, "keyshares")) state._vm.keyshares = /* @__PURE__ */ Object.create(null); - const success = v2.success; + let inner = v2; + if (data.encryptionKeyId == null && has(v2, "innerData")) { + const innerResult = config2.unwrapMaybeEncryptedData(v2.innerData); + inner = innerResult?.data; + } + const success = inner?.success; state._vm.keyshares[hash4] = { contractID: originatingContractID, height, success, ...success && { - hash: v2.keyShareHash + hash: inner?.keyShareHash } }; } @@ -65284,12 +65480,9 @@ var internals_default = esm_default("sbp/selectors/register", { } return true; }); + deleteKeyHelper(state, height, keyIds); keyIds.forEach((keyId2) => { const key = state._vm.authorizedKeys[keyId2]; - state._vm.authorizedKeys[keyId2]._notAfterHeight = height; - if (has(state._volatile.pendingKeyRevocations, keyId2)) { - delete state._volatile.pendingKeyRevocations[keyId2]; - } if (key.foreignKey) { const fkUrl = new URL(key.foreignKey); const foreignContract = fkUrl.pathname; @@ -65341,19 +65534,54 @@ var internals_default = esm_default("sbp/selectors/register", { } const [updatedKeys, updatedMap] = validateKeyUpdatePermissions.call(self2, contractID, signingKey, state, v2); const keysToDelete = Object.values(updatedMap); - for (const keyId2 of keysToDelete) { - if (has(state._volatile.pendingKeyRevocations, keyId2)) { - delete state._volatile.pendingKeyRevocations[keyId2]; - } - state._vm.authorizedKeys[keyId2]._notAfterHeight = height; - } + deleteKeyHelper(state, height, keysToDelete); + let canMirrorOperationsUpToRingLevel = NaN; + let hasOutOfSyncKeys = false; for (const key of updatedKeys) { if (!has(state._vm.authorizedKeys, key.id)) { key._notBeforeHeight = height; state._vm.authorizedKeys[key.id] = cloneDeep(key); + } else if (state._vm.authorizedKeys[key.id]._notAfterHeight == null) { + state._vm.authorizedKeys[key.id] = updateKey(state._vm.authorizedKeys[key.id], key); + } else { + throw new Error("Unable to update a deleted key"); + } + if (key.foreignKey != null) { + if (!(key.ringLevel >= canMirrorOperationsUpToRingLevel)) { + const signingKey2 = findSuitableSecretKeyId(state, [SPMessage.OP_KEY_DEL], ["sig"], key.ringLevel); + if (signingKey2) { + canMirrorOperationsUpToRingLevel = key.ringLevel; + } + } + const fkUrl = new URL(key.foreignKey); + const foreignContractID = fkUrl.pathname; + const foreignKeyName = fkUrl.searchParams.get("keyName"); + if (!foreignKeyName) + throw new Error("Missing foreign key name"); + const foreignState = esm_default("chelonia/contract/state", foreignContractID); + if (foreignState) { + const fKeyId = findKeyIdByName(foreignState, foreignKeyName); + if (!fKeyId) { + self2.config.reactiveSet(state._volatile.pendingKeyRevocations, key.id, "del"); + hasOutOfSyncKeys = true; + } else if (fKeyId !== key.id) { + self2.config.reactiveSet(state._volatile.pendingKeyRevocations, key.id, true); + hasOutOfSyncKeys = true; + } + } } } keyAdditionProcessor.call(self2, message, hash3, updatedKeys, state, contractID, signingKey, internalSideEffectStack); + if (Number.isFinite(canMirrorOperationsUpToRingLevel) && hasOutOfSyncKeys) { + internalSideEffectStack?.push(() => { + esm_default("chelonia/private/queueEvent", contractID, [ + "chelonia/private/deleteOrRotateRevokedKeys", + contractID + ]).catch((e2) => { + console.error(`Error at deleteOrRotateRevokedKeys for contractID ${contractID} at OP_KEY_UPDATE with ${hash3}`, e2); + }); + }); + } if (Array.isArray(state._volatile?.watch)) { const updatedKeysMap = /* @__PURE__ */ Object.create(null); updatedKeys.forEach((key) => { @@ -65394,7 +65622,7 @@ var internals_default = esm_default("sbp/selectors/register", { } } : state; if (!validateKeyPermissions(message, config2, stateForValidation, signingKeyId, opT, opV)) { - throw new Error("No matching signing key was defined"); + throw new Error(`No matching signing key was defined: ${signingKeyId} of ${hash3} (${contractID})`); } signingKey = stateForValidation._vm.authorizedKeys[signingKeyId]; } @@ -65403,6 +65631,7 @@ var internals_default = esm_default("sbp/selectors/register", { } if (processOp) { await opFns[opT](opV); + esm_default("chelonia/private/operationHook", contractID, message, state); config2.postOp?.(message, state); config2[`postOp_${opT}`]?.(message, state); } @@ -65514,9 +65743,9 @@ var internals_default = esm_default("sbp/selectors/register", { } Object.entries(pendingWatch).forEach(([contractID, keys]) => { if (!Array.isArray(keys) || // Check that the keys exist and haven't been revoked - !keys.reduce((acc, [, id]) => { - return acc || has(externalContractState._vm.authorizedKeys, id); - }, false)) { + !keys.some(([, id]) => { + return has(externalContractState._vm.authorizedKeys, id); + })) { console.info("[chelonia/private/watchForeignKeys]: Skipping as none of the keys to watch exist", { externalContractID, contractID @@ -65537,9 +65766,9 @@ var internals_default = esm_default("sbp/selectors/register", { const externalContractState = rootState[externalContractID]; const pendingWatch = externalContractState?._vm?.pendingWatch?.[contractID]?.splice(0); if (!Array.isArray(pendingWatch) || // Check that the keys exist and haven't been revoked - !pendingWatch.reduce((acc, [, id]) => { - return acc || has(externalContractState._vm.authorizedKeys, id) && findKeyIdByName(externalContractState, externalContractState._vm.authorizedKeys[id].name) != null; - }, false)) { + !pendingWatch.some(([, id]) => { + return has(externalContractState._vm.authorizedKeys, id) && findKeyIdByName(externalContractState, externalContractState._vm.authorizedKeys[id].name) != null; + })) { console.info("[chelonia/private/syncContractAndWatchKeys]: Skipping as none of the keys to watch exist", { externalContractID, contractID @@ -65616,10 +65845,18 @@ var internals_default = esm_default("sbp/selectors/register", { const pendingKeyRevocations = contractState?._volatile?.pendingKeyRevocations; if (!pendingKeyRevocations || Object.keys(pendingKeyRevocations).length === 0) return; + const activeForeignKeyIds = Object.fromEntries(Object.values(contractState._vm.authorizedKeys).filter(({ foreignKey, _notAfterHeight }) => foreignKey != null && _notAfterHeight == null).map(({ foreignKey, id }) => [foreignKey, id])); const keysToUpdate = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === true).map(([id]) => id); + const affectedKeyIds = /* @__PURE__ */ new Set(); const [, keyUpdateSigningKeyId, keyUpdateArgs] = keysToUpdate.reduce((acc, keyId2) => { - const key = contractState._vm?.authorizedKeys?.[keyId2]; - if (!key || !key.foreignKey) + const pkrKey = contractState._vm?.authorizedKeys?.[keyId2]; + if (!pkrKey || !pkrKey.foreignKey) + return acc; + const activeKeyId = activeForeignKeyIds[pkrKey.foreignKey]; + if (!activeKeyId) + return acc; + const key = contractState._vm.authorizedKeys[activeKeyId]; + if (affectedKeyIds.has(key.id)) return acc; const foreignKey = String(key.foreignKey); const fkUrl = new URL(foreignKey); @@ -65636,13 +65873,17 @@ var internals_default = esm_default("sbp/selectors/register", { this.config.reactiveSet(pendingKeyRevocations, keyId2, "del"); } return acc; + } else if (fKeyId === key.id) { + this.config.reactiveDel(pendingKeyRevocations, keyId2); + return acc; } const [currentRingLevel, currentSigningKeyId, currentKeyArgs] = acc; - const ringLevel = Math.min(currentRingLevel, key.ringLevel ?? Number.POSITIVE_INFINITY); + const ringLevel = Math.min(currentRingLevel, key.ringLevel ?? Number.MAX_SAFE_INTEGER); if (ringLevel >= currentRingLevel) { + affectedKeyIds.add(key.id); currentKeyArgs.push({ name: key.name, - oldKeyId: keyId2, + oldKeyId: key.id, id: fKeyId, data: foreignState._vm.authorizedKeys[fKeyId].data }); @@ -65650,9 +65891,10 @@ var internals_default = esm_default("sbp/selectors/register", { } else if (Number.isFinite(ringLevel)) { const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_UPDATE], ["sig"], ringLevel); if (signingKeyId) { + affectedKeyIds.add(key.id); currentKeyArgs.push({ name: key.name, - oldKeyId: keyId2, + oldKeyId: key.id, id: fKeyId, data: foreignState._vm.authorizedKeys[fKeyId].data }); @@ -65677,15 +65919,23 @@ var internals_default = esm_default("sbp/selectors/register", { }); } const keysToDelete = Object.entries(pendingKeyRevocations).filter(([, v2]) => v2 === "del").map(([id]) => id); - const [, keyDelSigningKeyId, keyIdsToDelete] = keysToDelete.reduce((acc, keyId2) => { + const [, keyDelSigningKeyId, keyIdsToDelete] = keysToDelete.reduce((acc, pkrKeyId) => { + const pkrKey = contractState._vm?.authorizedKeys?.[pkrKeyId]; + if (!pkrKey || !pkrKey.foreignKey) + return acc; + const keyId2 = activeForeignKeyIds[pkrKey.foreignKey]; + if (!keyId2 || affectedKeyIds.has(keyId2)) + return acc; const [currentRingLevel, currentSigningKeyId, currentKeyIds] = acc; - const ringLevel = Math.min(currentRingLevel, contractState._vm?.authorizedKeys?.[keyId2]?.ringLevel ?? Number.POSITIVE_INFINITY); + const ringLevel = Math.min(currentRingLevel, contractState._vm?.authorizedKeys?.[keyId2]?.ringLevel ?? Number.MAX_SAFE_INTEGER); if (ringLevel >= currentRingLevel) { + affectedKeyIds.add(keyId2); currentKeyIds.push(keyId2); return [currentRingLevel, currentSigningKeyId, currentKeyIds]; } else if (Number.isFinite(ringLevel)) { const signingKeyId = findSuitableSecretKeyId(contractState, [SPMessage.OP_KEY_DEL], ["sig"], ringLevel); if (signingKeyId) { + affectedKeyIds.add(keyId2); currentKeyIds.push(keyId2); return [ringLevel, signingKeyId, currentKeyIds]; } @@ -65700,13 +65950,13 @@ var internals_default = esm_default("sbp/selectors/register", { data: keyIdsToDelete, signingKeyId: keyDelSigningKeyId }).catch((e2) => { - console.error(`[chelonia/private/deleteRevokedKeys] Error sending OP_KEY_DEL for ${contractID}`, e2.message); + console.error(`[chelonia/private/deleteOrRotateRevokedKeys] Error sending OP_KEY_DEL for ${contractID}`, e2.message); }); } }, "chelonia/private/respondToAllKeyRequests": function(contractID) { const state = esm_default(this.config.stateSelector); - const contractState = state[contractID] ?? {}; + const contractState = state[contractID] ?? { _vm: {} }; const pending = contractState?._vm?.pendingKeyshares; if (!pending) return; @@ -65716,7 +65966,7 @@ var internals_default = esm_default("sbp/selectors/register", { return; } Object.entries(pending).map(([hash3, entry]) => { - if (!Array.isArray(entry) || entry.length !== 4) { + if (!Array.isArray(entry) || entry.length !== 4 && entry.length !== 7) { return void 0; } const [, , , [originatingContractID]] = entry; @@ -65735,12 +65985,11 @@ var internals_default = esm_default("sbp/selectors/register", { const contractState = state[contractID]; const entry = contractState?._vm?.pendingKeyshares?.[hash3]; const instance = this._instance; - if (!Array.isArray(entry) || entry.length !== 4) { + if (!Array.isArray(entry) || entry.length !== 4 && entry.length !== 7 || has(entry, "processing")) { return; } - const [keyShareEncryption, height, , [originatingContractID, rv, originatingContractHeight, headJSON]] = entry; - entry.pop(); - const krsEncryption = !!contractState._vm.authorizedKeys?.[signingKeyId]?._private; + const [keyShareEncryption, height, inviteId, [originatingContractID, rv, originatingContractHeight, headJSON], request, manifestHash, requestedSkipInviteAccounting] = entry; + const krsEncryption = keyShareEncryption; await esm_default("chelonia/private/in/syncContract", originatingContractID); if (instance !== this._instance) return; @@ -65752,28 +66001,106 @@ var internals_default = esm_default("sbp/selectors/register", { const responseKey = encryptedIncomingData(contractID, contractState, v2.responseKey, height, this.transientSecretKeys, headJSON).valueOf(); const deserializedResponseKey = deserializeKey(responseKey); const responseKeyId = keyId(deserializedResponseKey); - Promise.resolve().then(() => { + Promise.resolve().then(async () => { if (instance !== this._instance) return; + if (has(entry, "processing")) + return; + if (!contractState?._vm?.pendingKeyshares?.[hash3]) { + return; + } + Object.defineProperty(entry, "processing", { configurable: true, value: true }); if (!has(originatingState._vm.authorizedKeys, responseKeyId) || originatingState._vm.authorizedKeys[responseKeyId]._notAfterHeight != null) { throw new Error(`Unable to respond to key request for ${originatingContractID}. Key ${responseKeyId} is not valid.`); } esm_default("chelonia/storeSecretKeys", new Secret([{ key: deserializedResponseKey }])); - const keys = pick2(state.secretKeys, Object.entries(contractState._vm.authorizedKeys).filter(([, key]) => !!key.meta?.private?.shareable).map(([kId]) => kId)); - if (!keys || Object.keys(keys).length === 0) { - console.info("respondToAllKeyRequests: no keys to share", { + let keyIds; + let skipInviteAccounting; + if (request == null || request === "*") { + if (contractState._vm?.invites?.[inviteId]?.expires != null) { + if (contractState._vm.invites[inviteId].expires < Date.now()) { + console.error("[respondToKeyRequest] Ignoring OP_KEY_REQUEST because it expired at " + contractState._vm.invites[inviteId].expires + ": " + originatingContractID); + return; + } + } + keyIds = Object.entries(contractState._vm.authorizedKeys).filter(([, key]) => !!key.meta?.private?.shareable).map(([kId]) => kId); + } else if (manifestHash) { + const contractName2 = this.manifestToContract[manifestHash]?.name; + if (!contractName2) + return; + const method = `${manifestHash}/${contractName2}/_responseOptionsForKeyRequest`; + if (esm_default("sbp/selectors/fn", method)) { + try { + const result = await esm_default(method, { + contractID, + request, + state: contractState, + keyShareEncryption, + height, + inviteId, + originatingContractID, + originatingContractHeight + }); + if (result) { + keyIds = result.keyIds; + skipInviteAccounting = result.skipInviteAccounting; + } + } catch (e2) { + console.warn("[respondToKeyRequest] Cannot respond: hook errored", { + contractID, + originatingContractID, + inviteId, + request, + e: e2 + }); + return; + } + } else { + console.warn("[respondToKeyRequest] Cannot respond: hook not defined", { + contractID, + originatingContractID, + inviteId, + request + }); + return; + } + } + if (!Array.isArray(keyIds)) { + console.info("[respondToKeyRequest] no keys to share", { contractID, - originatingContractID + originatingContractID, + inviteId, + request }); return; + } else if (keyIds.length === 0) { + console.info("[respondToKeyRequest] explicitly empty keyshare response", { + contractID, + originatingContractID, + inviteId, + request + }); + return [null, skipInviteAccounting]; + } + for (let i2 = 0; i2 < keyIds.length; i2++) { + if (!state.secretKeys[keyIds[i2]]) { + console.info("[respondToKeyRequest] missing key id", { + contractID, + originatingContractID, + inviteId, + request, + keyId: keyIds[i2] + }); + return; + } } const keySharePayload = { contractID, - keys: Object.entries(keys).map(([keyId2, key]) => ({ + keys: keyIds.map((keyId2) => ({ id: keyId2, meta: { private: { - content: encryptedOutgoingData(originatingContractID, encryptionKeyId, key), + content: encryptedOutgoingData(originatingContractID, encryptionKeyId, state.secretKeys[keyId2]), shareable: true } } @@ -65781,63 +66108,68 @@ var internals_default = esm_default("sbp/selectors/register", { keyRequestHash: hash3, keyRequestHeight: height }; - if (!contractState?._vm?.pendingKeyshares?.[hash3]) { + return [keySharePayload, skipInviteAccounting]; + }).then(async (value) => { + if (instance !== this._instance || !value) return; + const [keySharePayload, skipInviteAccounting] = value; + if (!!requestedSkipInviteAccounting !== !!skipInviteAccounting) { + console.error(`Error at respondToKeyRequest: mismatched result for skipInviteAccounting (${!!requestedSkipInviteAccounting} !== ${!!skipInviteAccounting}) for ${contractID}`); + throw new Error("Mismatched skipInviteAccounting"); } - return keySharePayload; - }).then((keySharePayload) => { - if (instance !== this._instance || !keySharePayload) - return; - return esm_default("chelonia/out/keyShare", { + const msg = keySharePayload && await esm_default("chelonia/out/keyShare", { contractID: originatingContractID, contractName: originatingContractName, data: keyShareEncryption ? encryptedOutgoingData(originatingContractID, findSuitablePublicKeyIds(originatingState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", keySharePayload) : keySharePayload, signingKeyId: responseKeyId - }).then((msg) => { - if (instance !== this._instance) - return; - const payload = { keyRequestHash: hash3, keyShareHash: msg.hash(), success: true }; - const connectionKeyPayload = { - contractID: originatingContractID, - keys: [ - { - id: responseKeyId, - meta: { - private: { - content: encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", responseKey), - shareable: true - } + }); + if (instance !== this._instance) + return; + const innerPayload = { keyShareHash: msg?.hash(), success: true }; + const connectionKeyPayload = { + contractID: originatingContractID, + keys: [ + { + id: responseKeyId, + meta: { + private: { + content: encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", responseKey), + shareable: true } } - ] - }; - esm_default("chelonia/out/atomic", { - contractID, - contractName, - signingKeyId, - data: [ - [ - "chelonia/out/keyRequestResponse", - { - data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload - } - ], - [ - // Upon successful key share, we want to share deserializedResponseKey - // with ourselves - "chelonia/out/keyShare", - { - data: keyShareEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", connectionKeyPayload) : connectionKeyPayload + } + ] + }; + esm_default("chelonia/out/atomic", { + contractID, + contractName, + signingKeyId, + data: [ + [ + "chelonia/out/keyRequestResponse", + { + data: { + keyRequestHash: hash3, + skipInviteAccounting, + innerData: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", innerPayload) : innerPayload } - ] + } + ], + [ + // Upon successful key share, we want to share deserializedResponseKey + // with ourselves + "chelonia/out/keyShare", + { + data: keyShareEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_SHARE], ["enc"])?.[0] || "", connectionKeyPayload) : connectionKeyPayload + } ] - }).catch((e2) => { - console.error("Error at respondToKeyRequest while sending keyRequestResponse", e2); - }); + ] + }).catch((e2) => { + console.error("Error at respondToKeyRequest while sending keyRequestResponse", e2); }); }).catch((e2) => { console.error("Error at respondToKeyRequest", e2); - const payload = { keyRequestHash: hash3, success: false }; + const innerPayload = { success: false }; if (!contractState?._vm?.pendingKeyshares?.[hash3]) { return; } @@ -65845,7 +66177,11 @@ var internals_default = esm_default("sbp/selectors/register", { contractID, contractName, signingKeyId, - data: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", payload) : payload + data: { + keyRequestHash: hash3, + skipInviteAccounting: requestedSkipInviteAccounting, + innerData: krsEncryption ? encryptedOutgoingData(contractID, findSuitablePublicKeyIds(contractState, [SPMessage.OP_KEY_REQUEST_SEEN], ["enc"])?.[0] || "", innerPayload) : innerPayload + } }).catch((e3) => { console.error("Error at respondToKeyRequest while sending keyRequestResponse in error handler", e3); }); @@ -66270,6 +66606,10 @@ var chelonia_default = esm_default("sbp/selectors/register", { // Similarly, future events will not be reingested and will throw // with ChelErrorDBBadPreviousHEAD strictOrdering: false, + // Chelonia will store some information (e.g., date it was received) about + // messages. This is primarily useful in the server, and not so useful for + // clients, especially for lightweight clients that don't store messages. + saveMessageMetadata: false, connectionOptions: { maxRetries: Infinity, // See https://github.com/okTurtles/group-income/issues/1183 @@ -66321,16 +66661,16 @@ var chelonia_default = esm_default("sbp/selectors/register", { const secretKeyGetter = (o2, p) => { if (has(o2, p)) return o2[p]; - const rootState = esm_default(this.config.stateSelector); - if (rootState?.secretKeys && has(rootState.secretKeys, p)) { - const key = deserializeKey(rootState.secretKeys[p]); + const rootState2 = esm_default(this.config.stateSelector); + if (rootState2?.secretKeys && has(rootState2.secretKeys, p)) { + const key = deserializeKey(rootState2.secretKeys[p]); o2[p] = key; return key; } }; const secretKeyList = (o2) => { - const rootState = esm_default(this.config.stateSelector); - const stateKeys = Object.keys(rootState?.secretKeys || {}); + const rootState2 = esm_default(this.config.stateSelector); + const stateKeys = Object.keys(rootState2?.secretKeys || {}); return Array.from(/* @__PURE__ */ new Set([...Object.keys(o2), ...stateKeys])); }; this.transientSecretKeys = new Proxy(/* @__PURE__ */ Object.create(null), { @@ -66340,6 +66680,8 @@ var chelonia_default = esm_default("sbp/selectors/register", { this.ephemeralReferenceCount = /* @__PURE__ */ Object.create(null); this.subscriptionSet = /* @__PURE__ */ new Set(); this.pending = []; + const rootState = esm_default(this.config.stateSelector); + rootState.secretKeys = rootState.secretKeys || /* @__PURE__ */ Object.create(null); }, "chelonia/config": function() { return { @@ -66402,6 +66744,7 @@ var chelonia_default = esm_default("sbp/selectors/register", { this.abortController = new AbortController(); reactiveClearObject(rootState, this.config.reactiveDel); this.config.reactiveSet(rootState, "contracts", /* @__PURE__ */ Object.create(null)); + this.config.reactiveSet(rootState, "secretKeys", /* @__PURE__ */ Object.create(null)); clearObject(this.ephemeralReferenceCount); this.pending.splice(0); clearObject(this.currentSyncs); @@ -66580,9 +66923,25 @@ var chelonia_default = esm_default("sbp/selectors/register", { const keyId2 = findSuitableSecretKeyId(contractIDOrState, permissions, purposes, ringLevel, allowedActions); return keyId2; }, - "chelonia/contract/setPendingKeyRevocation": function(contractID, names) { - const rootState = esm_default(this.config.stateSelector); - const state = rootState[contractID]; + // setPendingKeyRevocation is meant to be called by contracts (or applications) + // to mark a set of keys as pending revocation / rotation (that is, adding the + // key to `_volatile.pendingKeyRevocations`). + // Keys that are marked as pending revocation can then be collected by key + // rotation logic (currently, 'gi.actions/out/rotateKeys') to rotate them or + // delete them. + // Calling this selector in itself doesn't revoke or rotate the key. It will + // just set a flag on that key for later handling. The flag is automatically + // cleared when the key is updated or deleted. + "chelonia/contract/setPendingKeyRevocation": function(contractIDOrState, names, keyIds) { + let state; + let contractID; + if (typeof contractIDOrState === "string") { + const rootState = esm_default(this.config.stateSelector); + contractID = contractIDOrState; + state = rootState[contractIDOrState]; + } else { + state = contractIDOrState; + } if (!state._volatile) this.config.reactiveSet(state, "_volatile", /* @__PURE__ */ Object.create(null)); if (!state._volatile.pendingKeyRevocations) { @@ -66591,10 +66950,12 @@ var chelonia_default = esm_default("sbp/selectors/register", { for (const name of names) { const keyId2 = findKeyIdByName(state, name); if (keyId2) { + if (keyIds && !keyIds.includes(keyId2)) + continue; this.config.reactiveSet(state._volatile.pendingKeyRevocations, keyId2, true); } else { console.warn("[setPendingKeyRevocation] Unable to find keyId for name", { - contractID, + contractID: contractID ?? "(unknown)", name }); } @@ -67004,6 +67365,17 @@ var chelonia_default = esm_default("sbp/selectors/register", { confirmRemovalCallback: boundCheckCanBeGarbageCollected }) : void 0; }, + // Higher level function to automatically retain / release a contract + "chelonia/contract/withRetained": async function(contractIDs, callback) { + await esm_default("chelonia/contract/retain", contractIDs, { ephemeral: true }); + try { + return await callback(); + } finally { + await esm_default("chelonia/contract/release", contractIDs, { ephemeral: true }).catch((e2) => { + console.error("[withRetained] Error releasing contract:", e2); + }); + } + }, "chelonia/contract/disconnect": async function(contractID, contractIDToDisconnect) { const state = esm_default(this.config.stateSelector); const contractState = state[contractID]; @@ -67403,7 +67775,7 @@ var chelonia_default = esm_default("sbp/selectors/register", { return msg; }, "chelonia/out/keyRequest": async function(params) { - const { originatingContractID, originatingContractName, contractID, contractName, hooks, publishOptions, innerSigningKeyId, encryptionKeyId, innerEncryptionKeyId, encryptKeyRequestMetadata, reference } = params; + const { originatingContractID, originatingContractName, contractID, contractName, hooks, publishOptions, innerSigningKeyId, encryptionKeyId, innerEncryptionKeyId, encryptKeyRequestMetadata, reference, request, keyRequestResponseId, skipInviteAccounting } = params; const manifestHash = this.config.contracts.manifests[contractName]; const originatingManifestHash = this.config.contracts.manifests[originatingContractName]; const contract = this.manifestToContract[manifestHash]?.contract; @@ -67411,56 +67783,68 @@ var chelonia_default = esm_default("sbp/selectors/register", { if (!contract) { throw new Error("Contract name not found"); } - const rootState = esm_default(this.config.stateSelector); - try { - await esm_default("chelonia/contract/retain", contractID, { ephemeral: true }); + return await esm_default("chelonia/contract/withRetained", contractID, async () => { + const rootState = esm_default(this.config.stateSelector); const state = contract.state(contractID); const originatingState = originatingContract.state(originatingContractID); - const havePendingKeyRequest = Object.values(originatingState._vm.authorizedKeys).findIndex((k) => { - return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractID && state?._volatile?.pendingKeyRequests?.some((pkr) => pkr.name === k.name); - }) !== -1; + const havePendingKeyRequest = Object.values(originatingState._vm.authorizedKeys).some((k) => { + return k._notAfterHeight == null && k.meta?.keyRequest?.contractID === contractID && state?._volatile?.pendingKeyRequests?.some((pkr) => pkr.name === k.name && pkr.reference === reference); + }); if (havePendingKeyRequest) { return; } - const keyRequestReplyKey = keygen(EDWARDS25519SHA512BATCH); - const keyRequestReplyKeyId = keyId(keyRequestReplyKey); - const keyRequestReplyKeyP = serializeKey(keyRequestReplyKey, false); - const keyRequestReplyKeyS = serializeKey(keyRequestReplyKey, true); - const signingKeyId = findSuitableSecretKeyId(originatingState, [SPMessage.OP_KEY_ADD], ["sig"]); - if (!signingKeyId) { - throw new ChelErrorUnexpected(`Unable to send key request. Originating contract is missing a key with OP_KEY_ADD permission. contractID=${contractID} originatingContractID=${originatingContractID}`); - } - const keyAddOp = () => esm_default("chelonia/out/keyAdd", { - contractID: originatingContractID, - contractName: originatingContractName, - data: [ - { - id: keyRequestReplyKeyId, - name: "#krrk-" + keyRequestReplyKeyId, - purpose: ["sig"], - ringLevel: Number.MAX_SAFE_INTEGER, - permissions: params.permissions === "*" ? "*" : Array.isArray(params.permissions) ? [...params.permissions, SPMessage.OP_KEY_SHARE] : [SPMessage.OP_KEY_SHARE], - allowedActions: params.allowedActions, - meta: { - private: { - content: encryptedOutgoingData(originatingContractID, encryptionKeyId, keyRequestReplyKeyS), - shareable: false - }, - keyRequest: { - ...reference && { - reference: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, reference) : reference + let keyRequestReplyKeyS; + let keyAddOp; + if (keyRequestResponseId) { + if (!originatingState._vm.authorizedKeys[keyRequestResponseId] || originatingState._vm.authorizedKeys[keyRequestResponseId]._notAfterHeight != null) { + throw new Error(`Contract ID ${originatingContractID} is missing key or it has expired: ${keyRequestResponseId}`); + } + if (!rootState.secretKeys[keyRequestResponseId]) { + throw new Error("Missing secret key ID " + keyRequestResponseId); + } + keyRequestReplyKeyS = rootState.secretKeys[keyRequestResponseId]; + keyAddOp = () => Promise.resolve(); + } else { + const keyRequestReplyKey = keygen(EDWARDS25519SHA512BATCH); + const keyRequestReplyKeyId = keyId(keyRequestReplyKey); + const keyRequestReplyKeyP = serializeKey(keyRequestReplyKey, false); + keyRequestReplyKeyS = serializeKey(keyRequestReplyKey, true); + const signingKeyId = findSuitableSecretKeyId(originatingState, [SPMessage.OP_KEY_ADD], ["sig"]); + if (!signingKeyId) { + throw new ChelErrorUnexpected(`Unable to send key request. Originating contract is missing a key with OP_KEY_ADD permission. contractID=${contractID} originatingContractID=${originatingContractID}`); + } + keyAddOp = () => esm_default("chelonia/out/keyAdd", { + contractID: originatingContractID, + contractName: originatingContractName, + data: [ + { + id: keyRequestReplyKeyId, + name: "#krrk-" + keyRequestReplyKeyId, + purpose: ["sig"], + ringLevel: Number.MAX_SAFE_INTEGER, + permissions: params.permissions === "*" ? "*" : Array.isArray(params.permissions) ? [...params.permissions, SPMessage.OP_KEY_SHARE] : [SPMessage.OP_KEY_SHARE], + allowedActions: params.allowedActions, + meta: { + private: { + content: encryptedOutgoingData(originatingContractID, encryptionKeyId, keyRequestReplyKeyS), + shareable: false }, - contractID: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, contractID) : contractID - } - }, - data: keyRequestReplyKeyP - } - ], - signingKeyId - }).catch((e2) => { - console.error(`[chelonia] Error sending OP_KEY_ADD for ${originatingContractID} during key request to ${contractID}`, e2); - throw e2; - }); + keyRequest: { + ...reference && { + reference: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, reference) : reference + }, + contractID: encryptKeyRequestMetadata ? encryptedOutgoingData(originatingContractID, encryptionKeyId, contractID) : contractID + } + }, + data: keyRequestReplyKeyP + } + ], + signingKeyId + }).catch((e2) => { + console.error(`[chelonia] Error sending OP_KEY_ADD for ${originatingContractID} during key request to ${contractID}`, e2); + throw e2; + }); + } const payload = { contractID: originatingContractID, height: rootState.contracts[originatingContractID].height, @@ -67468,13 +67852,16 @@ var chelonia_default = esm_default("sbp/selectors/register", { encryptionKeyId, responseKey: encryptedOutgoingData(contractID, innerEncryptionKeyId, keyRequestReplyKeyS) }, this.transientSecretKeys), - request: "*" + request: request ?? "*" }; let msg = SPMessage.createV1_0({ contractID, op: [ SPMessage.OP_KEY_REQUEST, - signedOutgoingData(contractID, params.signingKeyId, encryptKeyRequestMetadata ? encryptedOutgoingData(contractID, innerEncryptionKeyId, payload) : payload, this.transientSecretKeys) + signedOutgoingData(contractID, params.signingKeyId, { + ...skipInviteAccounting && { skipInviteAccounting: true }, + innerData: encryptKeyRequestMetadata ? encryptedOutgoingData(contractID, innerEncryptionKeyId, payload) : payload + }, this.transientSecretKeys) ], manifest: manifestHash }); @@ -67486,9 +67873,7 @@ var chelonia_default = esm_default("sbp/selectors/register", { } }); return msg; - } finally { - await esm_default("chelonia/contract/release", contractID, { ephemeral: true }); - } + }); }, "chelonia/out/keyRequestResponse": async function(params) { const { atomic, contractID, contractName, data, hooks, publishOptions } = params; @@ -69746,7 +70131,9 @@ var SERVER = { // ignored strictProcessing: true, // The server expects events to be received in order (no past or future events) - strictOrdering: true + strictOrdering: true, + // _private_hidx= entries with per-message metadata + saveMessageMetadata: true }; init_esm(); var import_npm_chalk3 = __toESM(require_source()); @@ -72510,24 +72897,186 @@ var createAdaptorServer = (options2) => { const server = createServer2(options2.serverOptions || {}, requestListener); return server; }; -init_esm7(); +var serdesTagSymbol2 = Symbol("tag"); +var serdesSerializeSymbol2 = Symbol("serialize"); +var serdesDeserializeSymbol2 = Symbol("deserialize"); +var rawResult2 = (rawResultSet, obj) => { + rawResultSet.add(obj); + return obj; +}; +var serializer2 = (data) => { + const rawResultSet = /* @__PURE__ */ new WeakSet(); + const verbatim = []; + const transferables = /* @__PURE__ */ new Set(); + const revokables = /* @__PURE__ */ new Set(); + const result = JSON.parse(JSON.stringify(data, (_key, value) => { + if (value && typeof value === "object" && rawResultSet.has(value)) + return value; + if (value === void 0) + return rawResult2(rawResultSet, ["_", "_"]); + if (!value) + return value; + if (Array.isArray(value) && value[0] === "_") + return rawResult2(rawResultSet, ["_", "_", ...value]); + if (value instanceof Map) { + return rawResult2(rawResultSet, ["_", "Map", Array.from(value.entries())]); + } + if (value instanceof Set) { + return rawResult2(rawResultSet, ["_", "Set", Array.from(value.values())]); + } + if (value instanceof Blob || value instanceof File) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + return rawResult2(rawResultSet, ["_", "_ref", pos]); + } + if (value instanceof Error) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + if (value.cause) { + value.cause = serializer2(value.cause).data; + } + return rawResult2(rawResultSet, ["_", "_err", rawResult2(rawResultSet, ["_", "_ref", pos]), value.name]); + } + if (value instanceof MessagePort || value instanceof ReadableStream || value instanceof WritableStream || value instanceof ArrayBuffer) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + transferables.add(value); + return rawResult2(rawResultSet, ["_", "_ref", pos]); + } + if (ArrayBuffer.isView(value)) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + transferables.add(value.buffer); + return rawResult2(rawResultSet, ["_", "_ref", pos]); + } + if (typeof value === "function") { + const mc = new MessageChannel(); + mc.port1.onmessage = async (ev) => { + try { + try { + const result2 = await value(...deserializer2(ev.data[1])); + const { data: data2, transferables: transferables2 } = serializer2(result2); + ev.data[0].postMessage([true, data2], transferables2); + } catch (e2) { + const { data: data2, transferables: transferables2 } = serializer2(e2); + ev.data[0].postMessage([false, data2], transferables2); + } + } catch (e2) { + console.error("Async error on onmessage handler", e2); + } + }; + transferables.add(mc.port2); + revokables.add(mc.port1); + return rawResult2(rawResultSet, ["_", "_fn", mc.port2]); + } + const proto3 = Object.getPrototypeOf(value); + if (proto3?.constructor?.[serdesTagSymbol2] && proto3.constructor[serdesSerializeSymbol2]) { + return rawResult2(rawResultSet, ["_", "_custom", proto3.constructor[serdesTagSymbol2], proto3.constructor[serdesSerializeSymbol2](value)]); + } + return value; + }), (_key, value) => { + if (Array.isArray(value) && value[0] === "_" && value[1] === "_ref") { + return verbatim[value[2]]; + } + return value; + }); + return { + data: result, + transferables: Array.from(transferables), + revokables: Array.from(revokables) + }; +}; +var deserializerTable2 = /* @__PURE__ */ Object.create(null); +var deserializer2 = (data) => { + const rawResultSet = /* @__PURE__ */ new WeakSet(); + const verbatim = []; + return JSON.parse(JSON.stringify(data, (_key, value) => { + if (value && typeof value === "object" && !rawResultSet.has(value) && !Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype) { + const pos = verbatim.length; + verbatim[verbatim.length] = value; + return rawResult2(rawResultSet, ["_", "_ref", pos]); + } + return value; + }), (_key, value) => { + if (Array.isArray(value) && value[0] === "_") { + switch (value[1]) { + case "_": + if (value.length >= 3) { + return value.slice(2); + } else { + return; + } + // Map input (reconstruct Map) + case "Map": + return new Map(value[2]); + // Set input (reconstruct Set) + case "Set": + return new Set(value[2]); + // Custom object type (reconstruct if possible, otherwise throw an error) + case "_custom": + if (deserializerTable2[value[2]]) { + return deserializerTable2[value[2]](value[3]); + } else { + throw new Error("Invalid or unknown tag: " + value[2]); + } + // These are literal values, return them + case "_ref": + return verbatim[value[2]]; + case "_err": { + if (value[2].name !== value[3]) { + value[2].name = value[3]; + } + if (value[2].cause) { + value[2].cause = deserializer2(value[2].cause); + } + return value[2]; + } + // These were functions converted to a MessagePort. Convert them on this + // end back into functions using that port. + case "_fn": { + const mp = value[2]; + return (...args) => { + return new Promise((resolve82, reject) => { + const mc = new MessageChannel(); + const { data: data2, transferables } = serializer2(args); + mc.port1.onmessage = (ev) => { + if (ev.data[0]) { + resolve82(deserializer2(ev.data[1])); + } else { + reject(deserializer2(ev.data[1])); + } + }; + mp.postMessage([mc.port2, data2], [mc.port2, ...transferables]); + }); + }; + } + } + } + return value; + }); +}; +deserializer2.register = (ctor) => { + if (typeof ctor === "function" && typeof ctor[serdesTagSymbol2] === "string" && typeof ctor[serdesDeserializeSymbol2] === "function") { + deserializerTable2[ctor[serdesTagSymbol2]] = ctor[serdesDeserializeSymbol2].bind(ctor); + } +}; init_esm(); Object.defineProperties(Buffer13, { - [serdesDeserializeSymbol]: { + [serdesDeserializeSymbol2]: { value(buf2) { return Buffer13.from(buf2); } }, - [serdesSerializeSymbol]: { + [serdesSerializeSymbol2]: { value(buf2) { return new Uint8Array(buf2.buffer, buf2.byteOffset, buf2.byteLength); } }, - [serdesTagSymbol]: { + [serdesTagSymbol2]: { value: "node:buffer" } }); -deserializer.register(Buffer13); +deserializer2.register(Buffer13); var createWorker = (path8) => { let worker; let ready; @@ -72550,11 +73099,11 @@ var createWorker = (path8) => { resolve82(); } else if (msg && typeof msg === "object" && msg.type === "sbp" && Array.isArray(msg.data) && String(msg.data[0]).startsWith("chelonia.db/")) { const port = msg.port; - Promise.try(() => esm_default(...deserializer(msg.data))).then((r) => { - const { data, transferables } = serializer(r); + Promise.try(() => esm_default(...deserializer2(msg.data))).then((r) => { + const { data, transferables } = serializer2(r); port.postMessage([true, data], transferables); }).catch((e2) => { - const { data, transferables } = serializer(e2); + const { data, transferables } = serializer2(e2); port.postMessage([false, data], transferables); }).finally(() => { port.close(); @@ -73406,16 +73955,17 @@ function registerRoutes(app) { const formData = await c.req.parseBody({ all: true }); const hash3 = formData["hash"]; const data = formData["data"]; - if (!hash3) throw new HTTPException(400, { message: "missing hash" }); - if (!data) throw new HTTPException(400, { message: "missing data" }); + if (!hash3 || typeof hash3 !== "string") throw new HTTPException(400, { message: "missing hash" }); + if (!data || Array.isArray(data)) throw new HTTPException(400, { message: "missing data" }); const parsed = maybeParseCID(hash3); if (!parsed) throw new HTTPException(400, { message: "invalid hash" }); - const ourHash = createCID(data, parsed.code); + const dataStringOrBytes = typeof data === "string" ? data : Buffer14.from(await data.bytes()).toString(); + const ourHash = createCID(dataStringOrBytes, parsed.code); if (ourHash !== hash3) { console.error(`hash(${hash3}) != ourHash(${ourHash})`); throw new HTTPException(400, { message: "bad hash!" }); } - await esm_default("chelonia.db/set", hash3, data); + await esm_default("chelonia.db/set", hash3, dataStringOrBytes); return c.text("/file/" + hash3); } catch (err) { if (err instanceof HTTPException) throw err; diff --git a/deno.json b/deno.json index 8920949..83c1d96 100644 --- a/deno.json +++ b/deno.json @@ -45,7 +45,7 @@ "npm:vuelidate": "npm:vuelidate@0.7.6", "npm:vuex": "npm:vuex@3.6.0", "npm:multiformats/": "npm:multiformats@11.0.2/", - "npm:@chelonia/lib/": "npm:@chelonia/lib@1.2.9/", + "npm:@chelonia/lib/": "npm:@chelonia/lib@1.4.3/", "npm:lru-cache": "npm:lru-cache@7.14.0", "npm:pino": "npm:pino@8.19.0", "npm:tweetnacl": "npm:tweetnacl@1.0.3", diff --git a/deno.lock b/deno.lock index 6998d96..2ed6be1 100644 --- a/deno.lock +++ b/deno.lock @@ -25,9 +25,8 @@ "npm:@apeleghq/rfc8188@*": "1.0.8", "npm:@apeleghq/rfc8188@1.0.7": "1.0.7", "npm:@chelonia/crypto@*": "1.0.1", - "npm:@chelonia/lib@*": "1.2.9_@sbp+sbp@2.4.1", "npm:@chelonia/lib@1.2.7": "1.2.7_@sbp+sbp@2.4.1", - "npm:@chelonia/lib@1.2.9": "1.2.9_@sbp+sbp@2.4.1", + "npm:@chelonia/lib@1.4.3": "1.4.3_@sbp+sbp@2.4.1", "npm:@chelonia/serdes@1.0.0": "1.0.0", "npm:@eslint/js@9.31.0": "9.31.0", "npm:@hono/node-server@*": "1.19.14_hono@4.12.12", @@ -207,7 +206,7 @@ "@apeleghq/multipart-parser", "@apeleghq/rfc8188@1.0.8", "@chelonia/crypto", - "@chelonia/serdes", + "@chelonia/serdes@1.0.0", "@sbp/okturtles.data@0.1.6_@sbp+sbp@2.4.1", "@sbp/okturtles.eventqueue@1.2.1_@sbp+sbp@2.4.1", "@sbp/okturtles.events@1.0.1_@sbp+sbp@2.4.1", @@ -217,13 +216,13 @@ "tweetnacl" ] }, - "@chelonia/lib@1.2.9_@sbp+sbp@2.4.1": { - "integrity": "sha512-vyr/4V0Jcr97S3873xJL0+pXE4kxIqwsSin84hdNaIpSoJ8hIjizHpznV2loe/eQmtq7uReTkezJcyhzjQ5JfA==", + "@chelonia/lib@1.4.3_@sbp+sbp@2.4.1": { + "integrity": "sha512-qfK+8t5XHoNdpVVfw7o4XdWd9Uar56yHKInhbbEwvyNAnjkLQ9OXi1H0l+YxVVC+02C/NoBKuqgG72tCCnwpog==", "dependencies": [ "@apeleghq/multipart-parser", "@apeleghq/rfc8188@1.0.8", "@chelonia/crypto", - "@chelonia/serdes", + "@chelonia/serdes@1.0.1", "@sbp/okturtles.data@0.1.7_@sbp+sbp@2.4.1", "@sbp/okturtles.eventqueue@1.2.1_@sbp+sbp@2.4.1", "@sbp/okturtles.events@1.0.1_@sbp+sbp@2.4.1", @@ -242,6 +241,9 @@ "@chelonia/serdes@1.0.0": { "integrity": "sha512-MkkwhuZ8pGPOpYiTse/u2sxUK1pVm97QtC8yPbwaYqhSc5W0SMI4VaKe+h/ERagNCwxXH7hntLFSpevEvQpJ/A==" }, + "@chelonia/serdes@1.0.1": { + "integrity": "sha512-YPZ/HWe6ThCoF3asIM4cBkDECzfL/VXDMCJZkuDacKmlPX+w1HqzDvilc6eY/+7PTI24HLOXlXi7n5026bCwJQ==" + }, "@dimforge/rapier3d-compat@0.12.0": { "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==" }, @@ -2804,7 +2806,7 @@ "jsr:@std/path@1.1.1", "jsr:@std/streams@1.0.10", "npm:@apeleghq/rfc8188@1.0.7", - "npm:@chelonia/lib@1.2.9", + "npm:@chelonia/lib@1.4.3", "npm:@chelonia/serdes@1.0.0", "npm:@eslint/js@9.31.0", "npm:@hono/node-server@1.19.14", diff --git a/scripts/build.ts b/scripts/build.ts index 74faad3..e4eaeca 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -19,6 +19,7 @@ const options: esbuild.BuildOptions = { 'import.meta.VERSION': JSON.stringify(version), 'import.meta.ownerSizeTotalWorker': '"./serve/ownerSizeTotalWorker.js"', 'import.meta.creditsWorker': '"./serve/creditsWorker.js"', + // Lock DB after init, preventing overwriting 'import.meta.initDbOnce': 'true' }, format: 'esm', diff --git a/src/main.ts b/src/main.ts index 31022c8..b4c42f0 100755 --- a/src/main.ts +++ b/src/main.ts @@ -1,10 +1,9 @@ #!/usr/bin/env -S deno run --allow-net --allow-read=. --allow-write=. --allow-sys --allow-env // Deno APIs: -// https://doc.deno.land/deno/stable -// https://doc.deno.land/deno~land/std/ +// https://docs.deno.com/api/deno/ +// https://docs.deno.com/runtime/reference/std/ // Deno examples: -// https://doc.deno.land/deno~land/std@0.141.0/examples // https://examples.deno.land/ // Third-party modules: // https://deno.land/x diff --git a/src/serve/routes.ts b/src/serve/routes.ts index bb6def7..64560df 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -531,7 +531,7 @@ export function registerRoutes (app: Hono): void { }) } - /* +/* // The following endpoint is disabled because name registrations are handled // through the `shelter-namespace-registration` header when registering a // new contract @@ -621,20 +621,21 @@ app.post('/name', async function (c) { try { console.log('FILE UPLOAD!') const formData = await c.req.parseBody({ all: true }) - const hash = formData['hash'] as string - const data = formData['data'] as string - if (!hash) throw new HTTPException(400, { message: 'missing hash' }) - if (!data) throw new HTTPException(400, { message: 'missing data' }) + const hash = formData['hash'] + const data = formData['data'] + if (!hash || typeof hash !== 'string') throw new HTTPException(400, { message: 'missing hash' }) + if (!data || Array.isArray(data)) throw new HTTPException(400, { message: 'missing data' }) const parsed = maybeParseCID(hash) if (!parsed) throw new HTTPException(400, { message: 'invalid hash' }) - const ourHash = createCID(data, parsed.code) + const dataStringOrBytes = typeof data === 'string' ? data : Buffer.from(await data.bytes()).toString() + const ourHash = createCID(dataStringOrBytes, parsed.code) if (ourHash !== hash) { console.error(`hash(${hash}) != ourHash(${ourHash})`) throw new HTTPException(400, { message: 'bad hash!' }) } - await sbp('chelonia.db/set', hash, data) + await sbp('chelonia.db/set', hash, dataStringOrBytes) return c.text('/file/' + hash) } catch (err) { if (err instanceof HTTPException) throw err From 2d78852a657ef7931ab8e75937892d085cf1512f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 02:05:52 +0000 Subject: [PATCH 52/71] DB init/close improvements --- build/main.js | 138 ++++++++++++++++++++---------------- deno.lock | 1 + scripts/build.ts | 2 +- src/serve.ts | 3 + src/serve/database.ts | 160 +++++++++++++++++++++++------------------- src/serve/routes.ts | 34 ++++----- 6 files changed, 185 insertions(+), 153 deletions(-) diff --git a/build/main.js b/build/main.js index ec9f0de..ae6608b 100644 --- a/build/main.js +++ b/build/main.js @@ -68871,10 +68871,16 @@ function installBaseSelectorsOnce() { } }); } -var initedDB = false; +var dbRefs = 0; +var setSelectors = false; +var preloaded = false; var initDB = async ({ skipDbPreloading } = {}) => { + console.error("@@@@initDB", dbRefs); + if (isClosing) { + throw new Error("Cannot init DB while closing is in progress"); + } installBaseSelectorsOnce(); - if (!initedDB) { + if (!dbRefs) { const backend = import_npm_nconf2.default.get("database:backend"); const persistence = backend || (production ? "fs" : void 0); const options2 = import_npm_nconf2.default.get("database:backendOptions"); @@ -68884,73 +68890,79 @@ var initDB = async ({ skipDbPreloading } = {}) => { const instance = new Ctor(options2[persistence]); await instance.init(); currentBackend = instance; - currentCache = new import_npm_lru_cache.default({ + const cache2 = new import_npm_lru_cache.default({ max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 }); + currentCache = cache2; const prefixes = Object.keys(prefixHandlers); - esm_default("sbp/selectors/overwrite", { - "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { - const cache2 = currentCache; - if (!bypassCache) { - const lookupValue = cache2.get(prefixableKey); - if (lookupValue !== void 0) { - return lookupValue; + if (!setSelectors && true) { + esm_default("sbp/selectors/overwrite", { + "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { + if (!bypassCache) { + const lookupValue = cache2.get(prefixableKey); + if (lookupValue !== void 0) { + return lookupValue; + } } - } - const [prefix, key] = parsePrefixableKey(prefixableKey); - let value = await currentBackend.readData(key); - if (value === void 0) { - return; - } - value = prefixHandlers[prefix](value); - cache2.set(prefixableKey, value); - return value; - }, - "chelonia.db/set": async function(key, value) { - if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - const existingValue = await currentBackend.readData(key); - if (existingValue !== void 0) { - throw new Error("Cannot set already set immutable key"); + const [prefix, key] = parsePrefixableKey(prefixableKey); + let value = await currentBackend.readData(key); + if (value === void 0) { + return; } + value = prefixHandlers[prefix](value); + cache2.set(prefixableKey, value); + return value; + }, + "chelonia.db/set": async function(key, value) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + const existingValue = await currentBackend.readData(key); + if (existingValue !== void 0) { + throw new Error("Cannot set already set immutable key"); + } + } + await currentBackend.writeData(key, value); + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/delete": async function(key) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + throw new Error("Cannot delete immutable key"); + } + await currentBackend.deleteData(key); + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/iterKeys": () => { + return currentBackend.iterKeys(); + }, + "chelonia.db/keyCount": () => { + return currentBackend.keyCount(); } - await currentBackend.writeData(key, value); - const cache2 = currentCache; - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/delete": async function(key) { - if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - throw new Error("Cannot delete immutable key"); - } - await currentBackend.deleteData(key); - const cache2 = currentCache; - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/iterKeys": () => { - return currentBackend.iterKeys(); - }, - "chelonia.db/keyCount": () => { - return currentBackend.keyCount(); - } - }); - } - initedDB = true; - if (true) { - esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + }); + esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + setSelectors = true; + } } + } else if (setSelectors && currentBackend) { + currentBackend.init(); } - if (skipDbPreloading || initedDB === "preloaded") return; + dbRefs++; + if (skipDbPreloading || preloaded) return; await Promise.all([initVapid(), initZkpp()]); - initedDB = "preloaded"; + preloaded = true; }; async function closeDB() { + console.error("@@@@closeDB", dbRefs); + if (dbRefs > 1) { + dbRefs--; + return; + } if (isClosing) return; isClosing = true; try { @@ -68960,12 +68972,13 @@ async function closeDB() { } catch (e2) { console.error(e2, "Error closing DB"); } - currentBackend = null; } currentCache?.clear(); - currentCache = null; + dbRefs = 0; if (false) { - initedDB = false; + preloaded = false; + currentCache = null; + currentBackend = null; } } finally { isClosing = false; @@ -75982,6 +75995,9 @@ async function serve(args) { try { await startApplicationServer(); } catch (error2) { + if (error2 instanceof Error) { + console.error("@@@@@", error2.name, error2.message, error2.stack); + } console.error(red("\u274C Failed to start application server:"), error2); throw error2; } diff --git a/deno.lock b/deno.lock index 2ed6be1..c387523 100644 --- a/deno.lock +++ b/deno.lock @@ -25,6 +25,7 @@ "npm:@apeleghq/rfc8188@*": "1.0.8", "npm:@apeleghq/rfc8188@1.0.7": "1.0.7", "npm:@chelonia/crypto@*": "1.0.1", + "npm:@chelonia/lib@*": "1.4.3_@sbp+sbp@2.4.1", "npm:@chelonia/lib@1.2.7": "1.2.7_@sbp+sbp@2.4.1", "npm:@chelonia/lib@1.4.3": "1.4.3_@sbp+sbp@2.4.1", "npm:@chelonia/serdes@1.0.0": "1.0.0", diff --git a/scripts/build.ts b/scripts/build.ts index e4eaeca..ae81034 100755 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -20,7 +20,7 @@ const options: esbuild.BuildOptions = { 'import.meta.ownerSizeTotalWorker': '"./serve/ownerSizeTotalWorker.js"', 'import.meta.creditsWorker': '"./serve/creditsWorker.js"', // Lock DB after init, preventing overwriting - 'import.meta.initDbOnce': 'true' + 'import.meta.lockDbSelectors': 'true' }, format: 'esm', platform: 'node', diff --git a/src/serve.ts b/src/serve.ts index 9bcf4ab..52dfa72 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -100,6 +100,9 @@ export async function serve (args: ArgumentsCamelCase) { try { await startApplicationServer() } catch (error) { + if (error instanceof Error) { + console.error('@@@@@', error.name, error.message, error.stack) + } console.error(colors.red('❌ Failed to start application server:'), error) throw error } diff --git a/src/serve/database.ts b/src/serve/database.ts index c8a23c5..279f92f 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -187,10 +187,15 @@ function installBaseSelectorsOnce () { export default installBaseSelectorsOnce -let initedDB: false | true | 'preloaded' = false +let dbRefs: number = 0 +let setSelectors = false +let preloaded = false export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } = {}) => { + if (isClosing) { + throw new Error('Cannot init DB while closing is in progress') + } installBaseSelectorsOnce() - if (!initedDB) { + if (!dbRefs) { // If persistence must be enabled: // - load and initialize the selected storage backend // - then overwrite 'chelonia.db/get' and '-set' to use it with an LRU cache @@ -207,82 +212,84 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean currentBackend = instance // https://github.com/isaacs/node-lru-cache#usage - currentCache = new LRU({ + const cache = new LRU({ max: nconf.get('database:lruNumItems') ?? 10000 }) + currentCache = cache const prefixes = Object.keys(prefixHandlers) - sbp('sbp/selectors/overwrite', { - 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { - const cache = currentCache! - if (!bypassCache) { - const lookupValue = cache.get(prefixableKey) - if (lookupValue !== undefined) { - return lookupValue + if (!setSelectors && (import.meta as ImportMeta).lockDbSelectors) { + sbp('sbp/selectors/overwrite', { + 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { + if (!bypassCache) { + const lookupValue = cache.get(prefixableKey) + if (lookupValue !== undefined) { + return lookupValue + } } - } - const [prefix, key] = parsePrefixableKey(prefixableKey) - let value = await currentBackend!.readData(key) - if (value === undefined) { - return - } - value = prefixHandlers[prefix](value) as string | Buffer - cache.set(prefixableKey, value) - return value - }, - 'chelonia.db/set': async function (key: string, value: Buffer | string): Promise { - if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') - checkKey(key) - if (key.startsWith('_private_immutable')) { - const existingValue = await currentBackend!.readData(key) - if (existingValue !== undefined) { - throw new Error('Cannot set already set immutable key') + const [prefix, key] = parsePrefixableKey(prefixableKey) + let value = await currentBackend!.readData(key) + if (value === undefined) { + return } + value = prefixHandlers[prefix](value) as string | Buffer + cache.set(prefixableKey, value) + return value + }, + 'chelonia.db/set': async function (key: string, value: Buffer | string): Promise { + if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') + checkKey(key) + if (key.startsWith('_private_immutable')) { + const existingValue = await currentBackend!.readData(key) + if (existingValue !== undefined) { + throw new Error('Cannot set already set immutable key') + } + } + await currentBackend!.writeData(key, value) + // `get` uses `prefixableKey` as key, which now that the value is updated + // is stale. We delete all prefixed key variants from the cache to + // avoid serving stale data. Note that because of prefixes, `cache.set` + // can't be (easily) used to set the key, as transformations could happen + // on the unprefixed version. + // Note: 2025-03-24: We benchmarked `.forEach`, `for of` and `for`. + // Which one was faster depended on the browser, with no clear overall + // winner, but `.forEach` was faster on Chrome, which uses the same + // engine as Node.JS (V8). + prefixes.forEach(prefix => { + cache.delete(prefix + key) + }) + }, + 'chelonia.db/delete': async function (key: string): Promise { + if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') + checkKey(key) + if (key.startsWith('_private_immutable')) { + throw new Error('Cannot delete immutable key') + } + await currentBackend!.deleteData(key) + // `get` uses `prefixableKey` as key, which now that the value is updated + // is stale. We delete all prefixed key variants from the cache to + // avoid serving stale data. + prefixes.forEach(prefix => { + cache.delete(prefix + key) + }) + }, + 'chelonia.db/iterKeys': () => { + return currentBackend!.iterKeys() + }, + 'chelonia.db/keyCount': () => { + return currentBackend!.keyCount() } - await currentBackend!.writeData(key, value) - // `get` uses `prefixableKey` as key, which now that the value is updated - // is stale. We delete all prefixed key variants from the cache to - // avoid serving stale data. Note that because of prefixes, `cache.set` - // can't be (easily) used to set the key, as transformations could happen - // on the unprefixed version. - // Note: 2025-03-24: We benchmarked `.forEach`, `for of` and `for`. - // Which one was faster depended on the browser, with no clear overall - // winner, but `.forEach` was faster on Chrome, which uses the same - // engine as Node.JS (V8). - const cache = currentCache! - prefixes.forEach(prefix => { - cache.delete(prefix + key) - }) - }, - 'chelonia.db/delete': async function (key: string): Promise { - if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') - checkKey(key) - if (key.startsWith('_private_immutable')) { - throw new Error('Cannot delete immutable key') - } - await currentBackend!.deleteData(key) - // `get` uses `prefixableKey` as key, which now that the value is updated - // is stale. We delete all prefixed key variants from the cache to - // avoid serving stale data. - const cache = currentCache! - prefixes.forEach(prefix => { - cache.delete(prefix + key) - }) - }, - 'chelonia.db/iterKeys': () => { - return currentBackend!.iterKeys() - }, - 'chelonia.db/keyCount': () => { - return currentBackend!.keyCount() - } - }) - } - initedDB = true - if ((import.meta as ImportMeta).initDbOnce) { - sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + }) + sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + setSelectors = true + } } + } else if ((import.meta as ImportMeta).lockDbSelectors && setSelectors && currentBackend) { + // Re-open DB + currentBackend!.init() } - if (skipDbPreloading || initedDB === 'preloaded') return + dbRefs++ + if (skipDbPreloading || preloaded) return /* // Preloading logic preserved for historical reasons. Preloading should no // longer be necessary, since `chel deploy` can be used for accomplishing @@ -336,10 +343,14 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } */ await Promise.all([initVapid(), initZkpp()]) - initedDB = 'preloaded' + preloaded = true } export async function closeDB (): Promise { + if (dbRefs > 1) { + dbRefs-- + return + } if (isClosing) return isClosing = true try { @@ -349,12 +360,13 @@ export async function closeDB (): Promise { } catch (e) { console.error(e, 'Error closing DB') } - currentBackend = null } currentCache?.clear() - currentCache = null - if (!(import.meta as ImportMeta).initDbOnce) { - initedDB = false + dbRefs = 0 + if (!(import.meta as ImportMeta).lockDbSelectors) { + preloaded = false + currentCache = null + currentBackend = null } } finally { isClosing = false diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 64560df..8fc9e94 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -531,23 +531,23 @@ export function registerRoutes (app: Hono): void { }) } -/* -// The following endpoint is disabled because name registrations are handled -// through the `shelter-namespace-registration` header when registering a -// new contract -app.post('/name', async function (c) { - try { - const { name, value } = await c.req.json() - if (!name || !value) throw new HTTPException(400) - if (value.startsWith('_private')) throw new HTTPException(422) - return c.json(await sbp('backend/db/registerName', name, value)) - } catch (err) { - if (err instanceof HTTPException) throw err - logger.error(err, 'POST /name', (err as Error).message) - throw err - } -}) -*/ + /* + // The following endpoint is disabled because name registrations are handled + // through the `shelter-namespace-registration` header when registering a + // new contract + app.post('/name', async function (c) { + try { + const { name, value } = await c.req.json() + if (!name || !value) throw new HTTPException(400) + if (value.startsWith('_private')) throw new HTTPException(422) + return c.json(await sbp('backend/db/registerName', name, value)) + } catch (err) { + if (err instanceof HTTPException) throw err + logger.error(err, 'POST /name', (err as Error).message) + throw err + } + }) + */ app.get('/name/:name', zValidator('param', z.object({ name: nameSchema }).strict()), From 725cf764273a9dfaa6a550f534727d11b183e26b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 02:55:54 +0000 Subject: [PATCH 53/71] DB improvements --- bin/chel | Bin 7900955 -> 0 bytes build/main.js | 209 ++++++++++++++++-------------- src/serve.ts | 7 +- src/serve/database.ts | 288 +++++++++++++++++++----------------------- 4 files changed, 244 insertions(+), 260 deletions(-) delete mode 100755 bin/chel diff --git a/bin/chel b/bin/chel deleted file mode 100755 index a7ae0be271dd78c835d4520f2ce219a6f5076b1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7900955 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

jAje-|Njh1>&#r z9?P?UM=!GR^16B+KaVUCe^cdI!TmhFhWmM>g-6e}{ciu4TYWlsezy4zUOmpdhev;B z9%w(_FW>I~UMhbGujE5`qWs75;ru&7{7Q8j!@X`3cyf-_XA1Xv=I}<_b9k%v7x3&k zR-Xktev)|!4;SVY-1obJhtIY68eYlQ@JRVRpO2T%!wup;rh0DSUe6ue>$!(}J;SrD z-oD>h+e3I-TE8NAc8>W7o<7Um^Lc*n*BJ4?P`@T{@7EOW?a$#$ZO`Gpjur6edDhMa z+}E)Zo+#e;_<^vF-zG z;eW5|lMem_T}Sos;d5->?BQPLK>y$CQ$OG8JfQ1*9l~41`+hu+*EvG`omJ-%-0M7s zSK3bC;ajbp6L=<1;r%~a{1l$O(L96K@)0$wP82@h(E zU&2GV*U9Ve$L|X9!TW8Vui^6-*gV<5{rK(R6TL3m!OJgRcHIA*YI=C1aoNMG^Q~Wj z@_GAP`2Zfg#o|MFDIdaPc?3`8BX};4;kA4WZ{-QRmwTPOUp_7=;?K~yWN;ss9PZu!;hJ_@ZjC%TX-k$;JthY zPcF1PJv^1~;h8*8KYYA$x%bcA$1z0wvsIr6?)8n~K8^|8^H1P!QT{31^UvU(zksKj zCkuF@aVg=od7Vh=!;JN1K4qnT9c-mOM z_HgfSpt|}z@%|3r-ro@J{T;%+zY*N~>&LzC*U!H(;=iK#Glu&-@#|2}g+}jz!zoR@c+}oMJy`4Tj-X3q~6!E8i(AKvM?(NLs3td0Y;qmu0f8dRL0dK!) z@g=;tV;Hf->=kg)Elt=Jd9>cxAV|aF{^*4cc@(DcDJek5fZD;WO2bO;ZFXcJB z-dViA&hWbVdA~sXO2>uw&*S|#EfN18im%{)KCR(?9oxV|y`S2`{dn)--ku%&xQpz# z-ow2;gBRNQ(EH{2BY2|i5xh~IV|emItMeG%$UUF$*V{iq{LR(=DcrByW^iwR0pDqR z0WVIp_d!Z{cXRV4y#0ywtAgi0HDAG7c?~Zwv-mYUlQ-~OzJV9=7T(CW@K)ZzJGs}1 z7Bs-{0_fKki0|AAQvFkKqe#CvgA#zyw}TY#dW~e0%dL zJh_8;22bTPcqY%`xqJ>UgXm#7cW5w^`zTZIm_x=WdYn*;5=kgUiKG)*Cy{y|B@%Q+c9giEh*Jlg& zdU|`AzeoJjls{M=J|B7h5bpUS`1|!f#R&ddeZC@wH~QSm7=B%So*{u>;okPWvlQOE z#M(WDN8hzNXYg1)gIBlyql5d&IXwBk<(b1hzJRAcwD<))+MAc~;3wuwxaY6n`K1=W zf`{@N?s?YmQt=HumT%zwk8Qs#yjJ`cp2|CTE8oHEA6Wh#9;lvsxc4j2`1?FBRL=pt zlZWv1GTZMEp2;J4_c?ptVFWLOUpe?(M-2bv#|9643=b}6p1@Q21YXHgcqgC2%i}D6 z25;mucy^-2=kQ!Uheyh@fUmS&!V?{LOL#7?;QoHA=kxLP*U>fNFKKO^T*HSaoP7NM zyie4?JyuV3dK7dD0HV@(9 zQ_P3(>@4#L{>$_S^K%5x&ars!pSQ>BHb(pnRJR149&hze;lqE>x(yG1ZgtDxk$eVE zpJVOJ>CZKv!-LYifR}$`zJNFKlKvozU&528n^*AY(dH|7{222Z-pJSRO5@eQyJuRS z4ZKl&3$Gt#@mqNKSo03vD$fqyD87fM3(K>I=kh?~@AImZ58%}^EKdjzpJndz$n*I8 zj1YeZ&Cd}$y}ZrOF}%=r0#C1I$IApBon)TEeI1*^GsS1{NZh3s9?GS$KIvMWm8Nq+9{9|~j?F3%@p4DLjZ{;aG`dy2k z!sADnXYlGw^BKIC=kVxJ7C(pgk2Ejff#MhNPVwGvud^T5OT@?jZsS@cL}D9m2yKTl^57 zDSrg_c`|~xceFe)Je-)1;j!jhLRWkW4_=|`0l2q6gBNQ54DRjE;nlsYopX4fnHTWn zKIRK}dSCMr?(4=9{%p<96+F;=<~2OhcyHjIzlAr--@$zy?CH0)I(xl+{&@a@#=-rY z%0GmA{t;dI6L_KR3A}!o)iZ_X4>zB}eS9-`@YfbUgBQx5!+n0v;icley*ZCdX*ZCgq>--+>>wKW~)$8Ny`~dFj zdAP4-1|F%H|lQ;_wgOW zy}t?E`#XVqe^a=R?-bsvUl}}juGK$>ck1sP?)@#`!3!+U0`C1S;ojdR-1}R>y}v8C z_qT@E>em|H$~W-6`rE?2zgxQc+rhoRJGl3^hkJkbaPM#M>cjKa`#XT=rPV)#7xD-m zzSi=N;NIUDUZ}rgcyx~KH-US9Cvfj?3itj_;ojd29&5idcp{&}N9u0@_x>*6jrv={ zeSDX2?{5Y7{;uHO-x}`yUBg@TtATg&7M`fTTe{9i9Xycl;NIUJ?)}}vy}yBuCtq*9 zzXQ1UH-s0@vw1aym+}#Os{Y1sAKx)NSAP?@_jdyK{-$v6?-cI+&EVeO8C~a#9G=PN zaKD}@;J>HqnG){TGZkIeGd0|=&)4w#Dt`m__HE#vr-h%bJX^Tu>ENDc2Y;LL^l;C! zhkKqt^Tp?9r#u6==kfK@<2}z1@t6O!T~9`E&*SS5^Tde1k@Ae;p2v@G=9wV=|5u(A z?s@#UVV(@}Pf(s2-1E%g!`IpQrGWeWq6NHqu^sOv+>gg4JX3rH&*dw4`Xb9;!wY!> zZ`J+{yi@)b9xg5a7Vhou;NJcn+}q#71MPPYkK}`M4__xtv>n2|{zG`8JQ3X6KZ1Mv zW4O0}46l8?g|~8Vug^nY-%`ZCPV+E>7uwF@exKj}zvuVkcY*j%Dt`$-wtm7pZLi>7 z=New9&TF{Wxq*9~H*l|W3-49WEj-jb_x5@nyv{qs2U}am_V8nM)bZhYyv}~yyLkqFpV{H%N{=M=D9=^lY$r0S&hmGN};(b3}H$Q$8 z#D7%%n!x>g|6{w=(FgXQVq;d$me`twda_*_sAzu9NB zF2RpI$4_eL$}4!LJS%wcdzPn$r}73qSDp>LxsBy%;nDvw@8B!t z*})6N_wY&{yy@`uK%+bZc>0I7-wM)}^a!3PPYn0h(PMa|*U@65h&}@J_yhdpm1*uKljz zjl6;Tan!=Yf3kVAh4*St2ao^Q`n7|5{vPi0WDk$;WO)Lgr*_&83gsWbeV&ByU%q~} z*KzPr`6IZ`lM&qKiLYB+hsTWnvaQ1j+`qTw>n`)8h`+J&OyT~zAcOmPVFtgw^5k&8 zKRJhco&tUk6{|P+$6FcrEa6f)ic&7L% zypm_|>~zaNg9mpu&*8D$`@#AYh@bwK9d`?OscrwuJWIqsOL;1|f8VEur{~)`xrRsg zw0<@4Oum8V>Te6L?qzwl@LG8~xPM=J2lwx5_i+Ed_MZMQ+iy@GzJAE{edhr@l!x%{ z!IozTFBKobWBCXkJjC+E@LKU>cq&iet$YIa?`x;@neBH9&mU=?!TtN%Gq`_WJBR!C zwde5Qv6jDpH%~WT!2SE$CEUNSy@dPswJW%PUwZ}j?`zj^|GxGb9zNOH*}(n#+8cPK zezovgzJ>euwL5ryZ`_dA!9Z@a}2m6Z+qq`+Da6_4Cmb@#C-9dYi%hd+9m+)UR6n9DbU- zfL~9(fRE%Q{3h}x{1);G{=4!OJdxM%JIL4YJIfpRpUJoI!9Ux2+QIA3S^anL{A=bt zyq53bjXZeE;dQ%^58(0FEq@5lcIHEP{!Q};?)UjeM|ccRzh!yGaL1Wyd-%I`z6f-D_&oRX#j(G-AL4mJ#D76~hH!tqIfAdW9m8`Sk7IZ(PvE82!wI~S zr|?$m#uV=JA%pvRID`9on8O1dk8^k|FW|l&F5so&OL!$;!fSa2_xa%U_VM*`tP%es zjpG_V&~^j&JRA5mzh>86E!^{T@J#E&4xVd$=;5_|PuIE{D4+M&&yNGRuMZ*I=fe>0 z^C5!!d>FwittTlM zJ|Fh*Qt^T64^FoH5xiIa7(UbX7+zn)@+9z9K7j{Ai%;Qxd`;m`-Rb@Y+}~gDc6og~PmcIE zD$gA5?eOtro(1ARr#vOxpW|1-8*Q)PvFcF6bNLz`$vq$2xk3E*)y@{~*Pk7Hu(tWU zgEtSf@#^70WWI+-@<92#ow3~awU^a#(6@YxZb!=oEm`{(dhUcfu~0^Z9@xVL|Kgjew3*R4G(cqy;pKE7-C z<2Akw+~?;8?s;1HWtZ7J*}{E&*uh8duzB9Yley+Iypjj{cRp`@o($m8Q!P&jFJEdt zga_xDNAN`M?e+b79b&}iKeIZF;ahD_;B#%K@cv!ao+&(dw|NHlI?Uja;&XT@_x-b9 z1>&Erel6hJciK2E;f=N{czU6=e+3WZHQf8PhDVC`{jmKT#J@)EZ{fYRw{Rcd4*t!b z+xYI_e!O@-wr7v{6MtcO0@cssJx>VlwLOG)Ki0g3_wo_k>lwp+T^+;Q%PfBa@8uJC z@H2}~;hB62_jNUc`?@-V`?{LLeO;ZyYwfpyck%^1{JFKigvas_Io>1#FuL46z=Vu!J~KEJjvnp z-&uR+@c8lO1-w7gd;xD1U&6D(;+OF7Eb|JUJjHwkZ=Y^n!#nvJ9xp7uffvs*-@qGr z3vZuf@msimPp5;&XIuOZ9z4gqhx_+*_VDB!iw`tzJ|A-V0Pf$@3E{cwIfN%qwER9V zJipJk5#leIa=vr@E_}4U!Tezy77WeB1x(eUnt<62hCcjmr@3^I-&EXgh}Y@3lN*c>F%|1fI($@Lrz6 z^Y>exDZG-;;PHF34#Tq#S)Mt(l^1ZYgZJC(?4O4$5#L_U&W{z`Umw+Q|DC~OEt>dho zBe?&rqK~t;$Jf;{;{Q;261X3aDSWQ&Dcry3lEH(EZC=gbK7Vp}q6TPvGOb*m0M_=h~jakFDGAZm)R`_jNCa z2S3(4hkN@A_-)kw1^n2$4d1@k`c=WR%WS_ZcrCB#KePBXypcEX_-ZzPHtc@a*R1LwGHZ;LR_r zo+Eg6Im;8nJJoXx4^OhXCGhIXmS+MFuVS9UTkUrWua2|$4Bjh#22YQ-_#ED!U_OUO zS1>Q&soKAQhgY)rlCC^Uc>8m!a|N$7A6D@C49j1`%UhYR;gRal!1LQ${083Kz`TWb zw>ICxeI4lFpVd0BgGYa8$NL^WexG@uzsKhJPpm!zcq|X$-CeAmLwNe9<`KNV{FM)m z-w`}j{uo}#y}jN}uS0_PAE^!#`1%9Z-zmJ%b_TD$dbNXg&fx7ITfcI+ujg}kuXx`N z+rL2kHLhUiqY}Qx`e$%&{|ufg-uL5m^W$ia_;;)Q1>DMER%iT<-1l{`x$eA^x_iLk{=#ynt8QUcg(Ok4ku< z_AKF*-1D)WE5tuc?X2N@ZF_r}r$KzDJR5k_*?PByd;SjY{oTPk)uD&?a?i(h1|K}U z-u_hW9KiiP_2vxXP)2A)0B z;y3V4`CEAUVvFCxlb4uxaDRVo2TxyZ@jX13@8SObTA*?E`I9`~@(keh+2%ekJl@x< zA>x;sZxP(zUyI@M57~Sh!xN2f0xw=`?U}%1#i#IQWARgX`62TR-koKyA7^mCzn9Z> ze{T-Y|JCvr@bF^u1-#XLzY<AL^cz{6YGa~(Hu zzrWYQ{r=t-p8vP?tAqRfy&c@|@AYuMzqg0`{k=f*%ja!-hP8hH_xpPx-0$xV;eLNF zf`=o^KZ0jBF^}P;d<>6nYVirYySe!Up8t+{3NPeScq7l?#Vst)3|`A~cqI4Z*z4@; zLxK2RXy>B^-0wFo;f=N{cyxPf=L#OnYq*~`*YGs8JiZ^ce}nkVN!I=r?)Muz_+Vq} z+YX+pojp90@8RD5K>3cf^RCu@-_J4E`+Xtezp3^Q;oklc{a>y9F+9JY?RN~%?r)yJ zt9zMG;DzE-c>4g0pTf(>n`dzUUcd}qzS`n*cMoEqeqz6@HRJJ!-GegH}Ljv%{TD$G3G72f2{cy-kfRP!Q;o7@8I>T%zJnz z-@|>~2tI7{&gb*}PqyQ30Qc`Hgz$TuV(~-xgXIzY(ee?zkjL;!K8Dxw6#hQ>6yC}+ zcrTy9gHx?v1>Ey5;GyD6_-XPb{D$%hehc{;UTb}5;Nd^oxNqQzyoJ|VAGUD+{8C3h zPxB4#pI_?X{`sXnyjGq-{qXtL$p>^j_b-I|=a(Y*M%yEJp*qCyT0VyN@&xY3%LLwE z-R4OO_v0ml`*ApfS6{O4TjlWX%~t<8+|N@5ynBPiFW|krglDS%5?;tFcqL!K6L}5y zx~<_?)N$9q{qtZOxaVo%H&mW2Jk|G$I=JWA!GB-JT@Ux?;q2j_C-}(W_4B^UGl2Vi z7{W7cNATvKZ5&7N-~#g)UMqeKPZgiQi?>;x3A~r5@M>-GQ+WDLbMJ>A*Iu6);{R6l z$>Cm~0-pVw)pr3;K4SYV;i-HH59Ad*m#^Udy!0Ago%)M|??tZR{=D=C?$1l#z?;)8 zPYZA5Tev?jy@UJn(syuwUV0Dr=cVuA{=D?yqlf2npyy)`;E_CpC-NaYlSlAEK7v>B z7#>~U>NbX_@&sOMd?#>!UU~}m=cP~K{=D=I?$1k~(fxV#aDQI<9PZCcFW~;X^ab3X zmtMmCdFe~IKQFz4`}5LQ@cN^6eAVzqTjU+#@8`_Uitv;&r1*C{=D=dyjA`P-pNPs^kS=j3~wJ{ z&to6M^V~dvr>f5c-l+a5ypvDinbsv=kG(#})_KHVdQH17%Hi#OY<(%<{<|Ivc;0HA zhgb3?{nmeUus&CC|6Q0B+`q?KAK`1b|1L}e_dJ^;ygkCVM|cPK--X%1eZM{2zi$#; ze0V*d`?mk}_m@9wbq?XFdxePjUq>YHN_i&mUY^4Jdk|B& zzmD*E_rK;d;+xYnpW*&Fhhug1dg{JVf%tz{o(0^mdzbL>$87v6cypQ6a|Q3@Yj~X1@I>z8`O z`Hud4i|^t23(WWMO7UJN)_+kjOc%N4h;;(W&%QJ%eyz+W5&lvI7 zQJw_uc~baZ+f#V@VyjOEujMnkKF5;7gQew}!&7+yZ{!PjCokc_ODz8q9?2_sB45EX zc?~b*Yk2-r+iwG}6u*Ht@)q97xA4BQ{2koq&klZDje8IG^V%Nnd4i80zOI-m&j9Z2 z7{X(1NAUV(*8UN^mHWT@U-KF9kMsEqKQ^D?E3JD|c>Zc@PXCoH~&=l^cr!3*Wt!JAK6d=Jm%dw3}yXua`uY^nSqJo~KWAHqv{1o!%k z;H~0gcqbpjqtDrX6L=$^z*~6=@8wf?_Ib;n!Q;++2G3qfJR#!$RC$JQe_ib74dxjkK3AR?UaH;4&JTECieco>2ejluZr^>T~2jA8_ho|yA-17&YJbb<3J~+a| zBRqo7RG$&t>l4F+ORW84c%}9y@I>(wcqLEa>31yu6rRa5cqN~~Yk3ZDP1m)5Djl z&mJEC*y02Ie_v-x`2gPh$l^nIulOOn_=&|w^q-oK;H5lzK%^1{{pRJ8Qfq0`fWF5%4w zuX^zQLIsa6GGD=i7ns-ZRPk$gEpOqz-!0tt+rfRmJGk$+hx>km?cw=0@@@ZnP^}>7 zu6?D0I)w1_H1i?cuX7@JsrY02QGQQlj2+V;Q9QzQQA%Cm<1^L94y{by|6 zwD9tJ)~_wRk#}&f^A7IMNA2Ok^)3G%p2!2W%lq5>mc3Uyd4)<{>;H}SRcyL|o zR|&7>OL!}<;E{X<&*e4T$7K!oacStvvwEOP;?cf*axa;Bm9M?VE z^8}wgyl#J5c?NKA#}J-qJA(W3c}DR3u{Mq|+>hTeyi~mJ$B##E{{->%$gZPOxUcgW ze4*_b+}oeS%O_g<=WuU-L07!*hwU#B|24IL3HSD|;LYc3{Azgqa%<-rUdS7`w|@h# z6yL&o`4%3%!uH$2gIAjG;FY|GC(5&jm-0aU_IkGR0o;$%5FS<5o*}%EM{qw*M{qw* z$MCJT6L|6}+wTOP%Tu_I%apG844%K*^3ULnJcqZhxA-}{d4qWY4_{-xfcvd zeOxMd`ew_&f>-hy?&GqC`?xf4UpF@J*>Bmp(ZYTG+`>Ii2Y;sW?BL#xJ$&>9JAQ-D zA6|!(3#<+UcrFj&K2L^lKhH++T6sqBP9DSi_gZ_#@Zuu#1RlQ4d;(9DCxzGYDZD!0 z@?`M(qvkVs@NechUB9m}hxk!hj;&M?Fm#@U$_1E9l(8Dd>lO9kGmn_ zzog?Xg8T97#~Jg)h(GRzwhoNp-j0N>&o@rszo9%S+@DL3!J{wQ@js*gQ1clc%ja;v z4__SNizB=|!k0&Qb%d{u@cIZ}AK}drzB$6%BYb;=cSrc{2=9;Z{Sh8$Jbk|9m)STD z;DtPd`#27daGx)p-;awC;=|vz`5eRjzG4C|wLO6+nr|sQl~3XE^G-at&y&HE!h8mg zo@}1O!>5?f;n`W{1-w^17x3&Hi}(JqZcD`fmg-i))8kJ*{(o*Y)$sX$+VQ)F=c-Qw zFXS6|`W$O#OMkBU79N!59lZP-^BugA_w)x@{2rb>-8@kLyl&B>%?I%KG3Ft>kq_bF z&+NE};N3GV&j=nXK8DwiviLDPe5`o_Pn2f@Zxo-x(}m@k!gF~BFXc0M^$g3C!^3Bp z`#kbG`*B?${?3}83wU~Yo1aVgM%xv<{}p>axsf$IlCR;Zyn*}k%6$LqSBv;Z zs9#&SKaXn%AL}_?J-k+X_VD<4>u;cc=k3Yl19&G7;oh$yJW;&2*Yo>0ju3ygug`G* zJcIX-c@o4|$}@p`JErjDOSWER@cIO+&kP=1!90ii_3a#9UD@Ibcqd=L!>d?)36JGV zcqgym$*)?T6}*<$@Ze;NU&BLr1CQhzcr0(>`Bg3d7M_OY9X!06`3|1Sdw6h?#qZ&% ze4ugm`7_ma2>0hk4&jOV6~TSnNATc8YflW1K49zH7@jEJ=cBjNkCzGJ8_n|+o?Ow^ zJ?|g$WQhN~^333af#sRQm)b7i{pr@<1w4q%OL%`xbI-?iR*0Y7$gba3aKC=5;a;~j ze5E`M-1D^XUfWxE^?$AX9lVzB;Emk#vA=u9tDV7@58n^*^)Q6z|7CGQc#v8(@+mx%XYf`&gZJ_r9zMYKJBP>e0-nkj@ZxTkr-Y|> zH($bwzc8=hsq(Dgx%OMbBjsPiE9Gh6>D2bSf%ozj?ytYLaDV;P!ArGs2e0LOc%}Ih z=&#T7T>TorD|ra_b#(|Y?_vFo;L$zJNAN^GhEKJfz*`-s6L=?2;pG`8AH2TveBNJQ ze=@}XhmPwRyvl98_2Za%=7|5M@)U4i9~N+LPYFNe#%2Z9eSamAr@heDi#4XYiH7>u{rX4&ZsObr?R@b_6dU zsd)?UG{~s1o2-|J120j=M-LOJA?cCfHQdTVrzd6_jbY(nZ2toBKT-Qj zxW5lr!Go__{a5hvbtfGhr!_o&iM4+X_x3k%|Gw1*o+?iZFXUUef8VNumn&=M4j#PJ z+S$YX`&N6nf8WaM!8#9AC->{##MXfje(dx1@U^x_@c3ia&KMrH=3}_mIf2KDpTHA& z3Qy%zc=B=EZw3#(Z9an+@*G}&*W%~!Mqa>s`2rq%&+?S;P`-pm@(O-z9fr?tYU5bL z{dix)Jx>Gwd*#`{y&YS4@HIQ`I=be=4j#&TxX*_@yipx|KR$20{R8daeWmt?a9=kf z`1o7a{t>+Rxs6v0@8x57E>GZ}yVySGIe|a?p7uG_6#mpx?enNp_`C0`&uzkA+1uwl zXYdog|2qet2+ZMkKhHj=I)|UDJO%s@Zf)@k_(?yo&&QVV>4&UeOZa(Dw)Rx;yWGn9 zwSs^DWA?e(8h-y*Sv}YA>C>z|4g5>5wEP?RnP0NcwYKn6)UPf4hNs(pJNP}nXXCYl zpLwo*PPm5;uV!`F!=HARjbre2n~y%9zpnNV;5Yc_?;ebA2>;Z*?eoJ!_|L9u9>L#p zb*tM5ex~MU41cuhHim!dS~l(p{H!P)!5^*m z=kOnDUd`bvpa1YX`uvBF7dGxC{5Lf&OZbg7e=7LBbiAzKZ&kl)_!V_rui?K^+I(x^ zcTxK{@W0aW(!&2-@mu(VRsRnDH>&dv{{Ac2@zujGlJDUk&^!!whv)yFYke5NZ|w6Q z9?OUDhpGJ${Lwm2NAOJRWDGw;`N!~uj^70Sbf5q5>)*zX_Z0q2U;p9PKiiIr41SsB z^9+8uwZ-S~CuqFp@IuF90l&NIzkpvbw&S{l|E=n|gnvlmTfvX}H(Qrh@ITNxP{Tj3 z^=%FRvb=%6UB}S|e&Rz_4ZsGS<9Xj~^b^Pw&7izyf{65ORhd)^7wcs0v z=YOL-1Nc8`y$az2)pH1cipD*HpRM^hg8#kZWB7elhcWzgo!1ihQ#7w8@Qc*16ncX&PO@?VXE^S{y^m~;9t0hwPyi;kjAlu|DMhZOZc^QT~Wa= zI@Q*J75uAjwRu>>TlIGhf5Q*$cx>R0{;6HRZQu`9`&;--YcAO62f1o;t@Mmbg4dL}I?K&rde^u+o2>wuC|KWGk ze#h_^DNh0~v>s02rPlcre*W05GpF$9D?WoiO7nRJe{^Z%p2JVn`Y@+ww%-E&QJt?B z@JFaVCH$kB&rA4=)cy*d>%6>ze?oa`_#?I7HT;#mUFSFOd+9o71Am#mKiI+_r+RMT z@BD$SCmsArir>NSqIuH8zd5(-qCI@A^J(zkhv)xX{T;yH?CU@Lzcmks@Hbsx$590T zgvNIS|E%gC!?%hb!|$&;C-C3YIxvBsulA?#Z|n8W6#knJwRJLszeMwD27j>5%Q^h& zKL6n#*7>M_=UOKh@P}xfEa9Q9&zJBgY8)&0-}(H9KS=eg;lHN#ui<~Ab~f;bs}39Z z6BNINr@9}~!IR&=%E5iq9lVhD@cs@KzlR5RG!L{Nf1TUQ2k>NK@gdyrqYmMf;v;w` zAJO&u0x{h0qx$_JZ>QgPN)Z1w-FKS6{r;QRm3gL!|B>=!aK9g$!%JTlmLxKcR!aQm^}Vblo@G!!Oh8@!-3MuahsI*?s!~ z{C58S3;YYZpAf;%)$8{W{5g8PJcfTy_a74Ymz944|E^xwPvOth>+1}Dy6)4?;Lq26 z@;Ur+mECtLj_?Ki1jR4m&(?i_>Ih%K&(!^gHT+z^4*;*!{tf)?x(~C3k941*gTKh{ zcfmiXJbUvsT`xyQm-9Jy@uhe{-z(apO z0)8!xV|Ikk;QybFi#hzws!subvc`7-f1Sp03BQt##|mEh{U!L7o?@RvSi^5Ww)@7- z5x#-{lh%zb{H^L&2ftMH-@z}^eeXT|M|%Gy`2OMf^CI}xCHWG*(0r@l zwc4|Se@e&u8h&lfs|Nla)p-LyO~>yReoNgq?%=)dpYP!3>iFHm@8j<)U3z%_{FmB4 zfZtW?%n*L%Q}q53{DvCG5&TlMa}0lr+L^$wqxED0e~I2dn!-I#29MRA8GNVn;~f5e zUw`1=@%aP)q4F%@A5xwQez}3Y-?4&!-RBSdMfw~?1HVA?a09=k`n!eyAH84D!M(pb z`295Qd${KbesFmH{D$W30RBVuYY4xNj*AHH^%=pxulkSSo+mlNC-9GGT&D0F`1uQd z{59--mKpp#TIc8Ri{%A8)bX-_-_YM5fggWsd;hwEU#9hc1^*+B`x<_x#<79FOy`RY ze4=%A3xAuA(+>VB<=MgSruOXNFVXrO{P6JnxxVJZ0N(06IE0^|<0yhZTh~h?_{(&i zHirAUn!tTsoxpFa@tVT@e38NZd@+NM)ZaP0)aOhJ_*-?Ivw*);>%$U${Nrq$so!}I5=YUcp{ za?Q6P{Eezx1i!aF*D-=;Ke5jPjN#s|1b)8qPvE8I=M?UFGPu`g2EVng2j+0kQ@}mX z0)8va!zFyBx>a!R*9!g^tut%*n{?bYNB9Q*09~JK;hv|1zftYn!Qbxl2Yy8z7s3AU z{Q11rnF0L6IxdFr*J>Oi_*tsM2wtn5V|e&uYexbvUSao7Ch+Q&<|#aXsreKhROT7H zQJxvRdzHoK@LE2HSFg7C0^V!C3%c@@^w(IPB|Lepc?D0;HDAFy#n8_N?I1r>#9TJeRNG-kt{DD1HO){o^O?*#se{Mz9o*Nw9`5Vj9`5U2@Uz3~u&;XqxL=PA z;idW&!J8{-y@e-NHjm-n{xRI!pTNES6S%iOg*V!724AWDGkA51wKIo@r<%{<-u?pa z?O(vX{UzMnzl4|C?+V_i{WUy3-P*Z^SMmn#?ccz?{Vm+vzlD4IJ9u;*Yflf~s{MO- z_L~+T=>Pli+sX%UZ+{5)_7CCS{s`{vAHma+wPy_PwVl9=n_2t>9^TwMg?sy_aBqJG z_x8`=-u@gOYrk{2uVV%Lnz>y!F5rIMSi(Ke68^i&Q^CC*E4b&W;dfP@HQe(waL==W zKSFt0xaZlzJx>QeTX}YH&(p&_&mR5;4D7*1tjgt(9j3_jY){nP-dmdniu__dGp34D9(}dw6-$08zTORYG(xZ*Y6{^=ZWD<)$`hzvKJLMBHeLgG^dQRfp@8OjsFJJlzGm)ah|tG~7Jis8L{3@@K#@d;h))dZeCUh^DY z$fxi|p23SJSe_X?d!l&`PyWt)PFMZ{o+|$Wp2@v_zApLrE)jocjY|dh`C7w+U$OOV z4R2NF1|H~lA~x{osn*{X?!POsh5PSHba4M&i5=X3SE7dp+V377%DsQA+d%zx&wM_^ z{kVwW{yhH?ywHAQcq1Rf{k)LSbzYdj{k)LE{k$-R`*|Uw>%1_7`|nERa6d21;eK8y z;C^0M!2P^X!u@w8mT*5WRB%5ptl)lLsNsHISi}9i(7^q7B{p#XU5OU%zbmnY`|nD0 zaQ|J29zN6hxraykeTqQ;-{);AAHYj_2v7BU7DIR~kKn=U?fIW0xPQ+*h6m5Kbzlt7 zp%_nbzlwmF?eRSR zJ3a$=uiw)N;gNnnXb6w>J4X@R&qpJ;pO0d=pO40HKOZIVLhYHr{dbOz^$*uqQ^bGG z=QBLex{$*gZO`Gg>QKOg=iB^T!21`Nm+(~aOL(sM3hs4V!M$!Z+|T1{xSz+pe?Cuq z-fj?orAOIyatrsmZQ-7$gWpJbc5t8nd-(7KyN(L<*V`Gq(CRsWhw>2a_jNs==kaz% zh@YsPBe=J7OxJb-_vdL(;ML07pTfPJQ+T8J4DRip!85f#hbMY{UeNV>A`5tSzUD2w zk}u)j{tE8v=jsTrkMQ*o-W=hZBfLGrw?}w)gzt{<{s`Y6;lUMj|3mAQ*Jp5qhe!DE z2#=2N5!~lb41cQT&lv9We*!PGox=ThcBb%lWAiG5`}~=~v-eqi4o~EBcrEvK@pxY# z{&nha3HN#};a;~2{_o1Of_t7dyw`RE_quK1z3SG&y>450r#f`-W4CPtCeZDQ>t+p$;*KGxlRks@Mbz8%$i>wX} zJou3L2A;^hUF`1`@o!OoJGj@YhmUk#+rz!Tf&RbmH&uTJaPMzOSNn(XNXKaePvzb& z->=V;81bF@JBIsl;lBgMJQKwK>SOHqO5whqXYjPJ_!+#E=k&8Jehx26^8!BlNAngQ zJ><>@XT&Xh^IY@jN{7#zVRV;+_z^s~lldH;UD^J90dEFZJ$UZK0v=w`yoCFFSkh0l z_zK?3SMcPj7GJ|N`5K;t7T>_btC?@$jl6}2LyOYVjdFx`z1>Udc!Bxwd1tuLEOvs(vMKANL77KFQjX!u@vur|?|yJ|Ddf zz7EU~KZySHV4ml2KmNUc%u^u#*Og}hA837C!sl190BOkycwLgT%zisUt!c)aZ z@JjI`c&Ydpp5DmvkKwiA6L_ci2|QB2Qh2ZWPvNQJGkA6rYtIZ`$#ZygGmH26=ymqv zr9k}Me4fM0U$yzXJi;q@q5ZDlt-OZ&>$vq1-W=hZBfLGrw?}w)gzt{<9-iFX>b!@0 zzXH|I>z^xr0QdOt2p=Bd(Gfm6!s8=+e1s=Q_~ZyrkMQXco*m({BRoIC=kR0m96tAX z4)^Q267G4H@Ruo11^0HW;Z<()q=7f`4Lo>(#kcVAO!F<3x!gJY)bH8z zc?$SQ&*v%Ozpv*cRPbvlPYwT9eP6hN|E9j@-oo!x>GzM|r|CH-J^V&$XK>ZS^?&KT ztUe+91dU?^zw4#;+?5#q>$kG@B=F07{o$|Belz%O^_;65{u0fT0{+#%viVTLKll;* z9fS)02#s$If0Vp|Ur*!J!tbZ&RCMrfs69RWVvTPQ9dR|-v|1-^>82&097YY2Os#^-blGe8j{w9rY4nJ9SE8q{%JTKwr>-eqU zy~e$U-%b5$;IY>27M^+i;Xm{G!yk7mJI@9uAFlsd_q25~g#Wer6~UjT_!xe^>XyJS zRew|X-E|(%;D4!kn8V+rSRRl`4{>wyOTFx8=j@71pk{x>?0 z^zgrXs;%e2)eqPIw{+eN;l0+S2>vAHiQ)HB-4gg^UVr#sYQAOg3p8(Y_`MWgz@MS{ zP{MDlepT=Uy<=-%igps^Dj7Tx$4JbX+&^+o?S*{KsB@_|tvG!Vvxvt)CJ6 z7CIlr@GI&#P2dmIyiMVM?dw1MCYoBf`3@AYhw6&{rn3b>UnD^{MDMz8T@CO zS2_H?I=>X~`|CQSgg?#e55J}QTf^V1{x=0hll?97ydxiGlNex&vW>#Rks3ub>%PNC+hmPf}f*xvW7oR z>rw;%SDhDH_?uL>4t|o~|ABv8;}~4)aQ%N*;}XIzcMp4AAHiRzc^ku@>*rti!?ez% z@UQy$7k+u2A9MH%Rks2@^4DMRi&eJ@exBN2!-pEj27a2ng}+6|O9y|s*6kjCBegTQ z_Tl>fzSkfANsU(ozn$V^`15sKB=9$@zbX8|KL6n_QJr)6|MB?`KU?ce2|v~6Km1J1 zhZ=q@#W(Oz`22@|Q0r|6zk}-2!!NJ%Y;fA)`rpax4}Y7l|L}WgeTd=b`|Dr$OzU$B zzf`X;GWe_f{sVlk_yYd0%k1@j34f>BU%}t2>$e(y2VLhh@DD1!g@0Jy!QZ0!*2C|l z{K2msu79R_hVX&LD}p~%^^D<{sXht(#X2rhc%a{L$l&+)^&kEWtJv{dH=k&w%|2K_e2>-Y|g8!vjVF ztoob6zv1gY{O;Ga`y@I1D#~BLPuIFp!XKjRy$b$tt$Q{6*mM5j*U@!F3y*YO=-|)y z>wox*<-v6h*Z;#>$3l3nc^<(Zr+E^?Kcn+S0>7u~nZo}~`_15=)bo3D_@C=OVFAB| zpMT*G_4yBfrRHZ1zrO0+z+a*JmM#44Ki2y%@YneKhd)7e3!=mIzf9MwAw1N4i{RJO ze2d|~Ay43M(D9qXzwPrM{t-QAJBNQ#$72CMTkBE@zq;CA!H4o1egnV$fxlk$Y~f$f zeCy!1Jl)2nhu={339oy&{^@h<{mmh~eXe-~@8u(SevZYb@Zz7%r|?pq!7KUf2+!fQ z;^#+rafFxfMtPR-R^Grn`39c7!}{C8y9>>?@Zde>9Xyop;K{#Od=Kv$^Wb`i$G3d1 z`2b$aL-@7z9Pc6g_If^l1b?~i1B~FO>2-Gu|A0S-8GaqT&yv8Ot=|Ee!2d$)VG4hO zo_jxq-%SqZ5 zndU_oemBoI_+iSQ9{klhuRi=Rtz!fDSGE4c@QJU7@INVk68MRlUnBS%)lLfklCOvG zw`kqY;9ph#OyKv>_~-ENYdx95@2&U({$$-3X7IhW&Xn+9=z7iJdum=(@LMYn7w}8< zcM59w3zR=g_~nXk;J4CoSMVzozlJ|r`LKZ>ArJ1no&Wo&{TBSu%ELDNJ=))P;74kl zL-?=N&o2CS8vh9XD~*2-{spZMefZ7vcX$)#b;a6&$3;4;(w;4Rw{4L>6RG!S?FHt)cJkj4h zS->yw=S2AB{`Y9$U-k7LewEH^1;4GY|M1&spSgkG-T%(WUAFW8``U-J;CECzZTRgq zUpnx}*MIo8wXf^Kf3LiX;Fl^7d+^hJ{fGZZ{U5-;sXU3{Q(yn#chr1L;7?XQjNljP zdZq9ybbZJ0Bh^j@|FiE~;9vLrhrdVtpTaLze+u|Ty1&fePu4sw;b&=oGKc>`*Q2e;W8vT31)_@@hTT!~ae9>ka%|oma5$cK+W*`?MDP*Sd~v z__NiY4!qEH3E?kNf4cAwDn5e0TKlvf{0fb8AAY2+;{g6^#mDgdb-qLRrJ6?x{F}%$m+x!TX*7wbMXf%lXTIsEUMFH`u@T89hxf2#j8_`X`-O89rwpE>;d z@(O;G#(zQAe6Qj6*Lf}Bm#Ci&{5zW0EBKGppEdkSg zj^I})pHuiu^Lh;buI_^w{9zOOTzdllqK=!xKcUa9rtqtD-3$1BnvXO1;o5hV@Po8I z&*3A@uL^#(_9qMY$21N#eBk*He}%4l13%W+fA}Hl=NkShK5Cc=q52X&&|A2k80^;6G9OG5jj^X9&Mq zp1`lKaT~$krsvrd{#fPJ7=Ee7ErY*S*J}d*Pwn4w_^&nZrtsr^{fGa|*MImgO^&kFQwG-^Wo&WdS z)86y6;3sI_wc$5ZK6Kzu&~*>tua9lsb>X|6WuL1?@O`xp@4;`X~e*)jb^B?|h&wu!XG@fJlHJV=;{1WB)1ip{XD~JC<{hz`&hv@IC!Vl59 zF@xXL_doDIsr@-TR-RYzKP!F#e~s4j8va1v|HJ>T`O?6T)qZ0Ie}mSIHT)#aiw*qy z+D8R<-Om4qc>cqGsO!>(-$Bpa9ry|AX9$0x@~{hku*M;R-&5;(5B?MNrw>0t_pbr` z#h(B0=c}JX_~U*51HXszWCVYj=1U5HpXS9F{z4r$gMV53oC$oW{^amS=z2}zKhyXW z@Rw;EX7IcE`%n18eg6ahfX=Iezf$cl;HS!K_`NlrOZerwKQ{2YDBo7_>;By4`x<_G zts5KomAY>RciYbYUufJ~@V{$bx8a9rd^+&g>wH7_br-h3?ZQ9l&%f}wya&I&&bJSL zqxNY7crK6O_t148!oQ|GOyIB6IyQno(4T+dpI86K@TV%DGk7AOz%SQ6A%~B(zD?n$ z>wF9Ny>-4b_z(0vQo`@6_&NMn%99HIV2#59exTN|8a`D&m+)_B{2O?s@m#^*tbAL; zkJfl@;4js<1qW>B|H0~K3;tK#uiNm`bleX73eDdTzL)k7UHBPlCxXAppMT-IYroWo zU!go1!2ha!U=07QuHz7XXRR9v{H>n<@EdAArtsZ9Y~TMJ!ym3Z$>7)5`Y?eXruZDb zzt+Pk{4LrK6!1r@of-T+%EJ==YhA}Vd_Rp(1%HO_gA4dgH9j@`*S`OU@2xy(;CrZ@ z75rH`?izl8umA8D>;41dJ|B?1l9eAPf4B_umo_FET*S;l!-%$C` zgCC*m*oR-J^AFu1%f`420qc%KMd<#vy{g+VdYik@w-dJ>7nA>Hp zq5~*8MJn-(LNkz#ruMANV!u{}lctUB?3cSM5(`@ayaPmhj!qwtdtbewo(Q3jRRN zy9IoAwNt~trEy-uAEWVX;P=#ieg%Kx!|eOOYxslJpAGyM&X^&fr%{~#`0aGu6n>zt*BJg||NIwzxb8a>_`zx?hhL_4rtr;q_PcEb{3)6jGx&+xkCpJB zE6?ZfbG6P_@KBDa)I5#gQ{_Vs{xDtl zKKyw)-vRsu@)-U|wKIg5S|1YlbJWif{I42^6#gFde+>Vg@;QS)&G$d>tM6y?I*0G2 zc{+u^U(aO){K@|Q2fo|u?0YFCyiot=@O$X`R`3rhegXfb_E9zbHJUF=_>t;o1AnvD zs}=nAn(u4)hcpfw`0hI2;GpgNKT5}K!I!#TZTKTKFFNpJ^?7j!KTYdQ7yfBq|KU^J zFM9C9b=*Gum%3jJ;Gb3dG5j~WE<^a-%jx<{4`y!4DR3CnZW(~S2^6T z%M|`tjY9$dsIL1A?)%ab{!?AwIsB7a2Wt3xbX}J4%R_q(ZQx!Pxq^FL8XCyKt|IjNmh0x8YrRAMSOL1Gv{k#&EBT z9KyXWGJ${oDEqu%1b?>XdkXiu$T8gOA~X2)G`}WruZzs#UKcrqdtGD!_qxa#-0LDs zxYtF_;a(S6!M!eW0r$Gd8vY^u9>@~zb&(C+>mpZhuZvv6&(ONDfqPwK(A&;`uZwKK zAE13#8-8=mmk#_1T2Df_*F|>WUKbg`y)Lo`KT>(phkIS*0Pb~>G2H7Shw!uXefR|K zb&(^u*F~mquZtYRy)H6?dtKxN?sbtl{15v5s43j*A`7_JMb6+}7g@rep?%aG?sbtB z-0LD2aIcH3;a(THgnM0N1NXYf6}-`XXAK|fef|diMdeR$@OJ)tU1SUHb&+lOIls2w zG3da(E;59BU1S&Tb&(PLM16m?2lu+jKHTdf2XL>8jNx7vIfQ#%WCHiP$Ps*h{T@yV z_qxb2-0LDUxYtEa;9eJ*!@VwY3LpA@2JUr{Gq~49mhijk`Ed^Sy2uLdb&(6W*G1NF zuZvv5y)LqWdtKxT?sbuCxYtE);9eIQ9I~DNUKiPdzx?)g-*3acF0upny2ucIw)QPu zxYtES@DufYxgOl>BKvT!iyXj@)AMEwznR{{58K+xzwj-0LE9xYtEa;a(S6z`ZVV2KTzi67F@8bGX+}f3J&d!B2mk{(b@6>moaFuZs-fUKiPgdtGD% zKT*#YJ-F9J_TfLcwS5jXfO}nJ3_nNDcSHC-`W!HUdtKxRevmm#I!}U4l41R#_UnSh@BIj_gi>%;}(R;ZC`~vMaYPi=$F5%bB z?fb3`-0LD&aIcG8!v|V#H*l|u4DP?3|6Ui_f_q(L8}43H^ zIo#_ar*N-}EZ|-jIfHv$WC{1W$T{5WA}hGpMK0i87g@umqw_uZ!%% zy)JS9_qxa!ex~wj2!F2UKiumgM{uu;OyOtfJ?$8t==(Dn-0LDI@QL?sbtfxYtFNaR0ryIsBbEuL^#y*4qXA?s|@>;qTPGWeNAX$Oi6pkt=wq`}i7u z$2Zw~)D3($|J}a_Zs-5W`h2Ga_qxb7Jk#@O2kv!|A>8XCyKt|IjNo1u*@JssWFP)Q z-Dd}IuZxV~{yTm{_}BG&fC=2|B1dqqi%j8O7deJ|U1SFLy2uIK>mqZw*F{d@UKd%w zy)JSF_qxau?sbuKxYtEi@Rw=)7w{AG{8hufE^-O?y2u9Zb&)IhsXFc&?sbtHcvtIu z@SyGd_qxay{EJ#=+VDfQPwv3IE;5AQ!oRl$_qxak{`05X^I#9|b&-AezdX-Ae;mM{ zuKvexuZtYQy)H6=dtKxR?sbtVe1F}4$8fKU%-~)ZIe~j!WDfVb$SK_GA`AF`>p5ix z_qxau?sbuKxYtEi@DJ&Jx`2CKWDWPa$R+$j{XNPCexl~l3hs50Yxo!R9(x0SkM27` ze>?xZF0uuGv*uSD?sbtJxYtF7@N4!_-7ehgA|trhMfTury&veqf1&rl1Na&0e+>7! z$RXV8A``gRMULQe?cY-PvHE_?818kE8Qkk4CvdNe%;9J2`FaZXy2t{4keEZ*Yq-}%F5$1zJZ<1!7rBCaUE~_>b&(sm*F^@0Zs)((MYiBx z7ukk;U1SIDb&(<5>ms{wuZxV}UKiPedtGE7?sbs^xYtF-aIcFT!o4msf$yPtH-dXz zWD57X$T8gOA~X1#^u34){5{%l=Wwr!oWi{>vVePCN*Aw-p+roi)_KYF0u{xy2uXP z>mozA*F|>WUKbg`pRM!l!M!fB5BIvr0o>~%WBB`Y9~{EHE;508UE~Pvb&)CjIjWZ* z!~g2vTZVgG4={qC^k=JYO5w-o zdqHEk*F|PxYtF_;9eJ5!auBi;~egFkrmwQA{TJ4i>%>Z z7rBIcU1S6Iy2usW>mt|iTOMlPciq5GdbrKs;Gx_3?{$$axYtFt;a(TnfqPwK2=}_k zF8mm+^AY^CpW5?m4}K$kuGfcqUE~1nb&)aL>mrA6uZv9JUKcrndtGD-_qxb2{Eqsb zX9j<^z9&C{``?ww;a(Rxg?n9O0r$Gd8T@#Se+l=x$T{5WA}hGpMK0i-VB7xYtE4;BQlW4L>Qj`{okvb&(C+>mpb1 zC+I%DhI?J)2JUr{!Na%n-|HemoPslk^@nc*J)8&-HhmTJX>5{azdHb&(yo*F}c#bM?Ni3-`Ln2<~-}J-F9J z_TgR^Ie>dzWDNJZ$RYef-~YqEbUXVzVg&cP$Q15%kz=^mMP~4GK4tra3Eb--l94_qxam?sbt1xYtG2@O!_}_Tfvo*F`q)tMr~~1^2qh zHQehWH*l|u3moaFuZs-f{`UmC@U`~a5!~w{dvLFd?89%W=i&j}>mp;g z*F_HDUKg3by)JSD_qxawew^+jWB3WG>&)O@7de4@U1SdTy2t|Ve_wJ2_rEV$!u{_{ z&f)&|B`f&DwazTyk)Bg(xYtE4;rna-U&Di=ZT@cHd+GZF!C~8ZdyL*2wBR#+e$j^i zLHX8!|5BfyhVXs$y`V1qLcJf0;9t~!sR#dzo^$)~ciqYM6$AJu^7*7FJc1^RpFIlQlWx+(lFdM{MKkJbB-8T`HK ze+j>pKHr(cPf$A*{7iigvVi|Z-$SV3$LcyR;rr;g4g6*Py#@I5)t@!|cki|5nhpFc zeGU>lYCHe`qweUR-(8<`b>Pp{eI$gxeNTHX>%vb}KO^|ll~+CZ zGv$5wEq&ht|C-kG7`~szZ3r(le-rqv)&2;+(REMZm%iNg|6};|w2#f;pI3fP;74hF z$l)hyoTu>n>UtIM%JU!o7ysS@{PnsnbNIb<-7EONsXq(&CpDfm{Ck@3OZfR(R~z{K zbY3g?H*|g1@N+d^Ht=uiJ{}yto&N_YA6oFG`q_q`taYgazpe5lg#TIds|){vzqg0~ zRLAYX8+jl8B8~q5eouXGJci#v{T#wSr04epexdSb1V2#ir||z$KgaL~>G>;zuM|Il zf7HLX1AmCxnZjfL-ah>CUbh9mm)64){$|gA_&t>;6?~}n7x2I9y4UarDW8|{+v&d0 zz%Njqtl($qzPyGnbiFq47wi5KJbF9-U!r_&!Ozk7x8VnB96Ioa=)6MsL0UJu@Kbd^ zjo|;OdD?@&O#Sb}pP+rq0Di8IhUJq+QO zD4)CVM`_$5_*;oWmcb>pq1)K;vJ)U#|6S1`m$3&znkkr97F#U!`^`_<33< z7w{8wzBT+%^>Yb7L)WW;uQlIS@SEtmtlTJpbYUr0ddye_Q*#KKx&l&ja{{x{fjYUFzo${$6bhiP6k@F(fGEBG_CZm;2I>N;-Vuhskw9=o0Y7c0+O@EhrR zwc%%|{~h>u)J_P0m*#aBeu&n$2>vbY-+J)R>VDLRKS$5S1NetE4l(@kzW&1x_w^tC zX@CC%f0xD~g?~!x;TV2|@-TxB)t?Fc`kF^M{EwO!Q~2|>-WKpDdj7-TtLsw2|4;4D z;cewZ1%IUSb^-sa#;t~*rR%bU|4qkT!OvCv8vay`+XjBP`V$3%`ZNErP%4zV-{ZD+zGHaD*K>H{`3%3g?$4@^cOUqUO;Cem&)3@VM+5_trSa@V~47L-_aA z{{;R*t&=18sd`_L!q39TJbsjnV$dfqcndD_;I@5&EQ|xc$V;m z@8{v~J=H!ptl*#V{XF~x9k+&`rg^c1@2&Nrfj>iezJeEeZ?J~HUF~n+KhZb`kKfM! zq1M9|{3|{CT(}Ltf#y*Mewp$%gdeT`cj4dEI7jd&YaQ#sU!*+j!=Ix558$WlVb8@e z{2RLNL-?Uu_Y(L|G`~jh6Lo!4_(}3H{Oei=GWdJ7FPgw_>+3)KnYv$0;m`8?hhL`a zK7&6`--9aQ*ZE(2k2HsO^*bIF{Bm9Q1zpFj;osJEU&5cI{dohQDxX*I|5E#F_$B^6 z6F$=T1W(w`|8w@T=lT}>-8ya?{xs!h2Ywgr6GHfY@-F=Sy6zGDI~t!J{0BO(KK!Mc z7X$d`wJyc*BYpn^|CPowfqzNujNs2uJ1P9V8n-e00^OH0_+^@36ZlB^ki(CYPvMuV zodW(NjoS=IH`H@h2mWI9GlV}|_vq{9<_wzlr)kgx^;8-vnN(oe}&)+OMYY4|@K?Z}0nm_>;8HoWO6S`)m&X zp4Nvc{1}aM0l$-uJA=>sc@}l^T!6S`B3ctDH$MAbAK7-%qYWx1x z1b&d>bNI`3znj9J=lKsmPx(26U#W2};U`~YzY{ozKUwp%f`7!A8~be~$n z=ejNp{7$-0t>BsF*BbsSt>+u~_dj6g6%4oYzt(!&fF;Xl;66vEHa z_;le<(|AVkPwIO0;3sOn^x?;-p9A;}HQ!_SclADD2)~KuQ36l2-y6Yytn*FbH&Z)f z_^))`GkD_bKl~hxTMmDv=Rf>GBfGu@{Oh`J&fq`QzNm!XLj9k^FVTIlg5Tv}TTd47 zOO#hN{AlePm+;>xZyWewU$OOJ1;3f@<7@ag{QVF7XFA{DU$^uB%i7AlJd3-|Ei7~!B19v5B^-;kNWVA=F0$nsq!<1U##&N!hf#uN#L>WBO~}T zmA5JU7P>BD_*JSG&fuAzLnrXH*5@34s`jN*_z#qC1^h?)o$49<2g>IX{u<4%IXu$! zt>Ax9KNs*5wU4Ud$9n$5CpvBeKSArp3jS059_AW;Z}oEn-&6PH;K|$h{{|hm1;2^b z&o=yV%7+g8Ka__dyip!@;otS&+lTM1JnX|Cs`)a2|GVCU#qirHPlj;6UnKBHD1S!q z^He{Q!oTdlw+6qh`k%qSsrRJ?y!^kLUN^Y*|7P$;Uc!UZEq)G<{%l^sb9oJaoj-@d z{dZFv_+FaVE4cq&?i&6JUH1+AM;hngDcgB?sk{aEx}G-txtd2Exc^Ra2wy0Fx^VwJ z;Rs%9o$SH?@q6I#lQiE4aQ}U$7=FC=Ekn51sU`4K>;DMu^;s$W#cF>H_v@R%U#0!z z1pXVXKRNt|8lNfrQ0-R>__KAtn88ohbu8iE)%BXg{rXn$&uRa>fP4LN4L?x(^CjGW zH?o1RG_O~1|NW&k{3SZC4Ls5M89a46|KFtXZ^6HyePA1YKlQ%@f0)KUgg@Wk!@wV@ z_z3=0jb{(;zcbc{e@pQLxc?qk3}5Q{4&f&&&l7mZpF`nq)3~MZkLdn2hQC?&y9|D) z#&ZIHvG!v*{5-Wkg?oM$@YiTQ&fva2l<+@lUonUKdR4*udR|_@$GYw{d@t?um+-?h z4h{V0x?U^z|7hJ_!!J=jY~WXE9tBU^&i_lbp0wb(#;pxMOy}Ey-$CaU!au9))rCJ> z`}qid7q!!a|5)eMhaa!?Z2-SU>t_rPzHOf;4>#+McHp_zTqj2!6QcZwfz1`@k{$ zul^hgKS1X@fj>a)Ollgo@wLn*MaTy5kFHq1Nd@xYi9`0?_$SI;I(`NPxrO>6dvwxK8ELa zGtc0Qf%y`iCDzXdo?fBr4sZX`d=0NJHQ&JFm3g4!_;?0;TYk3S?c12Q;i2L?@aVVJ zeh4qt=3V%@ZS6>t_njbzWn5|7z=} z_shrG^M8W)i{57Wki%#C_Y_{e)#gzF|C!qH|35$OSo5w#{56WN;En!W!@VE=-@Sc5 zuNC5Ne!8948t(Htc!uS>w-frm{eQJC)pt@J!W(%99`A4Q|7cI`ct5*{znl6Q!IuxZ z`L6Y<55I$+YX{DJ>SjXf7Jf4guh1n$vON2?LRB{_kUpDD_+1~tZ}R1mui2$ zgug-Y4g4D4H^P6U>$`?uq<(JT@6>q(M{Vc%^OX-R_|%`9;D>78(t)3%>mI@%tLxZ> z|62Wz;5X@5J$n!SdbQt&zgW*TF+9@!dI+z-X!9|Fx4&dQg7-gap2CZ7n2+JvPt7xU zBcH(AmsxxcPu0&UJigH43wSD@!AtoZ9%y_j`1)to{sJB}<~7{+bxU}t_y!)!SMW-{ zhBxvJJiOfcOY6su! z;H{&#*FA5)1JBi;F5KgLJNRG+AMW6z9elilPj>L>4nEt#=R5cU9{<*^?-K6gu!1Lw z-@rY-^{gGne+TdG;61n>cL4X}4tMYo+}jz$y`9MpKHb4*aBqJO_x2Y%_!6FKoL4*e zW(RLQdwcx7oesQI`(3#Av$ul};O*a8{tV%vd<2i=V|ZUafyeSG+{byggU@&H#SXsQ z!B=$kXG7O`ww|*+{`r5~_;ldq+Pu4i_jd5X4nEw$NAOC=9mD;)PvG9q=?*^I!RI^p zVh3OD;Hw>cvxB!r+vDHpd^_;qDvdupm-pe>|5*G0p34(>As@kOc?Mt0C-C48cH9E) z?a$!eeg*gV1>EBscw5I^!M#7hG27!DD!v8JbzUJnQhXQg@qM`We*pLXC-A=7AHlu< z89Y<`1YXDscqN~~z5NQlR{R3)@eSPLS8$IHj@=%Ak8i;}K7@OG7w++Wc>8~q|8S2_ z;F01-aF5U6etjo!zrF?B<7aS>uizfPfO~uc@2meSc&>a7j@uspSn(}*E)U^rc^B^S zeRy=W#vktSF}!}n-FLl58p44lfixg$GZw_Gj=~ z|1RO{r{Bar2Z6^AwstDGKesO6sp9=Od~RAI{!VAud&LIc4=fMX@bU5H8+de-^)t|a z_v0q=7To*ah8K$Oz$-h$y!|X|rw^~>19VIm zw~sL&!IR_6Q+WJbbH5Hg&iCNyiEOU!Hd-5I`Ga3<{>=) zu=TSGZ{!i&=SvU1R(v1spFa-Z!AI=4F+7}^58=5yfqVNSc=J(fCxy4qGSA?V#%BVr z6`#YSv#p&eJpPz@0r&Bl!3(uh!b|xa?&DLzE5$G1ef6h?`}i#3K0a%Bqjom%_BnRG zfyU4CHj=mCvAhjW<({YBj;|*n;-jC~Jnh1Lp8EACC}lFd4Ieg)62 zHt*=Z=i^+;LwNsB7T<-(@(8}(So{#4{-1dU_xtYz-tX?eFdGI&K>tKH9tkzxMZzcg6psJ$`=x@wxgL!M&dYc=_SZuJ&Vi zEg!<;*!q*e^UKUf@U_}W;myx2ehiPVFwfxYmHCAJYx5jl{Kk9=&wp!P(0^w>gEv>2 zm+=1Y&FAp=59Sp-`IGqq-rktk@cuRCOL*}Y^9G*()qDjn|7O017k@Y3z=P}DVpl!{ z&)?4HXm|4#yt$rv8{WUEc?TYJ%tLq*ns@0BHILxUW6XQ-U_bLdJUqyJ08gK49>cS5 znGfOpADAcb=xFm1d@WDm&9f|i49}ipp26c|%_s2W81o$7KF)j!Po8I9z{?ky&*0J6 zyo8r8HJ`&Pc?B=uXYmVoc&2#`uRdtLgs(qh-oVqd%~$Z|9P>52{+#&+-mlDq7i{N$ zt@CQZi&HGV4Ub-K-hl_1c}PFiybJHY(L90&AF*}22agrshp*pk?F`_}Tg_wo+s%jY z@LlE!yn2uM2%eSZDZGD?`52!6r+Ef%>wG8hd~WeMJXHJ?-v6G(7w|~&Gx+*Ki!b5r zuba=|!FlEtJp6?D0v>f@ZbT~eh=>Zhdw-ch{X@!^~23$cy*Zh5MDgWJb^cdn~&hh zW6V={6Pu6W*%9U$Jbb+Q1fD&`Jcl<&nNQ*6GtCS5`e^eRJbjLN2@j7kpTp~8%`13( zy!is2q~a=D`cM^WXOmEqJQDROP1n&EX5j+Yl zKBa5_FoxGRv-k`i-oktWul{D|o5S0?S^N~9UDv#Tr*|@+!K2rjm+(?Phljtk_zGUg z7x3_R7GJ|F`3mm)hc(>y4;#4eAA*y&^EtcHj@yF!{-F)8|77tUc=9*%5T5V8m#ydU z>U!o8Ji38-4_^GUc^@9$$b0}VZ)_gJR@dKgqlUPfs=v;n_>fyYv^C zNAUO*^B%l>g?S$yo@zdT7q2&u;n7>nhw#2UfrlTk_!0d><|#b+i1`@a|EPHe&%R_n zpsip@xSi+57M%-1iR+{MzS-UHgF*ygkEvn@@xP5uJ7gf=TOPX7TdXYvkwEf3-8ORb$QJUGQXf?s?8+jYJ@c&_+9 zypa#!(aWu!7@lS3LwNNH^J~XxYkbKINJerti@azrd6L|C%^Bi8D zWf5?)Wu=kV(N<`umCJ@W;;_@Q}C|A6@t9(~BXf%iXRzJlj7 z^EJHrsQCsSpKTtzWc&K&A2V;kvvbX_od;X_ke22hcy_*d2roWq-i61XHjm)VSIm3x z{6h0SJpQWr03LkJJcd{DAw2oI#V7Ffx6McJyf#na?Ya3FUVX+qgU6pWpTKK*4)1^7 z;-~QX3+4sf_YX68_$7-k;kA4Y&nt_s;PD0K3wZm><~2Ol^KV>31zYg!eBo@4}ml%p-XD4f7s6`=)sx zo-EA=^q-o?^dFlK;kn`ycqJdfBYh9y+WXtq`jE&caNj@VaNj>n;l6(;;C=u62=4ob z5*{ml4o~D2Je4otnY@PQ@+G{GH}F!vf>-i2yq0g^jr`hu#Mbz)Nyq1sQjXZ;|NJkWYFhS!SE z;Ej9&U(0iNaJF5SDZDK&;Guj5kK`r1FQ3C>c?ECld>8OU@ijbD{1TojzJW)IU%@lQ zui?3T125#k%eV8tl(*oOybZ7A9e5)T;lao3dUfG#`L)lTTlb?#-h=n$eRwP%!ozdz zxCuO#kLddTWD3s|KZcj`3|`A8@ZjUtpBx^^r|?8xz;pQwUdc=NT0Vz|rS+$R$MOX{ zm)G!GzJv$oS^EtB}V{sbP&b9gSF!fSZ} zZ~uq2KZD2e5}wQF@LFEM+jDDw0gvT1JeM!wwY-71KV$8$;IVuS&*d99A zxr9gZ2A;@Q@KU~pw<~LZ15f0^E4TB%lDFW&1=da*-j{db**9;s>%DpeFXTOVE$_pl zzdm%=@8}NT;kT^)1fE}PK7tqW6kf_F@LHb3!*5&rQ+OsX;e~t-ujCbcEnmW;KiY8{ zczlid3ZDP-t#^(88eZPad;^bfX&$_4J0C)|(}MTq*M45Hwg1fI9e8?cYd?hN@-95w z$KoS+EbqZnc^{t32k=rJ!<*aKafk3g@d>;wAHfTqR|@Z|{V{yKuN^moC%c(X;MG5w z=kQqZQ+Tc8mhkE?HoxZZ^k8ehg6HxD+~;WxFBQLnSMoKyk#FGbL##i+tGDybkK2Ox z6(7R=e7o@I1ZzKn$MPQBkK2c5iXXyrc>-_bBY5;Y>rV!cPc)yseA%2Ym# zP8OfR^Zm>x^gEm9@Z_%MQ+R%^9k+l7pD~}o`)8P!@bDAnb9j2Xc?IulJQwifcGk}t zo;KFb5?;UEyn$D@wsuzV;zs6cczqM|4Sjd>_G`EEKYxpP2Ogbf9>RlT@3w1y)`hp^ z5xgz$!Ta()d>|jdV|ff8%7^eop1`NaSpP@xLY~5B@-e)WXYjdv0-@yI6g4b>5 zgP&Im-l&}r9$c(^gBR+51h3>hc&u^j!~J><;Hlzcc>XQx&ycS81RksZV|ZKZLk3@a zzQOyywBzP*Kd&j=&#Qp@dClN{y-Ikc{?FmDuW#_;BJ1Z8o~!>2Jo=Tzui)j%d<_qN zZN7o0zcCM9znyQDyaf+_Yw>M(U*3VQ5@4nuhLDvdw9k&oe_+Q0Vuyj%B2 zU!N!N_N%S^0^X>d89Y>c3D4vUczz3OzlJx8U&5nPEq)EpZfU-O$BGZ$xP88jyaUho zvUWmv`dafYypZ?dVaMVJ@J8`5ygjk_5xi78DLhvE7+%P8cy=pme+pkKzJNEcv-mkY zzqNS<4_%7YTj!z1&53%?Re%Ooezia);;cK;Dzz6#KrzO0)hqYh9 zuTuYOcyu3&Z{R<;`Mr1bXAMv9Yw^LGx3A0B^>?P)@amx!AHr|+fqU(0KZ0k6T6~}0 zyWg((7+yZm;uH9uD~nIz`6Dboga1K zzJZ@~V{3m6&tr=Z-m*RZXX@`pwc*JT79YYNt9-k*o@492P(Q)q`|tyweqS4Zc>W}d zPvE!F^-bZ`zgm0-f5_`?KIZV?sTN<95akZ2q?4%?TDC!dt(v_y`^yW$}IZ-T%kdlNes67N5Y6(Dh2;#q%vb zgP*Vb$>I4)7GJ<$p}&Jx!pj#~d37{VCvoQhv_ivEnQE&%bAXCvgeS6yL!A@jL=A6(789 zd;FiF`QCw7iVxxccpibT72k*Z^Ue@n{JV`$0{8eayi|M!U+M2NPT`f}3%IvGhu4a) z;5Rr#;}35X-@rTCzir^zd+mIK)3?X}|MYh`JMi#*79YZWKK9^|;`{JJzGCxn2=6OC zfqy{raSRU%>rVzh&Ho-ZJW_lCe~zy|@I>(y{GGo3z;nenaKFAAc%k^0*2TFol>zb9(Sv@qM`We+UmgZ2d{#{{CkS zuN9xc&-e8o-YC9+pQHCzb9nI)>rVx5YrnCCCo_#d+|PFduRf~rf5-OtN7`?9;MrLg zAHpxV()K?+c&_+9{OGIgd2I+U6raGqto`H|UMfC=e@g4s6ds>#{V(8Wo^9*-9G)q@ zg8O_~!b`}K$A56E$|3uG!c&+#l{*Uz^-YC8g_wgLU*NRWz@6dWOhUXu% z@yy^SY5y>V7m6?7@6&odhnI@4;Ct$MZ3%A_-@rY718+*@|2wzG|L)p9ci?Nqhj71N z^x(mH)_xy;SM3Le@JR6q{EBnzel&(xpVIilcVF6koWiqDTYLdO`H$NF!wbb%@T>1+ z`-dgGRD1)!Sbx`h1FsYxylZ>>zj$lAe|6y5e^~!R_~0CS-tWQ7&uIMN-k%}7QhWmU z{*2-IXEpxtFP>-PIfWOBFW~ppeq#<#K4pwibz}gStU)K8BgGXPs_&(hGGlZ`dpTO^^@fpM8i>&<&e#iUU`;95Q{SAvR;eE}! zIXt=kZFjvNuHdD7316$71|GDmofSNh2k+S)|N4CEXA52_z722xv$fxahgu&Zc%=9q zyf2U8k=hx;Q^hCnNynq*)7c+RN_!1u9*xFgZqc7Mv*YH&F zOL!$;)78!f-oA+)H~9DM>s!b>^ebFeKNY-C`~sfrVeK^V>TA}{3Z5x`4R7SF z_ikUu^6S=48{WT#9k)Z@(>#JV3u~tbPZZyWr}7~@)cSVq?;&lyhc6UAf(N&>{$%h{ z?M&c_;&XTc_D&F zD~s>LpRV_}F}!`H#V7DP-^%urDLhzPd)$@1_ zU+<>zhreF&Yk2%8Yd?7Z_W1u^{cpq9iVxu@Ydj-(_-AXs55G*$?=gJ+7mH8euhi#> zDZKof#b@v*Yk!!--~GS#98|!IJK4C+;I+Jh`{xl$_*(G|{Leby4LrQF9XB|0d;IX*F2wuojcqyO2{qJ(-JNR@5FW|M>pTQe>3IC@v z?S0MyzE*q<_xr^P9_(x5xrQI}4g0*c^?~i{7%9FDe~3PB?ZOkqM{v)#0X$WF4EN8o zM({%MDcqm$Ch(+d=bOVlKWFf8KZ`Hn)zj_%vVg~mui^fA*$SR2ehv4}%UU1Y9{)n| zZTP$Nd2ttBD?Wms@<)5$GJqHR+xaH+dzg>lS!ABV3;7sc$}@N+pTZk?0bk4KaG#IW z4!+pIYk2#fc3w+(C~x3CUpDYa@xh0-ucLon+<_;G58)ry{j>*972k*VF0=c>5S}SM zfxpP#KfrUvXK-InrtnJf1^i6iujlZ!;wyNq_pwWOcrUvy4cy0b1CJFSe0Y2Oef{ac z6UB${e|-K9&lTT?`+7BmSBg*I2kL$A7@pnR&NqYmdNqZYiZ9^4Ud`c+;w!kXS4((s zAB{iU*Q*UYQhe}{?eX`|_dD=J@gdyTw;nuK{I$O?yY)Qi>)Q~X9BBPd;kkSaPY=@g z!*lrrUdVHJDWAb>c?oai3%IXu^$xz=!5esRUpucAye(hDAENJHwPxGn94fvI_xaU@ z$BK{OAJh6UfM<%2;eLM~!Ar%b@U!)K{RCbqK8O2yK7-c>+qji*pYIEJaEQg%@V9Hd zUBN5Gui<{at&eVxf35g7-22moH;RwozMc=@YsJTKADX;f;I%uO49iiQ$cW z2w%$+c2u z`wU(xzJ&impO-D*jpA##f4;eb7k$k~xW~6Xwmoj8;@j|_Du250O7VSo|Lu0%0lYfH zJcj#q8Nt1s6rR1q+8M(O`L(}izm*U5)Z(Y`=$+;TJeSYm(R(buf~WEYyp%Wa-~-mq z3f`8l;i0^B&h~lbYip+sFXbJ0^mB`k;PKzgd+>6%+wJ;%vkz}y*L(m^|H(Xt*Snh! z;nDTY6L{V-AHml*Fi+v}4b8{!ux*~f%bS@`;Qc+!b9j9V^C`T%rFj9*_couwlhC|` zmtFHYyt%7+1#jQOd;yQ|ZC=Cc`Zoc<@s56+Drz;g3Gt-iHL|Zs+G-AG7yt zZTRkcS$qiJ=bu%l0Ds=C?DP6Q{CD~sA%^?=`2;>ZUccJ_Pvj|lBp<_5c?KWLC-6+3 z!zc17JeL>nLOz4f|&_ zZSh@ryKNr9*S9n8!Q*|*`|$jF<^y=9c4ByWeTyH$^BbFA`*(7-_94Z7=3{s%&)}7O z3UBXk?G*6prsgwvb64{UzV08o>vt>{@aS$9U&H(IB|Mfl@I=0Xw-2@B2Ip;$Po?-4 zynTT6rwtF~UAUiD1dkNogZJfqc%Xg`;IZOkcp@LsBkO+(&*WoxDbL{k`(_h(rT7A# z-_wpegO~CW-pCj5;NHpycr0JS3;7ye$~W*dw)TVbxAUR@So03NzK?kb_um=l!rMn! zd>@`2Xg+|4ijU!I`3Ua!sT5v4&e|Wt^MlQ={d-wk>%$}eWc#8V9^B933;2x>vF}lo z@b&#IzJmLGt%m0hu=ob<_q8=VdZ5JzpV;pIiQl#FfwbYZ;zM|;@8LxBL#_Qj{5Cq@ z7#=>%;uHAZy6>m(;^7vb!M~*UoH;xjSbPD$hmSuzKFs1P_#56}-y5mn^`k7lf&a|E zrvWbyxA@?b+v6WR(YytZ-U{NATcD*3T5)mQUc3Jcsw? zGq}G`D0lGr4qm|%wZDL;@*3{%nOE>k@oTuhcWr%Y`#R=|Z^OO)E<7IEct-G7Xg&_$ ziQ;4UCHkCV1kV+p!oQ>M`Ap!I;&b>{R2MmeuN7ay&s6^x@bF*ld~5i}_pr}xSMXTz zYxw`@dqk~IZ;yYb_%{6Os$1#8OT|ZU@BaYaDE`{Nf4H^&d;dr9_LDVV;NJfUys!8i z?){&^Q^i;CLcV~vpQ7=HNAe}SFK^(nd;?GA!GCOzPbTlceZGe~cy|Yn=xV~H;N8|v0{8uY3Qyl-@fqCr|2e$$mNDi4i>cptawJKWk#oYuEn$-mUw1 z^C62*;P=pb?-ZVW*y1yKX+D9M@&bN{-k;Cmwc;!IO5b~2!W+dm@Ym>j?;CjgJnLuh zx$SYd>-{YsI`F>YBX}zB(LZhN_u-X%2oKJ;_yivQhxrJe$}_mny9vBjd=Afb+$sD; z%99y9_@wn`4$tT26}*zK;Pq!Lehn`_Yrdg>-8}gG_Vwz^Tkz!P7T<=a7nyh9`M1nN zcu<>n;q7mmNAUQ&<~?|QiFpi9t}!3N8+ih+_PG77_uC_Qc1!aVUf#=m3{Q?U&)})z zC-C|y7N5hD|Fiy2;rYWXzJT{1Za#zOcQG&F)uHBdc=90g3SQsMd;w1nFt6c-d4 zYw-=deRuN}ynhe#H9Q=cZ{W2&_`-HRCy%%I7Cd}{c?fTgHSfaP$C*d)Sl)xD@)+)a z=Vb`b6`#OM`3Uasfm3*`_z66Gp7lS6$MPvWmlyC-K8O2xRq$Hz3;0@I!~MLL@OEnb zU&BNB1|G|UFK*{UE^on0c?kFO>cVTqNAR`02lw;p!`mm?c@5#=Ddq`0mXF}MJcXC? z3Ea;shu4aq!q@Tw?&mdww_j%cFX8={o6q5?yoRskOL&-BJHeN>uWyx`x8SwB4R7Qf zczBw%6VX3l-h*c!H1ER;`2gO?V|e>R*3J;#mnZO4K7yBpwUfe=_nVL5`Nz#Ocv6~A z;O#Tbb9kx#%;27HB|N^s+L^;sc?I`;Tfj5LH}Ldy`~BV(ynQG0HM}q1!0X#td{AxY zTO)75*YY+z*w@~XnvG@(VKF&P2U^{=J zF5Jf+&fV(}xm_dkUf zr&#+=9!%VT)>PHTS% z_wi5Q*}MK9U3VTW&!X1ly_g#rEM#g$uoQ$AxZDCvXq-}FhK?p!Nl4PfC`Cd-CmPd< zh|Op*Ny}JFrjt07h}wW+35bmf7BV%H6ob%!V5y+Z5Gm$nG>cR3bJyx;x&QsFUiExW z?RW2c_wSr@@BI0loc()w^XKQ!ALZ3|&)&%U@RK~d&7W`W-!uDJ-hS`wo&Eb}zsR%i zpS_pw!>{r-e2^zUFhA!e&%#G}8Ge^H;gh@zUwrlR9S%P_cT;)(W3#X1{5ec6Pk(a$ z{94X`9+mRsr{~Xa(`sU-SHROx}9-mArlR?76%TU(2WPLO$g4b2jqy z-DfZ5Q}|Y%zsLOfN?yFz>^ph#J7(X@)89S&L0%NI*Y@8#`_cYBvp4eW_sxEmzvjO` z+dp&u{6#*7_wv{L_h)(WS@Uy7c^Q6}@53i~AO4W1pFKZ6{o3dInZlRy>~rSNXYze` zE`Pr-n*TZTwfz0V3;AFA!1`H#NM{G3Mq7e96Oll)_1Pb=TYp0oU0 z;{EjU=1qQa{^v;TANLNg{QMl`?T`M!S3ZA}_wo5rK7`-p`Nz-CpX5dOL;iX39+Izn zzQeElg!$huSjgXDnE!ttQu!CY@%(jM%0D#TTPAuhUgaZ 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 @-}>s(=*CXkNEz`>6zs8 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

eYkQA;B&ms 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

PXm6g=IJ`T2e-Z{JPRaGAD*j^;g+X> zU#)rkub1~_9>A?{4Icb!|K)VE>cT1iKo~fsB%hQLi^(VO>P8>diTi-c+^b5(efEVhu%gS@GJazb{ znkRO60=K?Bc>Dv&lfo1A5!~{O;d^SH%H`$!=2f`$4dD4TlBWhAskh;lCxWlgJek9D zxb+>vi>oEi2tHMx!!6GO-qk#fE6VdRZ^5l^2v5KI=BNGt+j3qTo~ifXmM4Xut$7NE zPvO>g22W3xJac%a9^~cyTAmvGyPBut@Gji?Ch+-3B~K6Tog_YlTb>d8HqGOGqnzK| zhg;t&yf|Fe4d7Gt5N>(e@V{%GzQYG_>zl*Vx4!9V|2cn#@JxLMw>)$B2D9itZM^!G z<@uO5;nueWFJ2*eLikiYfm@y)d|S;kcK8HteW&p7rIKd`kJPJImG^6T0{ELWPvr0z zZhgCOe>2IGzytLhZh40AWJCFRXW{V5)#ZIzUmretvE-@33-u6w+nY~ae(uwTTh0jn zew|wv9=|~60B`Bz6h056z7Mzh3~uY@aLYY}r!SQLBY37hhueM^@TPu`U*ntQ`J1=k z);ENE&y_rFxUb%WTb>kthR(lm_!Mq^XYk_RZ(QDI=J2U{@U8NGEl&;pRn60c$N!Z6 zEx3Ko(uNmLN__;k`VQRI?ZPd00*{}P{yli2K7`wTNARn3zY}=$SLr{6+wZx};o;*_ zzkpl4_wDlhZCxL3xvTKG_7C9R-(=koZu@P+f3EwD;n9QArwh0IJ$U$#)TeN(@561~ z0o-!u@VWLM!o7!O-5K2WJBR;4_gf#9=WpJGTi+Hu`;*QYo~tKt%hQAZL-ULsK7m`` zDSUd5&H+AGuYRYzU&|A~pLM^yu815S!>w-@9!w=q07f!u{hU zPYWKXcj1;Nfgi7VMh-9F)^`G*zgO~1;okei{cFqnwLDe$nVP5V@DAMi#_;C5WZf=2 zR3E@CPY(Zv<{87iBcy);pPeM%V>5+^9jTwet$q%-b-nME=l0*+@VWN);ogz5ZWC_% zZNY!0`|UZr54XM*^D@<(b0o(mcWU%X2WV!>w-v{-Z4J#ga7?SItO^HkB9I}Hk0}h-0H`0TXzDt+*9~m`_JG{saJncp0n*Y zfUo(0KJPd@hFjk*{8?4mZvx*$eF(4Wx+A#d9K&C%^;3AUwyZmY=lXa7Kh~FeZ&aR- z)mPxQZWV611Ne2?zXmVV+i=@&1m8jTn>jp(Ti+r4qE+-fgkPmThg+Tnd@s$@_+fc& z<}JAO4dH)YyncBer>dfLr|pZtKqAmU|9=kM>`{ zKcrs!NqNq;-#Yw8-EZvh1a5tM@cHLuzbX7F^%30ijNuc_Q~7B*zj+mIeFONRr%Rq1 zJXUYREl&i0Q1fIC&*9d02*2%Jl4k_JM|}>rJPY^}ny2xz@_fu&aO)ewM~6wCHoQy68E`)_Wz zr*rV(fqD~e`)$Erq5F;C>04#L9k~6SeiuG}o75+8tM9>W-9FrMXYgc&^dG=e^$Fbe zJB9D9`(426|115y>&x@EpA&t!-@Tva)HF&VO)Ysuw-+8&!xa~KEU#I&Wz=Id*oZ)u=8NsucNc|XY^#$D4ox&~m4Bp&S`p@B^dhm<#@v{Ba z;J502I}Y!{t#1PNHkLd+xUW8hTb>a-yG=fi_I_E;Z|=jbZx!x6U-ATSUp<6do;LhG zoloE41Gx3g;q$8G8N$8)5ud>=&m8`Q=BeCNo=@{x(#MBKr^@@Z0lfZfsjtDUz7Dr_ zn{dnBf*0C9giqBIxb3$G-~7+=`Y?lMzT_Xk+sC|Mb?^WG8^XN}q<#dq`Z3(roxm;k z6rO4S89Z077Ukn*`wifG>wX(>Z*9rngj@a)9<3wwZMfA(a9cNqTkbC0TUYuga9=%# z+kS`e!*ss|yjWBEPvG?vAF3*UM z`*2@<47dFj@H=(C{;lP?nFny|TZ7mCCVA@crg{XoJRSH$b{;x>2)Di?czBQG8N(xW z@7Lx1dJoC-Yz1yPeRx&tYw&QSbAT^2M-$$>PU>55s}JF}ZUnd79k~Bv=^w)b^$c$N z9l&3%`<*#_0k^*1ZRI)V2T7g^e5BrhTb?G|`+~eqZo~Z*(m#UR@3Y15TDeRz1F9 z9mA77Bu@cP)xAl1zm}&0KSA@f9Nvao-w5vSE_pieK)nyQJQ@5P%`K9r-1)j^Z0j^_hlZyt#1t;Y$|!` z@Va^gw>%yA=#_Fm8900hx4t8I@O;TLhS${>aLeQUwmgTw>U^3G58>9g4UbomJP|xm zPvMrQ4`1(Ld48NYd~(AdZaJIq%{6Bm9zP=MM(~nx`)ctlG-i2G=1U@=W^7P<^`Vek; zM(|H-9`EjQesdpgeXHeV50p3J=s< zaLW_I|3~wr4$t7$cL4WJlRP=xSD(Ty&kVku=BeFNo`ZP|uzpm~N4AH%J00iXV4uVtPIe6C*kQ+dCZ$A>?nc|wOr zaO>NFM~6$E7#^z+;A_t1KAgiX=Me5|eF6W|fjS3xrjKXv?GBduIo#?Oa9g)BE6>w% z`|#tme-(bRdI;Z4_tl2m93uEOTHl55xWDWxfw%N=3jb7F>icl3&)~Lh4!7Jx_(c1U z;Pktkmeb{KedPS&*Ap_dn5R7 z_LBNB-0BOstviKV?iu`9drSX0d=vHHf$}_UzcqMA_uGVDu#@y}!7YCq{@|`sAHl7@ z1Gja%aLb**U%H$0@4>fMAHr?FBlvrDzutr8`I!4~>sy7ta4pFbz_(Bj;g+Wj|DfjS zJA44QzB&BCRVB|5zEGdREzcb8>-+ZgKbPlY-h^A<7To*yp3CR25bmodaLdz!e@y3- z!P75E{{h_ooq{1exlrmyaH}7~ZQTjna!=v@Mbdu;57esu4d8v%+T^P~>X;MR8l-{&;Rlfw^CpTaHA41TZXsr{uq2lEEp`ZnQFPx7?jv3eJ7c@p>& znx_vx`ef;!!R>s@;hTJ1>W6TvAHi+i0&ck{@Q(JM!atzy&&%_){Z`@6c|=~vwjJJq zTi+P|$`fV3UHI$N2XM=i!?)HvV|ef`>0iKYo>RE@9;u(ft$q%-b-hQ*bNg>@c&7b* zc&^@p@3K|L`_F$N+~&}R@1t{w;q}9H&hVx_?!k*Aq&|h)9QtrucL2BCIXvn}{~nzm?}{d8+W$AJykghj-xCH-?WkmONc}p+10Ho*e#s%`ZkDepTlTZ|LI$9&3FMZuKeL*3ICSdjN0#kL1bWq52eV`<=n>)ctz@EYI0{ zmd+V&zb9FRXIdY?t-c1gbsKQY-Gn!vEqPk-xq26F`%U0~)&2J2?Po~;3|{E(hve}4 zwSEY<`VrjLE#Q`W0^e+H$uos-tL{HpK3=xpDtv>#%JXI&?s?L`0k_wIE%;ShAHuD^ z4YzeWaLXOTpV0nY_!_H7&H>!^o5O3m-?_uRr^<8tZ(sP4Uu!Jyt3Lc#^(Nf%wBUPa zo}R<|aO<1FlT`8y;HmlqZh5Bgw&n@`Ri1-+9d3Oa@ZvDZ(}YjeW4Pt%!iyW^_b`VJ zAH%J00r%dr!}54d;J$k0-{t*U9v^SzFGR$;iC)Wb$%1x++XTjaH|jDwr&Ks z+#R@ofb@^yfqDkF{SM$=-R}qZlg99*DfL~r)hBRUH-%g7K0J7(^v~dR z^#X4Doxp=r<@%b#6W#9uUb{*D{mRNJ<@u*t@5AkNT@`NY*5H=A4$rlJ13pskz-_-V z{5(Crxx+_r>pO<$FO&Hf@R7Q=YI#1Ervm?`=4m;+4Y$4#JidF|<^8P#Pt^Nx%ag%J z8_4-Eb@&`^eHZZg?UKh^tvmU_Em@4>Ba3ZLJ%&2m0{xc5i#G2HSL z@ZV`3|7qoYnFny|TZ1=`+IpF%4iD8MxaH}xOX4-G*oHUUfPD2%hS?DcttkhiB{W zw%qT;;WN1Pox_`l%X}8_SiQDJdCr!n4u6);zXgvDk^UjvejbV7`JqzZfm?kHw{;V^ zqRsJG#kCxY*!dAjgoZ|R@F zM<0~eohf|YlKMW}>NB{lo5L;l5T5QM{YUUjeGa$%F5s`%{rZ*i{O5Z}|0>-69=`?; z_LTZM-0B-}Tek(b+#x*I{%!b3J%t~x`|87O4jDYyU4Kr27rW`4;XQp^z{950PvD8Z zpEiZtx^uYYUcjf?-+MZamwE$k-)q-|+Z)U{T%a{2y;n%6haLdz$pRIX%aH~(@ z-Z##Y?=6H|{Q!QE_8-EnegwZv>nHGczEHk*YYMkMGx(L-$9qP3&eo>_w?01HyIQW( z0B-d)__exj18((AxWDRo%Xx-yt8c@9ru{o`tB>JVU$e*Z^+p1>`W}28&C`cleFiTy zPY$>GA^di&FW{puZMA%THG$jpJA>z6mijr|>KAZ3Z!2q;&j&m2eR%j4>0gD%>LJ|w zs?@jPmZt-sYkds2`YznAqaHld^FD>A7fPN!JXbH^&5NXd0=L)CGkAKj)X(8ozku6y zU0J6*f4eXE@L(YQtMI0J2rtyzbe&HJ-n>Nm$M8byyKuXo^x$?sO5tl<@s0iI`QGjWjcR&s@{bk`r31s_pu(lzk&Q+UJ4H` zm;QZtQ+)xq`)Xyqa(=rn`|v{hRN-^=F5K?JJ$OUslfsiLG(S93U%>6YUGdBLLz_Rm zp6mSKp?Vi?_xT>&o+ncHRQvSd-Zy031>Bw&D(jc?+w+PKPqj}Ko~w7^_B_&q_ig_0 z=9M~sc%;67+w)FkgK~a*-tysd?Nf#OSIN39xIN#6@VoW-E`nQq2cBFj&(~eJ)hF<; z9QXO&(xB49ZpynUJt$qxDRO=^jtDnNX$L0N>Io#?O@O8A_e`fhO zCb!j>uOF&#dp@ec{oAF!4!8OS+>T2NZpSr*XWG9F&(%|S^A5?=hg+TjJiSxubGX$H z;dY*k;dY)C@ZfjSe*&+o`x}<$KT@yK_2&aJ$Y6c&>dW@R54s+2#4zb=`v7eIbO0_iKK5q~3$u{Un9|YX9}+=UKSb z58xZ={bvZb`VstvT3^7eegbcQRPN7nczm7gcLBHSz4Dy$JoBGOy$`qgD%|c5HMrd$ z>hR`IrGEn+s`ueGhXLH?n8T;qX9%CGSF7dy+T3bzn|mFe{7m!1Q}qtqj#mtSnI7K+ zZuLEQ|2#RqeYn+U@NKkz4!8Otd{?bsz-`^i|CHxuxqbSzGM_3uQxDF0bc>THMIj8CkxV_)ff=@p$eL}d^x8XLo4&3G*!;>#a|1LaL&*4E|>W6T< zpO4|m7p1;{Tm1xX$8iR?^I#75&zAlRc%WW?UU~kxdIN5GTJYdp=^w(az74nYssp$4 zGKS~czY8C!58!q_=kSB|d>+BAehlAdXL+Aw0=N1p{E0Wq>ytU$>KE{TtRn9xSDs&< zzt#Kj_h|kAZuK?z2eiHcxB4bL)%p-_^=l3)u_u#9)SmrZ^|M$4S z?YK_i`LDNJ{=7MZkJMW)D9_)HV;gSgK?DzPll~oeq&|k*ai75LyqVIq&kXMUM%Ha@ zT+VOjNgH0#{YUUr`*h%$dIqmgWZeNg{e=9!+z{^HF7+e0)sNwJ-cI0l-cRAV_MgE= z>OoMRPk4vqslhEz1782F)HmT)-=gbz-iF(C7{Lqe-+@on$8fvuCUCoMr||er$v=aq z>a7=+=VRAt8{V<=2Oj)R`gh=U^)cM8>j~WM3sd+=`^?}|_39?&{B}PH;8*H#sl%O1fwfAz)X&$9{qC%SGAZhcbt-}H4|2DkbFe5(CtaLd1d zxAd|1qVk;Q|K4JGU#-ABPp=nvs@{VC_jLk1T1EOqaI5dYZJu4Y9ghS)*Zw`YzpAV| zf?NJE-11D|mVXMj`Wf6lcU!>ib2snBn7`()z%73hp6R|?@U9-;HauQa=MT5~4&2Ve zF5J%J1m3Jj{~kP4AHk>UW4Ps+z^7|V|0&$+XK=eN7I3?+yqA>cpRXhREAWwe6CSQB z^)0xa4{dmJJ*ki2R^Nf!&t+Y>{alv73+>;7&(();yPu5U_v`({+q66%yPx=QyPs6y z^-W*8yq^T{rg|G*s7G*{PYlmClm1<})hBSfpQLcRpY-ANn)J`$q51@F`KNHpGlyIL z1>EYr&C2t)`-u;?`$-jU`2)D+Z^Ng$uLy3}R}9Zzq4S4ZeFC@pNeZ|7NgtkWq4S4l z>JxZEjk}~q8`KjTcy4Wx9h714{q1_z^%Ryx9f2Lx9c&7dv{3xA>3D=!!z{- z-11a5FV8c-Tl)KOtFOZCeprLs{jd&Cr_#Rx&(!BOJkZaDb9nkwoew-y zpTS@HGpV1$?e|)}mzU@B-`|UckDnoRHTbsLKZ4u7Vz}+A3vX(l1RkpA@Y~ggaQl6d zF}$U}CsDvF`uY7FZu_deqC6k_JhTC~&r_T5x#n!ay|EmZE_`401a6O;8gtGPvaU;FF2Ex3Jt*M{5Ye-V7FpQ|NsTXzVz^JEOS^Q3@BnsWk=)hk<;_w|Ij z54X>K0=Ru{RD%!nbCed`=9a*1Un$)7)rb4n%lVMO1N8!avHApV@3+t3_I~{w-q-h+ z{CatAcD!0}JOA5oJO3m2NON}Jg?b;p(G5BWxV?{*!>jsp^aO7C{jJLTvf~oK?YPw7 zbS9NU50zB0J&D~H>@hVWE#j^LU49R5;!eG9kO!arT!faUHf$4$M1FX^88HTPdntF%k!`Y zKjDafEIozqrFk;Au=QF?@&KF3am~>hOib{YH7t)~Dw1ro-C~ zj~(7~c;@h-!wZMc9PaH{-tVnX$bHF&Cj^2)Q+aO3e^<`i0KVDd;x+g&JIQ^x z4*!ID1OAfNNPQFj+ZX+1dHuHFCun^LpR2dwkEloR=4)l$4*ch#cnr5W^x$V)D|1NU z&;5~jAO832#54HTKNcUr|9gBLK5=+u=kjsf^Voka?^iYW1F?7=9=>0^0k=L)_*`?e z;BV7)L%8j$jz~Ke_W!h&7w>}H_fuEP>1%H?FJP%Q?!p~O^9A1Ne z_zTj%4*#rr1O8?8CVaKN^l8CQP!Hi7d{OG#@L!xG9>KqUo_Ggt`;FmOpD*=Y_)pXm z_^p}L_uvny58%H&OX_p@L+V5Lztu-@yRIkjkLZ1G3cpr;2EX}Zzgpg}yj{!Z$p?>o za(UfV;C8+R4sSR-ba=<%3H)t#9l?)O&)_Gh=kVJ%-e&pyHFo&a;S2a(`tzp0TX}9* z-6eCY!Y}%u+?N9QBkDEyTF2}C4ZiA!^!^5a-nMcdZo)5qv;5rAf}ipp=@Y{D(Ee@s z&($M%aDw#dz%%t2zQKp3z6(E3J%Nwad+^qY(kF#qquz(_^%1Gh;OD9j;Ll5>K8OE7 zeF#7Cqf$SD-=#i=AAge67xa&bPvC!5pVCj3`WgJtAIbM#&f!OWT_1HewTU(-{I3z z--drvJ%Vrf8L98Uf2bbAcRo$(yYOGAC-9q2m--%j>uuzEPvKt)<$CYK-O?%kS$9;K!_S$FhG7ezW$e!*AR17t8tv-1;=(f7JRG{4+bqag5;KQ18I6R*&K9 zHKb1$ezbZ5zhAuvUu8!PSKCGEXYl8$&*4_TfJa*Iy|R4XUZ`Gy|3uw~ueGb>slqo=58#%k20u#c z>+o-=H{jQ+H{roML!B5%9TiyqT z@L#Hr;MQjXKl7jeUcOGA!}Il|{{n7({5{I&!}!nArv`u9)1*%wZhcztf1M%s?Fjy= zGsQb_>yyB3Uw!yQ_nX13&k%0=D&YP@vfl~Z`pn^<{=L*!UR9pkuhf0G^{K&ETrYi^ z@H^C7aO)E}ybC`ml>RAvqTYvF{~T_|aSXqAFX>;vtOBkJbJ&xb^Y&D$nx; zQ^`|>zh6CoTb~Bp<`cqCyh-}E;npXHKmCVN--EwFJ%wAJ0sQ?JOP>*Z{%!Fw-1 zw>}x%<}-wErhP_m>ob8{pE>;3P1)}PZhib#d7jp%2LF)usl%;L3vPWP_)E1<2X1{5 zxb^A7f1~GB2Dd&#_z_xPz>l@_6K;Lx@HMo)vQK$#&rc}pE`WuaDU(O zoNe8j!hQY5TMmyL-gS8D@PWfe4xc!D?(oWf zE1yH)@P@-fhj$#FIK1!h+~H$~PaVE+xc}Of&!OhEVyzcOp!y|`x9iBRT;P8>dCk~%Gyz=^$&mnMl!{MRBI}T4A-gkKJ@Ug?E4qrIj z4_7{in!}q8Z#z78c+cUP!-ozp96ocn_lA}4x9ae^!&?rI9Nu+!3O~R0O8Gr2_*c|( zxYdv0pKME?0>1wi;xqVFyNXxdSf0=4Qu+5lefYnQ7O%nA`B`(BzYe$h7W|)^OP>&a z>IcNz@Pl729>G8T4Dk;9U0NT*k5li$Kdqj?&s6Whuhg6=yz&ak(}%C4p20U)AHcU! z&*3|(58(%^kKo6skKrFtFW`0@CvaaMPvMVkEBjr*U$C9H_oniB_1yQ0SK!<2AnwEM z_*UV&YkdHJjd~3psn_8fzhBmEz;pE`{8tUBZ^3U<58;ogx8YB!NARcZDE&L|7pTYZ zE!4a4UDOl!-s(MgbnT0m?{BB@_uRj$+?U{QSxa)}@bAasL-KE{x)V(*C&*!#!1su@_yS`LpK-gS8D@PWfe z4xc!D?(oY0mgi&p3LM^Wc7Y_H^E1yHn;Z29P9UeQp=kUzo zLx&d*pE=xn%gXm#b$H$3Er&-A?>ann_`u;Khff?ncX;Kkp zk;5krpF6y=V&!uP9Nutv=(LnZv!qR=(e=!|M)jIXrTB*Wszd2M!-O zeB$uA!z=Gt`5Xd=Hyj>1yyNi1;eCha4j(&w>hOib{liy2hnmBi4sSa=c6bl|s(;J- z7=5_iA99C}9X@sV!r}fAjyX8I>F~D0V~6(~o;iHz@WSCUhkKos@3-pkI{YX-UQPHV zZ<6ovXgfTHpLDDI9NKeu=J27z3y04f?j2d4gXO6@yzcOp!z1`M@7ihkJlJ)3>hOWX zM-HDjeD3hdJIiyhoPom|4i6pPf&Wv_pDz4cFWPZApA`NA@8G3paH}6Wym0u;;oiH- zbFltZhu0n6a(LwMuESG@4;(&n_{8CJhgXhT`5Xd=Hyj?qS6fAnV+22CL-`((F8tYh z%jX>_eD@RO^P>TLPxTyrr1}tkMZkA%H0Q$M{=3WbwE8Ceuw$iv z3;qN34*a;|q&|kP))i0T#~v@4jo=NeCBZPJu9C>)!}uAw;UchJcU1~ z`|ZOwJ3;0!grBNDg5Rq?g}?5@(q{($vHBctbFLh{^7#Y~Z#X=3c*o(1!}|`;;p?0s zzfU`M_|)MGhx>7P4%WX0zvu?}y_zQc3iTHJLG=*+nv0}Q2mWUD7@n$k;pcu-`lRp+ z)%)<@t7q_!zfJlK;isvO;5Vp`;g1ca&lJA>cf@D#&#KSiC!Zztm1D}s<)`XC{Dq&B z`YQYdM~m0thpRW>KU8nRAJ{|swBcL7N<4ypM!f_7$E8xAz*oCWya(T1J%wM@O9NE@O{;%@U^PaX90hwTa+H}k5)>ke-@Jc8f*Bl&%mnEnIt1pbw0 z%5h2IlV3}H2LGDY=kPnPk@^w*3au~T*-xc@3QtzwZFyYg@S*ncjxEpgd+I*?M)d%m zA1Cii*Wov7eG?u&F7+XNqV*B{F7+5*y+P*>zenp+c=y{nfB5}cpTiH+zmpol|DyE; z{CPL({Nbnrf<)NAkqcauJK_$OZ}-hgkV>o(yhzC!;l z5`MXQ2){;~4(4-EWuYLHJSYOML>*)O+wt)l>Ml)%)ML1k4~qy`;E$VxG!tPYGQQ#njjHd2#L8>!!~eLbJ9Ywm0B{^+_skL$jk^O}3+ zJ@0+*VOHkM!4vTYT=NU?T>fnh+vkbikEH|tX_;?>>wR4uaGm3V>wR6i;Cep$;K#}F z4Zt-Yfgh&l1GvtK!F3%&a9w`_euB&&fol&bxXu}aYY!9fvGhCzANc0HExR^ucvb z1g`5CfNKvi_!s4T7=mjL3Apw!0@of=@SWxUu^ITW&*-f2=r7>#<0$+0zv%h0-&FA3HmwW-P z`3n3klAnWX-uiI6pA#i-gKNGEezD|x;F=G?|1S9mT=PS4=SilY5xC|j;Co3v2iN=z z{7A`H;F@p1zb<*}BkkTa?|@$``7XHTeeioFAA)Os0RF5en|_Ainoq&sCiw}t=BMCi zNPY&c`5OH9l5fB@-#NP7+rK66fNS0Z-_kMr>w{~)5B@UA55P5_fV-QU$Kffs<}>hj z%KRy~=1cIeNxlZx`~v(Y$#*{5?oIP9_!^spJ#fv3;6Ijp1g`lZ_`f7S0@wTm zeETiT{^sDCpMk$c@)fw|8}Jh)Z+)!Yo8}$x%O&3h*Srt@U&)8ynje7oo?`ZQ2(I}Q z{GF1YfNOpVezxRi;F_<&|04MYT=Sh{+r4eMrCGlNu6YmqO_KM)HQxvSisT32noqzh z$*16&&%oE*%B+71uK5yt2g%pqnqPn)BKgk8+r4St1^EzI_fJNqzyYdHWOX-cFOe3$FPd_)PKvxaK2t$;arj z{t>vnwdrRJuJd#7oh4s@YrXxl6(WM`Oc@>yGeH!8P9pzgO}D zaLp&+8*XFzPr)^xfp;Z81=oBDzMtf4aLq5kkCA+5)b365F8H@3?}2MR059bI^L=p5 z$KY4V`~+O{WAKIKGjPop;M+Xi^k0H&ehyx|*8IJ;0N1>Ie7m=UWWEco`5yRtB_Dum zJ_0{U@-evPN8sO-{1{yGIrvQS1-Rxb@Y^Im2iLsy>2^Qvb4{N%xaPayk9meUUOjNl zhv2T{BXG?R!CxZz5xC|j;BSz84zBqb`1>SZfor}2_dBK^>x6c1ns>lYl=)q7&HLcz zOFjhG`~dv7k{^O=J_Wx^@)K~)Pr*0X)*Rm%xaMo{?IhoTYrgZDc5kniyaTRz5B!~y z_rW#a2R}~o18~hJ;BHTz{{h#02L2tHKLyu(34X2QYjDjk!0(fM=frkzns>oB?V97| zfonbh-$n9$aLvcyhe$pF*ZdfKB>4nX8^AG2z)om$KaYDfxk`iV{pyq;Kxe70M~p4K9T$!T=Uk+?S8J3ybZ4TF8BkI z?}2MR1mEIWrq2jm^F#36B|ie!`~>{%lFz|4KLbBe@)fw|8}MB6R@&}O^A7lRlJA0R z-Uq*5@*%k92jI@LO`k(>&8Ofmmiz=<^HcCQNPY&c`5OF_l5fB@-}!92w{s-#fNS0Z zzf$r(xaRxd|B(CuT=NO|6P{!GOu;pufxl4lQ*h0f;C;#0;F@26A0_$D=i0q#-UXj* zY<_=v;F=G>&y@LnaLvcyKazX`uK6+e4U*5mHD7@LTk<8i=I7v>Z)c9z0$lU<=i9x# zRPrvk=6m3WN@C~*%$14Qa`~du!k{^O=J_UcdopMoDQ`5Cz8Yw-FB=6E&Wn(v&} z?(Gzr?|^IG1HVx6KDg%l;MYrj0IvB2d`(ZT|KOU>z$bEkPQf)_f7kHNnx`2<|^WAL9yJ_FZ$0e+L@OK{E4!5^0V0$lU< zxZRukJac?qaLxC?_m+GBuK5W3U6PN%H9rDBS@L6W&FA3fOTGZtd<9-geh#jA>x=Dv z?vcC=uK6zb7SA_*_P{kCg6|{w2wd|+@FOKZ0@wTm{2P+b!8JbvzftlPxaJ%1Oecz%?I$7xMQ)A6)Y>cqZ#fz%@Sxzh3egxaJG+$LwhOEWtHD z2Y;dD7vP$=ztryS?UHxFHQxgtOFjVCd;~s|dJ@D5{-UruwAN)wk55P5_fS)G$6kPKe`1d701=oBD zeuLy|aLq5kACi3MtL@%2?}9r!nf^U+%?IEwl6)Ur^D+2qC7*z6ehhxJV#AERD{%X#X1pG?z z6#QQC3HVmGm^nH4cH#y2dWV>wuM)g3`5OGK;thB#ZhgDm+o#2CaJ?^w3x0~^J#d}l zgX^3SJeN5U__zo#a|r^HL}jbCQ=YYyHG%zjxHw0lr@h1z6yhl7FJ|LbDAA=t+=W|YcM!Y7zAZ}mS?m@TPCGHdN6OW0Hh);-5 ziI>FZ;7>l)Jf5_^+umPw2Yk&n%EFId&EQH z1L6tsG4Y)EjCf6aLEQfS>K?kped2xMG4T=c3GpfMlK7msb^e>%iH;sNmpyce3sdqd(W@r-yuydvHZ@BFacgRavh z9)SPj4s%=v;Mv*od>Z)L|1|jtczWV?=6i?1FU?JF1@Ve_L%efwdw+GlOT0%sBt9UX z5Fdl@6r1P4a^f@MHTb2cndh|@;O9KkJbti$)b2sOOWY^kCms_Y5uXsB5-*9*iCdSf z-d~5fM?4@N5g!syiD$$M;uZ0Rc<0j9J-Ebs#6#i(;tBCF@tpXKcujmk-2ULdo9F#p;yvOa z@d5FK_?UQ3d`7$`z94S@bafA1;y&>{@tF9C_=NbBcu9Ot-1^z-{dI_Y!~^0H@geb) zct*S+UJ-AIcP?AqgG;bHV0r80Vka$WwBVG`%h&RMLSFi5DCEg<*5+4vxh>wZq#An27;tS&THLH8*68DMs ziO0l8#3#h3#7p9H;?}QL@2^ALBOVZsh!2UU#53Xr@rrmuyz}eTJ-Ebs#6#i(;tBCF z@tpXKcujmk+%8x5&?W8@?-P%SkBCo*Pl=br=fthwtlnRTxJNu79uXfBPl;#53*r^= zhIr@N)jhbxd*JTN&HGV9;sfFd@iFn7_>6c>d;z}3d(7(#_HWxgsCS9`#QVf!;v?b{ z;#1-!@i}qpckTUsjl4eM5ch}SNE;wkZrctN}ZfB)~z`#l=so$J~?Xx=5>BOVeT z5KoAYiRZ*;#B1UU;`a5cd*~APiT8=e#7D#@#HYkd;&bBG?^o}yL);@C5RZrtiKoOf z;sx=FctgBXt?t1k-Xk6o9}rK7kBR5RXT)pb3*z<-t9$4Y_lft3$HYg(C&Z`3OX73l z){U$8*CFl^4~R#^hs0Cj8S#R6MZ6*2xoLF|F7Y1mkobUjLVOIq-`?i^y*cq2@tXL8 zxc!HA54znhai4gfcuagmd_sImyd*v+ZvAof{yM}x;sNo9_>g!?JR@EZufSjN9`kx` zL%j2+b`P3&iT8+y#0SI^;$z}D@fqntp0r7Vi#4F+r_>rGB?_2KN((XasCEg<*5+4vxh>wZq#An27 z;tS&Tt*d+J68DMsiO0l8#3#h3#7p9H@Ew~&AN|;(wE%yuc;~iu4=-HTd_K+r-{uta z`85yxP?_U{>zok$eUgvBH6Me2Nb(8zQ`a)TH^<;FIoo`WF9X+n0q)=Y$L05f&%h(` z61*0#z|+5&IW_o1d=CD1*{=oo&@%mZ{?)&mTqXVw_F1UXFx(B}7<=ZdMhY;M6 z`4RXVuQBgqkHK}$2>f|6XAG`$GH{(!5U+?g;LSfx{|j*UPUF_R-KQ_!0guFO@L1dd z-|!3Oy6O=Rh)2YS#8cuK_+HZg6#QM{Gw{>oJ{2|i(UNb#&lb0CZ}+Kl9Pm^1x&i*P zb8 zy?*sRxb9a5e*4?Z^{OEr+|iz|b0Y99t~bxy4~eJ5GvWpDig-i3^UwDBb)7Ew=oWLG z^uXi$%yrub|A2T1ex!H|{<-}(TI10RcLM&}z0BvxQt+c>&IJ4;;yL&Re>Lkbz>k%D zNxTNveiq=jZGXmc{hd48ea?Sow(Ed@O19etKT*5~uJZ%%&q=-yuK5ADu0J6@CY}?Y z5wD3ah}(Cyd((AxiTmK+lO96wUy4WIcZKJgg*gX>+jd^|Y<|Na+mT>H_V z-xS6N|_&lYkmm+X33AhH9rB5C7*+9eg=M$00pLk4sM0`SgO1vaK2mi}w&F50Bd)qzy_bzk& zalrehndh-R;sNo9_>g!?JR@EZuZTCqJNLDF(EW9Z_lSqY2gDQNW8yjS8Tdgrn(JOo zd_mm4zukk*=@R#e_ld{EN5m(@r^HL*bK=$mtM}I-?tvF0^YaoAkBAS6r^GYj1^7>$ zw>|pn-73NF60gBG+SKH&MZ1Sx#cgoC9=hOflDr50(09!9JOTJwk{^KU{UV0MN5seA zPukjC-*WJe%ligr;F_<&*WS$Z(|~Kf^I*HTfB(R|PUjNu5f8zia-r#M0RDNoU&j!9 zeOc!ST=Qe_K;~rNI%f*5>nXu^`+<3#Zcg0#ce|ep|DG-%2X?{hCz{8r9=hCr)dxRT z_BRCoqId*e%bXZIm-_=J;9rwDDY(v`g2&O-%g5Ulcy#X-ORvGp`;E`Ry$6gp;FrpJ ztpBw8JVhSgI^b(m>HnGh1YP>cz-#dwygbzXG@3X|`K~H{#Yq?cR!Yf4AJP4!GShZi8EoHSU0q^l=gKfOtfF2!58#Pl;#X z?~~&`1^a&JxD9@qxC@?%d*FFyo*(eRH6MasDRUz5T092-r+5PX#C^^Frr`Sca{{i%Yf8KX zuWy&o8#Lj9uprCpAerCFTo#?=OO3B ztu@>G`x<$i;1Kt~zbf~04v0s@hs0Cxcido}7tM$l#4GR<){yrr67Q_l?%|&AoAc8F z*Et^XfOtfFNIV69%tdBB6L4M6lz2&ePTX3%-Gk0|hUi7$xTk8Sr5UTz*Qx!`)8 z?14LS-44JtAA!GAo);PtPl;#53*r^=hInVab`QEvmw1nONPIv%AwDLa6Q2>Ui7$xT z>#y#iOWY^kCms_Y5uXsB5-*9*iCY`2-d~5fM?4@N5g!syiD$$M;uZ0RcxS`aJ-Ebs z#6#i(;tBCF@tpXKcn!XXT(27NK-}7Bbq@}4k9a^lB0eOZ63>Vi#4F+r@y_E`_uvxm z5f6zEh$qCy#B<^^;x)K0f9EcU+jhH$;Rnp$-7ffna{hSWIzJ#D5g!uIz(4xo3zqNq z$iYt*FTwwEw8>ZC_lVcv7jN>7<@^Qst6pGU@30=Vi#4F+r z@y;fzdvJ;Oh=;@n#1rCU;yLjd@tXL8xc#KnJ#>lt#QVf!;v?b{;#1-!@i}qp$*cF* zA?^_mh)2YS#8cuK@q&0oydmCkR`=i%?-37)4~Qqk$Ha5uGvYPz1#x@R)jf2H``~xU z=VN@2_sx0YCf_^Za%fe7$YV=K+22=&j~`$RYR_ zWljYCHSrky6nURa0eGbxsO?x4e!#0oQ(VaGf&)@1JUpdrf>n+}@(ykIv~5_lft3 z$HYg(C&Z`3OX73l)>BsRuS47;9uSX+4~eJ5GvWpDig-i3v*qd@T;e_AA@Kq6g!mZz zO1*A?UoSoduf%8Iw}@BZdY(7LJ6n-{i1&zx#0SI^;$z}D@fq=&_=33YuI`~r+$Y{A z9uprCpAerCFNx2ITU)Q*Ux&CyJRlws9}-WAXT%HQ74e36=c%iEaEbSbhr|cO6Yvk{ z^AE&x;xpnk@da`FY3&~Fl-)F@aP2t) zf1J#T!F4?exUMG!*Y!-mH<$T2xUOeLye7UNZa<^lr_S$!yV@K03&jKQUB&z0FBKnv zYi~nvT~A6pBVG`%h&RML+pg}%CEg<*5+4vxh>yWvE`4U;zk1uL%g;4T!L`ql_?)=a zUEPC2+#?UtdF9`S&9M0`j*C7uy4h*!iL z;+^NL?!hJABOVeT5KoAYiRZ*;#B1UU;`Vl{d*~APiT8=e#7D#@#HYkd;&bBGb64-L zL);@C5RZrtiKoOf;sx=FctgCi{pucE;yvOa@d5FK_?UQ3d`7$`z94RUt9$4Y_lft3 z$HYg(C&Z`3OX73l*7H{HuS47;9uSX+4~eJ5GvWpDig-i3^ZeC4xWs$JL*fJC3Gp%U zocN4*O?*Mze!=Piu6CV+u5T6n+iO-2!FIv67 z4snloKs+KoB%Tt_h!?~w;tlamZ*>nY@gDJz_<(pqd`vtiJ|kWeUl6xnyt;=jai4gf zcuagmd_sImyd*v+Ztb*se;wi;@qlGrr>*v&%pN+ufX3R zJ_pwxtld`k;}G|V2gD=dL*gm%DY(9VIs@1Js);X%+y3evy2O3reeiue^FFJX_=xy~ z_>_1_d`{eYX?uUmTh06V9pWDGfOtfF2>!;)%;yDC;u-ORctyM+-r2p~gRaLV-Xk6o z9}rK7kBR5RXT)pb3*z=3t9$4Y_lft3$HYg(C&Z`3OX73l)}E{P*CFl^4~R#^hs0Cj z8S#R6MZ6*2dD-e7T;e_AA@Kq6g!q_vPJBkZCcYqUzkGEMUE)6RKJl3Ni1>u~lz2&e zPTYFM>iu+- z4_)Fu@jmgG_=xy~_>_1_d`{fjd-eW0#69qf3JGvWpDig-i3^U8J)x*nH!k9bIYKs+HnCZ2V-5$7ZHvre|M#P82Q{ox%f_O!|A>P?{ zbq_A_9`TU)fOtZDOgtw(BVH3<5Vv2wx`!@tpLm~mOngLqLVQZRBt9o@h3)pI}tk4HQp z9uXfBPl;#53*r^=hIr?Ib`QG0F7Y1m5d2R4xd7MsL*gm%41BX^o8vVF*Y63Mf$Mf_ zaQ8Rn^9~KT<~y$?{SfaF4~Y+mC&b6ZbK*1NHSq;;`@q#bbcy@K`^017BjOYA`a*LY zbMPa7CXYYC^*kxTkCS{2ex!U~Y6Jcm$y*1t`#D+M2LIOjr!7B6;DYP<)&oCB<^wZq#An27;tS&T zA**}ng7>d5*OMN&ou~lz0h#mGo1C>wYbW+XK=Aai4gfcuagmd_sImyd*v+ zZvEft{dI_Y!~^0H@geb)ct*S+UJ-AIciy?W2N(SLzcklL4}2eSA6(D3KJl3Ni1>u~ zlz2&e4!-B<=K1*r`0h_O?}xYF)$T{V3;x+{&HXEU;(hRQrMCgN&Pj-m!E2e5fxmW5 z^F3k(@rrmuymMH)2c7Q{?-37)4~Qqk$Ha5uGvYPz1#$cE)jf2H`{3&yZjMWzcuagm zd;xgY5i{0ccAO5$_yi?1|4?+b8!KELzsb`PCjo97!HaNVv4zV;8z`_%*R+hn_a zaLvcWN5m(@r^HL*bK=$!?H+WU4snloKs+KoB%Tt_h!?~w;tlamyt)UMc#n8Ud_X)Q zJ|>Ui7&v{yV@MD&imRuY%T79>v8mm2gD=dBk(eF1*^+sxnfCHVW~@z0#N^}%+Zfy}qT>zB&+8-l-MZS(oN z9`TU)fOtZD41ToqlYvjgXW)AO{5klgl3##pzH?-|pP{_p!vViS<^+KwTAMpkF&i8$B`97A; zu-)5hB=3MRpFJa95U+?g z#5*5u_n_N#iT8+y#0SI^;$z}D@fq=&_=33ok<~qPiTlL+#AD(k;uGRi;wAApaqH;z z{%$($EzetrxJNu79uXfBPl;#53*r^=hIr?rt9x*X_lSqY2gDQNW8yjS8S$FK?kpeemD^&RkbRaPM66_%;InljLLY?hj2q0souiQ*b9U`3d-)lFz~K5ih_W6feQY zTbjp9HTWZvZ@~3&nw7Ns)aT7?aDD%(3% z5l_H%ehU76S^orF^Er6;TV{U?a9vMHyaw0#4S44)>GRljpQlIbw1wi=if4?3$E9P9{85OH|JFV?$1pBeemZ` z&GY9m@e%k5GJg!Nb8_%6OTGZt^P~jVIScT|t!u6`olms;IZx(y!8P9lf3rLf5P)AG zbNb+yiVwhb{UdPa&E`0c!GA7urr?^Nfloecj#mZl%I~Q;_@*y6e=k^{Z1v5d4mxncpKL@E6IPG5B8M8Mw}$g1=hwGw=h&EAZEe&%xg) zz5qX1ymLak=eLVH;OqQZdItYr&)~rq%=>Nn;4hOo1Mq{yhu}IV1^<-fC*Yc&5-*9* ziCdp(_oMS2;vVsUctm_iJSCnHFNjyf8{(Z4SNGr&?-37)55SAe{Qez+YyT-;%!>!j5^IN%?y<>v)FJlgD64_vn!5+4vxh>wZq#An27@XyPBHQ>7b&dIC$ zaf$bchv4VSb|Y}z?vQv&JR@F!-yqv9!F9WH;#Ru42Zy)^{(x-P2iNWPiO0l8#3#h3 z#7p9H;?`$L55zs<0r80Vka$WwBVG`%h&RMLpIhC7OT0%sBt9UX5FZoIiO-1F#23Wv z&#&&GOWY^kCms_Y5uXsB5-*9*iCd?v-d~5fM?4@N5g!syiD$$M;uY}*{E0W4--Fhv zqzB?2@qlzoPr8zrBE zYko$&CcYqUe_?e$UE)6RKJl3Ni1-Bjd4DnIa}NH$9*EcA7s#9j{FagVTtjEv?m^up z-UEN)U(GrLaGeu@e^c@?xaLRTJFI2iCqE%RC0-Jr6SuzD?%_M~xetf9M?3)E?MCxD zNJM-{JSCnHFNjyf8{(bQ+db&|UE)3BA@Kq6g!q_v4*p{~uL^Koe+B+e$0B;J7QcC9b9d(b&HahJG9+y}Q$H_!V; z;JTg|T-TEjPr-Hm1biyJ<>0^jiCIqxuIs76bv+Gn>&v81@K^r9Y}W-(ZZpT%1J~{P z#6#i{@fcjUn}F+fQ{p-J|ISZvol}BW*P0$0aQ(UNe5KvzSEU~ZT#r{5T({c;zgXr3 z;FpT`!FB!sT;~tLM_(}eH3ru?8TeD?=D1J6pCvv6KjFS7F0W%1cqp$UFTi!Xok_b- zUB5#-0N3N&2iG|R;zQyi@E6Jcj=_^FOrII}uG$-T{27z4z;(_XT<0vnGkLw+`D(j2 zoznx?o&#|0r%!x9d`Nr@zWw9P`_eP;gS8*<{eEEH4=@9NpX4iW{dsJ_kCMFgwRS%` z-v-zDF1XI`5f6zEh^OEu$~q_DdR%hiCAc2n8hnGR>b-N+B<|A-jPYka41bpq=&F_U2T>F`TYd<--Znpr>{%nqK z39j>NaGl?P>wN1Q?fy5E_1oZ^iM!y>6!*Y&jt{QAh2Uq%`?4bN!_G0Emx;l3P6DoT zQgF>rz_quWcmb|+N^o6g4X*2Hz;%vwcDw(5_A~c?u)(!Y7hLCf;JRHOT-Oio+d?)c5Tz|hTz+Wx-&N=Pg4itC5b&f|oARZAP5>JU|;CIP7 zr{KEIlK32alRHh%3viudXYGE}yTpCsed00k5%CG}De;o{oVfMP)%)v!A19wH@rVb+ zBjQ8iDe;VWLA)Z~5bu1e-GlD0OT0%sBt8KDkMx-k9}~}s&xqH=7sTyvw|mfac8UAM z`^01LKg;LiM#LxJ*B|uFwIBU}(-izB@dDg_oypI@Hy1C#w-T?ww-K+wuj*X2)}!m0 zgJ-Wd+ik$l6<>gFc)Q74=eGMlNW25Se`E4CczCyQ2mFWsGVX#G;$85|#69q<#e3j? z6!(b-#6$46+;7%706$bb27g$52!6l=W=;bBM)48&IpQh!a~<^C#fC&MEPd_?)=)opzr(-y!aS|Mzv~^(G%&=k&qf zvxa%U_W=B}a$JVs`n?__@Mqj)UZ0&1pMrly=Fh-&PECA4+`h2g+c#yt3x1`1e$xZL zOV2}aT~D8QOne0Xmd~5-Wt)Qk;=|^=D!~6H_iL?)TizpCD&KZIKRpyMr?-0+xb^a7w=g+`(eg*FD zW_q53YoFHl+dXe|k2&9L@FT@t@bkqz@SlkL;JV#D_$xkp%JTKB0r<~l&JbMZq~MRc z&#Zp}uAjfl!6%XFrvP_kP6_Ub*Wmk!H{gehTNkx^9*NuFXNbGt7m0h|SBd-JbMX*d zdmDg1=6=)L5M1*U@TW*V2lvGb@O{KfaLw1?k>sr(w0k>D+y?)!xCefccnGd@BJgiZ zJ_f%+JORI5JOzJ9d;+fd9K86OoQL4&KVXha34WP)4Sub71HQ(>%(15JKGzYq!M7B5 z!JjAYf$t&igC8Ltf_LTf!V!2P`4~JCPrzSwmU$gB1;0h|6Yx-8&&t7dP64jxe?`0j zU+Y2X`G@VEHx;+Rb-OOOCwUJ%5ck3Lb8sQ}|4BXq*ZmrTM|+v`a0Gs$%o&60b~AA6 zeP+%STpt(Bz%P^e6?k^Gd3|aQuIslhZueYVZ1Og^Zr26BU$*Ok|K^M4brT<4=ZD}r zKLTIl-{yRX!8a67z;(aI#B<^^;x+LFar;N@KA$P;bio605Bz_De(+^A30BE;JRNG zxZZbb4zAm^i*}#-{n{?L{vP+hHSdG#{66s*ypa7$z;(`;cnPk5$JOB4e*>=bJ3npr zpzady5f8!j{T>mxzE375o`CC|l=uW(=jY%$rvTS{39dcN!FA38T<=rS`B}S9J%1c< zo$nD3z;(NQa9#fZT-P%M*Y%9Sb^a7w*I9yVz9DX1*6u;q>4EDUA6)YhxUOeNJO%&r z!{+x(4t|Gt0j}@UE5T>-yy%>`_4D@rYThC45f6w*#D~OF;u-ORctyMczf1bGE^qe` z?q%**=72x{5p!I+;F|ZrUoZI(T=N6)SFLHDH%^F;iRZ*;#B1UU;`SBoesrB(;y&>{ z@tF9C_yl|)J?G%M&KdEV_=33o3(^B|AN-4YK7i{w2gDQNW8yjS8S$Fo_a_;C7uy4z?-$q_ij|g8}Mtbw=e&Gx2|dTpmQAXFUkE*J@Bu~ z`>X=u5%D4T`fHf=jKCi+J_gtA=EP^jYvK#y_OIIgbY(p*_$$Oc@UNc#{AJGp_<@q| zgX^3DxXww4kHNnz^E2>E#i!uE5TAkHC|-fF@Z#A!T z)!@E-zf1#ufqahD`c1osBYtB(|6+r$8JW)yy5N_sZH|ivez~|0zVU|U{YxSEFC-s< z-||+o-5C637nm2*q zcK=7p92fkVw)70X;RWV#O8`EVd>>r%G5Fq(H}ey4&5yzVDESOr^9A@3PcZXKaLv!b z*Lb4IFTgc#|F+%RNb)YY=6m3qZ*1lV;F^!Xza{w?T=OIF=WSxq+r4St1^=PsJ#ftj;CnvR%=d<4G1 zGfX}P*Zc@PmHZf7^EtS)t(jkdYrXeKSuHc@M9%E1V2skDfp?9pMaky`6;;j9n;SY{HKzy!OxWW4fyqv@BE?N zTYjc_e~ttGcgcI;Uzhnl__{lomKSMmw?6_QWEUo80y`~t~O!4Hsp34Vg) zYw*J)zW~opHT`$~*zWD)l6S$!-!pj+UGf3=?_@oF@be@egYR&InV*1PCiyY=@5D3k z8^jCne~6dhjrbgVtrwc(z5wrt+ka~J7ER3hUGU8%-vbZC1Mq#tBk*^K$KZ#FkH9}E zJ_bKQJO{s8-nUtRpC$PU{72$*@SllWe{T2l2XPzxHt{a_T05Hld*GT6!5z7tMBwYl zoFVwu;v?{66LZ~|fInCAIrt03XW*|EufY4_4fy-Tt-9TtE8pYefG3jgf`3}v2R}zV z1V3MV06r5Rg8xc91)s`&x+dUr$xp%8dXYK4Gw_YXYw+#F8}Jv2cW!R?_F8cV{LSJX z_=m-P@K1{O!M`m&0KZT?0l!*21;0)_1AkC_3chB~^j3mzDPDs=U3>w)n|S9h?cR15 zcfk)8_rTvF9)KSw-UmNLJO=;1cml5ZG5A#S8Te)51^8dYOYl3y=iuwTSg!xz8;je2 zZTI#(aTk0y@gDf=#RKqz#Uty~yu&lb1AUnt%M-(S239*KwG9}|zjN8&^9uZfSq&k~=2_vQ04Id~!Y8Td`&75FXU z4Y;+l>C?Kk-P;D@4)|W;UGPxc2R~Un1V2-J0DhDB5d0SL6x=)0JpP%0`||s13U0l` z?C%VG9q}4`EAa;W>EfN++P&>6?tt$p?t#BW+y{S~cpv;&@d5ZqJOMvjJOw{jJOiJJ zPr-jBUV=X$UW5Nvd;z}gE~fv^-`c%xC+>nDDDHv3Q9J-YPP`BP8SxnWJn;nlBJnZ! zAH*~8Tg40T^>;PFZ;Op)#y@78kZr|SS?X%D8EI)Vbg8P#1fxlfm06#)J0{^mj z44#XRz;6{FgWoTngZK6@`&)p&QoI8Hu=pJOBysES?S6hNZiD|`ybE5QZ2o@ffjfJe zb%x-t6pz3U79WBiFFpeQviJo2TJaqGX7L&L(_d!RS%Gga-hiJV=a2P|c5equ-T^;R zybJzyaUc9*@euq9@d5a~;zRJqz1-|q3jS>I3HVFIr{IT(&%k5x8vIo82K;RC&K>RE zekJaJ&&56PtzTjG%Lm_0ybpf7_yGJA@dP{ZN`TTenT<7<|ua-Fh_;1Af;C~e#fOmgm z9^VeZ&z1Z4j=;zA{OTAymFsf`{-E49Yzn@P-WLe`PFZIK{^uvk_tkv`jVUoYoX7yQ7z&3W4+9)KS#`98Qlo*99ESMCdxf`3xxOu$bP&%wVUUVxt~ zUV`UxANv~ox6*S1{xg|lHSIosDQ<)RO56qii?|1VpSTbH*nLd@A^4W!5%><`G58+h z3HU+cDfrvOC*Vhm=isM_7vPtQm*87&Ywm+L2jA_LW`7spnz!$6_y1GLyWpDdfd{WL z^8;|rN8tMY;UV~YVsjs`lz0Yy&SB>BL@%KE3^Cy39$-!JR0!LOBk1FoN6w(f;~WR3%Vm(1yc>vnzc&a36R1irO+1g`6e z!FB$K_yl|hnV*B}oEh<&_=327-|F7F#C_s@;xX|N@d@!M_+HY_47@L1fopFK@y`A2 z9^NH$9PsV8Gk@=Q!F9e5{&|@bg6o_JT;~kIFOfMT@ax3K;5sJ;`D}WH}x)YAN;c7{qphK82mxWXW*JIh*!iL;+==uJ?MOwc#n8Ud_X)QJ|>MxKF%KJSILOJ|R8@-&o$aHUrn=SQB3mw;v`w5ck2ic+hFZ#H~l#J?MHI;vVsUctm_iJSCnHFNjyf8{!>n zv&TGofztcbz55mB^JOma9{4NYZN9fU1pnZA=KDSd;7>aKn&tO^#NY>s55d>^w8@Xb z4?OXP<(vulJH#{aS0pAs1K)jr^LgPK{MXXM0=$2`+*f~%c5m0o^8j7qKJh;IVcVGR zQ;3O=h);-5iI>E!HQW2;zy0Cm&vgfUZ*d#^bMk!z{%r@;SUi7$xTk6GPAm$*;7Pdp|*B0eELC0-Jr6Svk`y}u4|k9a^l0)O!l=K0kj z@f6&-z+BHW;sx=FctgCiZo3EFu1mZJ{#&^ZWJr8KJOS6=vt#gM-s&3<{{ z;p46Z z5B^^9i1>hb46fTtz_;$2?T*2tJ1g_J6kPLD@HKZea|&>sGXvLkl;H1K=f>rBEAapG z&HNht`WKtW)pKy2(}3S5`2~2j_8*qpwbyGO_hU9P?tq`Si&>8cexY~|{C#p9L-3F2 zaR>i~%o%`38=1$AL-4PNkHAlm{hENEB3^)>DEm7Dzg@frzgK(?{-dqU_Yhg@xBL8u ztkVX+U)%+^9%uH~1Fw%Y&sY24PupAmt_Odt%!$AsCmw@uA)bH-@_y_T{F#!UfXDKA z)g1i(@0$C-6yQI2;p3O@+bqGSH=F&f!4Hz&8t|Q*QJ0oN;tO!SzS$eL zd(-QW1Fm@wT(5^caJ?S-;Cej_!1X#7g6n$v;Celbz;(_5T(5^QxXvGfYhMZYk#c<= zfqVZlzeiH=Mtlr@hRm6O>-A(xyaa#4w&wYVIr#cJ{$+Wcw>D}Y-?xf)z%}oJd#9M+ zJ6&*Bp6Btv2XA`n@;vW>TkDzUb9``JPXM0CIz#YUybrF&Hv-rB190st24DNM-z|F^ zg0Jx+(`N#{XKa3Nj=+bKPr-M7*~82E8F==(#q#Gj2miYG3_Snmf0lDf@OpUL(kt*! ze8hMS{?IMP7vSke=JB@mxc2#@c?Ud}ybG>#y5PDF4_tqKd*JVv$4fqVDccRebxsJb z=Sd8{-d?7MA$S=WPrzq8ZMi(pN8k^>)SM?N_(L*h48Gp(CO-k!IT`pSlFz|EaMMrC z^&fnl;z4tsfPYT%bMWK;VCHn}_HlpT>&^LTgP;G>pDnlB1wZxG#y#+#y~20^zSX|Q zL-2+!+$dG&yJNW2fe&*`Sm7<~KF z&H9Jnh1};n1^?!QmoIzBz|R-Y!S#8DDfoAO^UCF%3jB_roAuP-kH5y`=inQQH|W=! zISX+8yVZI^`#7q1h}+=0Js1401I+6?A^1Zde3d!>!JmA*S!W79NsZ^=$BUQX?-g&r z-ym*3vAw^0ihJPOiHG1%5|6*L(>6u5(Sk53czb{8{Ii{19BXn}F-ON8smu+ssM9bvV z;Gn-Q^9}eu;tTL6oNFGx*-vU8-{g>6mvbC&&3oWUWb!?9nd5`&Is)*=9%|-<;G2o} z!S&}c0`E$G0IoleG5GpNnf^!MfB%?SPYSO24E#R1e&*mhX9}+CD8N7V^nWb-pMifu zyaYePH-A4?;5w%U|DNRM;Cj8ap4>hk^m^L?*Xykf?#Ok-0oUuT3$EA0F1Q|F4_vRe zJ#am~KKNGhxT_D|xOXpmj=(iP1b4SI`2<|&jKFmrDR^gVGiMC`c<~9i_K<;ZCHWj& zdzga1@IrH*m*B^L-dx8j@Wape=dzy~e4|rMeh&V>>ks&il3#%9dTghCzBTgr!~xfJ zy5PFbF1W7K1J`x-z;&HIxb_%;A91GXCj@`%Zl>n}_@2J;7+lvs1m8>Y3Har|{_pa* zjKKGmde9?d%f9s3BIrR0{q@5n7p-F`*>-e9q@8vlefXg zYZ!OHuamqB{^Ctcz6-vqcnJPd$K?Cq+GhlQ>N8A!0Dii741UhGCO-sUziT`Jx5YE? z%?>pA99-8q1=r(Vfa`Ief$MQE!S%RT;CkGx&D+QKy9b)b)g5qMrwx8r-{c+ed&OPw zt6yjGUGQhV-na+;T=72meQ%MUU+_Ope!aZj4!|EPKi4t1{=5&tZG4XYo8^!_E~{zpEbDl+1a9f+|PZB>E8y|bvoc{9%1q>_`2d< z@EgTF@Lgjwrw6`=cm#g%BPKrp*W(_8e_pOXLvXz=CEy=i(;Tl6_>JNz_@Bk6;2Ugb z<`m%C=M4PX=bC&8{(JEX{DSRGz6RgGGd>4@ytw_8_HjSxLniNl>pETVATjwa_^ZS{ z@cze4z6XAhxDWm#@d0=;Gmm3qa9!sR{8`tSd;-3`_y~NbUzvOgJ{BK?e@VOo|BpUz z13r4mpO)99Ie7OW^Lly%zQ!&lzW`rb+}g5z9G@WG0oOS;_@q*ZExXu}Y>)&4~_$~5$X$G$E2gt!SKLbDN z4VNw-@0H*>rvle?)Zn`QIk>*=-+=4ip$l-GV{O$wf3yb|d>eUQx(oj6Bh7W#2fy<} z#shH8N8p=EegLj>VsKr@5d7aCHrq|W*VpF>!L^?hd{fDf!L^?$_z&do-va!O3(fPE z75F;x`b!P2uct4-2l6_*<+hKPzV7CL>+5bV`2VBp-s7h^#QXn`)7MIaQKwZJBXL+I zGKtfQU_`Lu&t5G&KOXb?-dFy+pO1I0x#pVL!)FdVchU24J@}*5WB6y(`|u-wDesdB{0Hg- zc>OEMr||gK;zRgEeFU%7$MC1^q)rBZmih$#BJ~`8dN$ASDVP;f+h4(46QW5)-Mj~t&kUN}B?ymox;_}1~xEe}42$nn18spDh#(Vry0>8&>v-qZ2cJXac;E39UO!AeN5=45oGhNfPto7AnmS%O zzHofy_{Q8vNk@^_^B=rgW?=E@8{(A2zeEo8{-g^d5 zpDjLzUv!dOe_q3%t;=1(&r)yT@74PYc5u7zAn3K{`E{)m!q@5%{8IH8zEw})e^5{1 z*S@LDe*}Nsd#|&fX9l-EbGY?cz^%^`ZgncS)v4jfKUhBB*YKOZQoMoN{<(vH?dg&a zZ`+>#)lL=f!mUmWw|)ljXK9})-0F2-q(`0QFzr-oad zHGH9eXKmq+`GoxawS!xo@Xy-w{Otdc<@Vt5HN|7N)fvElr{Dia@Q3|QzR!>0c0WZ1 zzq9V=mE$$s>Mr3of2r&zEBNizgWI*|VC&U|Tb~j9M0-6tp24l|1pa&d-k!t%=&90w z1-CwzaO-mgf2{Ty-oCxQ<`LZL_TXRA@9i=CV)YT+`kcV6&m8_t?Xz}#1-H6u`1kbh zxCZ`H_3+5{9PId24{pboVz}i8a68_W!tHq15N^l2MsPb$HHKS18QhNNOyE{0huiU- zDctH8@KFCfgWG*HCEV_#nZxZqnhJiui{<@c0k{2U<@g3}`_&fyBHgdzJG8gEc>=e( z1NceWX9|C;dJeb#XO35J>wf`%t@gijymM50y{v8sKkv=*xzL4Qs6K#O{}cF;N8f#a zd}HQ#2~Yl6?#G$KCr9@7_g_?SyKiCvzv^kP-7mL>+x-_yxYb#~?f#1m{IQ3~@4@ci z|DnIH62|R0oA=;9I$wT&EP)?>b@|<%q2n3+9lG6fxYe1#&(ZuGZu#2rwc}gIJ4d(Y zVD%%%`;MoMj~&k)pE+JRzI42ShtHAYoIAK(-y0m$p2N*G-+|xot;_v>+k-#xOz{~0 zZ~D8t1Nd$yzk@V#eByZF_#A%Co5|l73%LD0;Sz5BG>-2a5AWEXo7L$#o;W^qJac^N zch>GQ^&`S=Z?=D zuN+@G-Z;K$q(U2o-M!Mk~uzw+xt}s zf8BTGc>coi75r9zD(|-qJW=1mZM%2+?fHCHpDz$O-gi88eC&Ac_{{Oj@ulO9<2%R0 zyB&NEJ;xKrhw!VvMXuM)9G^N~I=*mx<@m<&;Mn&1TAy9VW4P@n1II^>PaH2CpF3VV zzIJ>Ix4(~e@R#Z9rGNMKe9Q-MtDC}~@JI4}YzWWPr|>Ipcgp^IT?s$y*kkrShud+0 z3ck2pu7g^@?eF&*ZhxmQ;dUHg1-CkDxE%**;8uSFU;Kw&uLZZ`06VxH2MCU9Zx=fb z(1Cy8{WAX$e(N{u_hHt)Dskbj@!Z-@&bJaIf|}uXpaR_Mami_+jdO`0UH_ z|0nQ9eE<)?BKZ{FQy;<;^$~oiK89!N8NB;dS?&ZrI^}Bn^)29q`V2mLwH#M0;r+k+ z)BSP9IlR6?e&4BrM}IHNUBDa7*Kn(|gl{#!f?NGHe5idk@L2oVz;pF2Jo)KW_H*08 z>rB=wNZR{Va;)5k+kppwg4q9wl=a!>xV>xB3&f)z9I@UtV>;y{7O=y?_UgmHZ4Is+aKi3fUj#@Kn8m zSLzG+R=tLoPmuX6;kEh-9{#oD*YHTaftP2?e!GK*=j;A_Z|u)Y@eVvy58=rLlJC;L zBp$(oFN^o!)@K5*{zdWwcwLL9@ajDAA^g>PTq1{`{#!W?Q^0R@f&LCH{3dsi-?ywC zU&DX@5&6BEE&M~FoWJNC-=4pD1V8D4Ql}5kZ!Et@m%_^n<$YraProKUf>%Gd`u=s4 z!{h2V^7?|O>IJ;HmA<~P09zH@|7b|$KzJ`~NlzaoF^JNMD+rI3#D|q>0S>Fx3_>F9rEj)OV)bE_oo^w@7 z|2=r|WT`)Zm$wuj!-Id3-zUuA$K6P-qn^U=_Iy1K?Dzt1byo1^TzNgN;n6$g_1n-t zFZm5TRo}vkFGzj|-<~fX+_yc?(NereUx~-?=xph;56`|O`2=o#4&bHcQ+TkJIzxD- zp2NR;fB8G5fWK@m$0z6Thh9gHKiBXZ4y4Ws{&oA^*ayyyB1fJeh?q|v2`E4XW zg%>xId;veUBd^D~ImV|bza+XVi0^(p-3r^@$=5`J3m zjQw@375qI~XAKXoC9mHdeA^KZ2JJamz5}oI{}17z*6+e|^$2c%Klb2-=3}`1{n&@U zM!%1Z;2+mHWN^z*9WNbUIKFax<9P6Z_MEMsuH&)e1II`3;uiA0I)O)ri|6n{eG0GD z3wU{i)S1C;y(-6-jyI0)91l-y&-2&1-6Qxh50Lly82(1RZzX|S|3k+!$ES{$jxQWv zIlgf`cwl=D)_))V(I=BlU%`Xp^*OEZQ?$+&Zrd?< z(81@>h1=g>G2HqYI6iWG;&|cs-0>Rz4PDG;C&mE#-7gY@9*+jTs4eBk)V@rmPw z<8#Mr$JdT;9q*iU@Hs?|_Z?3iA3L5qK6AWseCc@O_|Eb0p$DHs&+)|Zq2rn3Q^!lV zeJ)h+r|bJb4Y$vW72Mt*HjW1mJNO*B@aOCO+OgvU$48D&94{Q7J6=1!c6{r2=j8Sr zY<(lg`;MoMj~&k)pE+JRzJxz-F4y}t@KTTK?%=h0_u=h1gtwOC!x7x-^x-S5lfawP z%J&m6BDUpn5vqnpZpvV+I!!6V!AEYv&jNlHcPcRYpvRzG(}aH~IYyl{N(c%tV zXIGQ+5q)^|5P97t@Rj-i-l(T^ecu~9p2P2x%W>=(+~!<4zI42CdiYzBHx3L%e|3GdV9dr@uwKf(LJrI!kzXhWHAeyg}-0;OXh&Tln@? za-US^FWPgfzb5CQLU{N(S#B4es7LVV^^)(wYxNjjyg~APczwEf0#Dy4K7g0%DSWFw zgx7D9IwN@aX7MpRR?pz|>t)Upc=by00$!`n;4AeK9=uBG%;AlC1_4lT_@L(tVa||z^E$5^A z@bBnzu~WF!8N+j}lfkXd6dqhE=a)-(eYyA?Zuy$Nk^GXb^&5DqzJc3vw{Yuw2d{r3 z%MJdrJ^w)a>A>xLN(c`%--X-xln8G1dvKdq3{SOwAD*ixaJwFF08jNgy%hd|f06rz z$MFAppdA04!2d^m3b*~FgxmhMfH&Wk`PXo(vxQfh-@&cV&STr#@x%v7|6RD%kKzBe zme1b-+^%05!7V>=yl{N(ckcj^~cg9IqT-I^Hs~6j)mg&rdcp?2x|dwXvVmJZcw&2Q^-bjO zjt<=N5!|jNc!);y}Jbj@Y-zdpQBPvFh%B|n63?;t*c z+j1w47mm*zuN_}IzID9wWM@9`i(VwxdBu zSv$UUyfb#@;CSEh)bX+7x#Kg(E610PH;(Td5C7)ibLcsqI6ibdbA0M}>G;C&mE#-7 zgTFoa`gR?U9UnM8a(v==;rQI~+VQpHTgN+3IrtnR$NP?_j*lJB9iKT~IlgqfaeU`^ z_|${Xq33ww_|Wmp@u}k_e59ZI3wVBO`TVWn2i^}I-#Xqo<=}IO9Pc}xIzDzhcYNk} z<@gfbd|2+cY8>A=9{yc>4pyhymK&Ee&xTPGQ9KdZmjvSxBZ*Z>EnZm73 z>G;C&mE#-7gUP|?&~-d^eBk)V@rmPw<8#Mr$JdT;9q&Bn;B$x^?>nA4K6X5JeCBxN z_|oyl@tx!0a}Pd;p5uw*L&r16r;eA7FX12ms=SWYaC;qX9q&Bv;OiSX-gi88eC&Ac z_{{Oj@ulMp{OkwF-+epB!+&Vc!SX%F6UT>+XO2%DFCAYvzH)p6e~*4|51!v%U-Pcx zvEu{BM~+Y6ztP{PE#TJA-0|A+wc}gIJ1=O@;k1Y9^&#*Fo+H0w6FWYDpRIL3;;5*Gv;g&DpfBZ06uM%$gIs69iko*E}`5NBS{0eUQHT>vrNc|1m@>}=` znh##s-d>jP!2j*Y@&50@2yXv>48QkLl272a-G`26j?dsH>;2AixYe&6U&9;ia|5^g z9Cwa)^7hWCW3_g0M_yoRE&*9~>BtL~$>IFQ~>lJ74 zSiOX&>T`IeUcqgDTfnE!m(SlN-0~~*@Ze)oe+RdG@S^tiy}s7(!f&n~ z!L3dYeml+g;g(O}_ttz0xBL+PXw8q|me1f%(tHlL{1pBS&ClSLFX6A$di$Q+T1Ti!t2x z!whb9Ch(u=a;I?17w{`JU&1XvhX+T?>u~|Md<{QT^DDUJ*YKNbeha_oWcgj$9o*^! zFKKW0Khrv0_;KnH-0Jk;E4{v`54U^*Z(b|E3z5PtKZGBz{fyz3&)|>Jd=9t#6#it* zm+)t*S8$v20&ewd`17>R3U2u|{B@e&z%9RpzgP3YOWWJm@*Vi6G~b0=K7y|_AHyx* zhhL`o0o?K_e5d&l-11}ip~uMUYXY}?4!?!w3%KQH@L2P6xaBMOv6`>pmS4gjs`)kC z@(p~f`7PY?JNVNy-}%1>-ycHwOEe$Bt$q()YQ7J*d;c7_TYd$<#vS$h8{G06_+gsg!7U%Wti9cj)_e%J zd>4L#=6i6<$MA=1K7m_)0Dpq!hj7b};7`+h2DkhK{z}bH;g&DpAJcpZxBMJ_p5_;D z%h&LWG{1sdehvS*<~MN5Z{h!=`QYX4?QZ!F{91RC{jCePd<4I-=3}_!`|wEf1Gwc= z_~@7NeP9H){1|>atv`WVK8GKt`5F8q^%8D%=I}>regU_94L?=$E4by?@E2=-1GoGZ ze!Av^sk7bTZ`XVmZuKMhKWRROTfPtfsOAT7%ct;K^JDlo)ib!&nZPgC{1k5a0{$D# zmvGC^;n%&hexHY1zJ?#6`4!yqYxwb+-@q-ug+EI3!7H5Y4u7WRyKt)?!C$KR7;gDK z{N0)#z%8G`Kc)FG{Hy92-0Do=-`4yTZutWKbIq4<%g^Dz(fk5#`5Io{P~OK@aLcdZ ze|#6&uQqVYZ{bI3zH?f8yWdAWgj=01{Gpof!7U%d$C^*zmLI@hsQDq>@+0``H9vue zeJ?>V(>#@!UZut^!$4e`Cr1cl@ z(ckEN;FYPIa6A6nhi6Zf`UyN&pTNUY zB%i~3U(@{)9%+6C-)!W$ZzbH0Cs**)<_|BmehshHqt~?OY{#EtxE;Ul!$*Io^MPmT z6L|3VIv=>bpA_&$^E0^ROSl~mui$n(eF2Z3CjHd#L_KsjJcirx_ddMPItjc~ zpTOg%>wMt0z6E@w`5D~uCESkZSMbXAA9#4G&Iewo@8Ib(Bp(#*xh=JR2p?&_3twwK zg4_9m7;fhq`tYsRPvF5brOy&>=NBrtou6313$0VbOZDh=?KvDc9|7;`@$o)9ewOr^ zz!UWnZs#v5c&zmo@J8#@@U43E`gZ?zz9WX)`I0`oc((QrFV!dTWFq+-KGOaRc=KGz z&)}9X;dY*-f@d}#c>X-8U&9Oa9X$F6$p>#}&&~P?;q?n7--TN~g4=nY7;fi{`tZ>U zrG5g>)JwRXC#vA3%?BRjIv;qb9-ZEvgPm83;dWlC53jUN0$2uh&NB6T%D4cj132!zknB7zlN9UJNQ;TcvE}+mHzz|!t0ky|6RD{Be$f{YP*+?;OK7y1n}FmDW$-(d(qo34E)b!w<|K9=u-a%;4643Agj$6+F=M zsS9|a^=o*ezJph9(D|R?%pYEBz6-bhBlv;y^6;+q--oBCOFs#`RG+}JH%dN-ADBNp z*Zd4_{g-gNPN0IvHh*~dCh4b!kJNYY_{}>1w>tBOCz|iVt^Wva*Db_wyY8V6UupdW z9?hiB34E)b!w<|Kp1eis%;4643AgJgD)`9e4-d}J`NKo?9lTTz-sa37UTMAyxBerz zUDpxAC$|5?lebF$3A|9Bz(;SBd=5V_e|V<(8Ql6W;dY%#1-I)|7VzNhI)8YozJo{a zkbLlVXa4Y5^If?0AHnUqml$r>&Gg~5)=%K!JEhMFyiw2L2j&moYJLW{{!6%Bhf~4r zI-UhQFLnO#mHG}|zDwu-4rl)GO7mT~^&i3Qx}X?t*A?~Q$-AYW1YW35;G_3QK8GKe zKRna?3~v3GaJx>ag4=aY3wUs*&L5tt@8Hot>ipm7%pV?Wz6-bhBe-2R6~jAvT}~ff zYyAWs{*&}Mfj8$oboT?e*+=kL||!&mA%csbYkm(Kj*mFBx} z>pz0qb!9QUZ}W#I?~{HKc%eRlkKQl&9DZQ_@J#bFxb0eF7hSMDjWO z!2IEv=4Wv0zl7U$k`>&pvs}P~kLvv4srn8ceN5;79%ugWSo2-D^&i3Qy3H7F*M0Wk zwboDI;m4)V3A|Cy;Rogq-)epaxBg4GT}N8M8-4vQ;Q1$X{_vIh4qkpz=YOU%e|V+& zF5LQ$;C5YW47clI`|#u}=_i2~>J#{AA^9ABVE*t-^E0^hU&8G=+X^1)^_>fN@F|@? zJXPPpqqBAX|LDvg9&5e}xBerzUH2Qqd)j{=UTggX9)4Q-oWL9P9DZQ_@U7-&aO=N> z+jYnl+^%C@!1Hr-{_vH0^iS!^_V|{RCdAmvFnzxq@delRg&klkj=ZTI0( zt@DS+>Jxaap2Pc3mFr;&czmAJpTR9(!tFZn3U1etFW}KJeFv}AgZH=RZ`YHA@c4Y4Kiu*W{J?el@UHgXheu1DKRi~Sz-#rKZr5kR;|p~D zaO=N>+kFHT-0nkIz@sne{Nb^B^nv!A?Y@H;Zuc$p;kDLD;4AeKZucov@R995^e=1w z@Jf9L&%Pr0;Gf&;wYoyCj}76$S0&$tTRwu@eG@T!V*3v~yin>V@JM|EuhesRq4f)R z@-?YHgIm6Y+x;39-0t^Sz|)n~ui+#0=!5M!+x;Ce-0lzQ!?#)|fd^lg<(6=}AEbh> zZ2y55TBnAW>d}YV{oDN`G2HGy>BHl1==Oyt>LuLnH>u!uzsdr>(mFM~QI9^{?*G93 zDR8^Lr4P@(sr|!q^%8FPvsCbSDt#>A;lJws1CP|Bs@=cc{}RIoTE7pkv`zxA)hF=u zThdPsA8GvpzPd>AGq~kTxZQVC!84l=Jil1y125F0kF@7w_vyrNyU(W&kJeH@fye44 z-0thC;HC8sueDAMU#UkQZTD~Y0mblzZD084+uA=oQ!n9m-%tg&`;Hdy;5#~hc&HwI ztlhueXB5NjKBYdq)H(^gQZM0lUs46P`CA4vTf z-0~&d?$4^=nau|t|4`=xPt>DNw&!E_bH#AGAFK~wX`KY#sF!fN|Eq$R);~OJw10T6 z9-Ym97sKs-ygoemvD8oCq51?~s^{?FG+CblUj9Vt z&)}9X;dUQi1-JVE7w}{w^=o*l9(}4kXS?q&hTDCEeR!jF68KiVgxh_B6+F@TEa3T1 zwSRb_9-ZCp-|j1n;X|$8hetot?F*09Gr0YZ+0^mU@rC0n$2X1#pKh%#gY#`)1F)Qk=_1z6CLhn^&@R521&((YIQay&-{ycDec}4apvH7-|^J(vE#Yp zGsi2(myS1ZdmZiI<^ARNCxf~@hvGQ#4t(_kc^*&%Z`6D6)ej{f!;@c&58$bK3jhBf zmvQy~{lU{A+}10D$M@9V;e^|I`T525AG%&!B=+@@53AQ1a8}9056Z1IwN?kK882JS$%YF1cczuQB zWB5wF54Y!~CUC1WfZOv@Q@GV1!i!6#&k;QMFX?j(kJU5yR(%2wu9P}C{PJ7MbB<d;8k+H$%8Bw+DZZ*6G7n>I1md8Nn~odZ!RquJPaGdQo;f~symWlw_{#B(TYd-+_1`17eU6Ob<%eat8QeaPCUC2h!|n5E3QyiFzYjKppJ&?z z{!QC1@ISh{Y{w=1-j6^1D*yWiv4)?Z`3?Lj>N~i7E_5zvZT=icO#5u$Hir$o&^lYV%_00!dw50C!v@B4fLw>krOsr6I%HI9?l(FlG&^&I{d^#XpDdI|sC_vJYY z75vWEl+TMA9^6yrwuVRQ4LrH2W5PBY57=7(_0kKku& zK7(6+0{@uir*O*`@ITx`wr>fy{2YEQt-pX}eaLecL|IvH_xBLu# z%X`WGFo(b9Bl0})+VQpHTgN*Wwzrqnj~wqio;p5uJa>HNc;)!g@y78Te4%she62l) zAE&N+q$`gcJFPhWlcez_BPewR!4p2HjUDctt|0&ewZ@aDvu?f)();a7i?e4m`d zuX0!Er-Gl5eQ)3A0={~ZoY$z~wq4eaZyoP^!`Z%$_Z?3iA3L5qK6AWseCc@O_|Eb0 zn+Kmm&+)|Zq2rn3Q^!lk7mlwS-#8xpYkPg~cDkHb>N*}fK5%^G_{8zT@wwx*<7>ya zj(5Iw@Hs?|_Z?3i&*64lu7un1z&YHG2Uc)99=L$pal9IC%U#0l`@jlrb=GiuKWyMu ze*+)uzqfEZKedBbdfYO&sJ&ehJ$}-G#~+d7oFUxy=bqz<<3qHNc;)yK{_^|CoY!z$ zudU;qwKE6D`*8dFD}iTUkng1_-10;CMcV%uZuty;iRN>-<)`q=9)A7(aq=15@+JIE z=jd@fxaAk{``+M<`}#|`FV1`2qZ@C&>Oegj;?D?`S@QTYdsxyh_%03b%X#U!ErU5^ni9{1+?9 zFW{E1;dVT81-JYf{#Q?u1Gwc=_z~LA2yXc?{3y*&;Fizf$7;TSTYd&VLGyF?hYpqVl{NgFXS{lU zzH$xE-zC?9?BG9n#%24zQ@Y=6Z?D7NDRmE7MfZzGS;xqW=nlIrGe3#_s@Kk*Tzs>_CzlMLm z{Mx?H1|Dla8@Tnkg|Aeu-Z1kvTqfymWlw z_{#B(uY^>9giI!I6iWG;&|cs9Dc&tvj5lcM|@U%3AgoX9N#$}{@~#A={cS_ zK7`jnXaBxBhF|yNa-CT2_zeE>t4N(W`~vkAJiPW<`}d74Jh}cS_8$JQy}s2oCEta= zu(->9{~y4c>wjinXAB>G=!N|zUl!lMEgxLk-j1WMOTGiQd<0LvAo(8LmK(#Z?>;=xTKXP|1I3=@8A>tcW_yI zKiTRWI`Hf z4e<$l`%Up2-h4}Z3ePSUFW{@S_za%ESGk_UML%553oqgE zXFs;z-&XMCbK-0G==0(`c$~}UTKC88?Ot6V?*n~!`ufFwxkLIBKDGA|y#BU)pC7~1 zZ(p+iyFP;_zmog}o~h^X`qz@5!qeY~7w}qr0gpd$j=X;1*5?wQ{ao@Zc&WaIZ~s&B z4ZQg;@eMq^Qat=gd%NUcmiNgn-1>~*#qDLk>cMOE7(Tj#O(c)ux_E*wp z2Dd&Z@ajpD&*6>w6dsQyU%<=16`#Swr-;|^)#B6p?Y@LtpDTFzuaaNGSLzKsy-4yK z`08TuEj(F^cQ@_rp59hGqU-CZ2d@T_kKv7apMIj`6L|e#@c}%3h%r@-ujLmUszo)R*u>ZzAUz8^?F>{L=62-><@-wzo_DDS2P*!VlbE z2`^qDzw6k8+uyS>d}a4n!tL*=1a5T(aQk~Ih1(p)j^~cg;QfJIhgrdI`xZGay>z^B zdt_UyHu8Bifye4O-1;fu zVIXsu!)x^l{zQF0SvuapU+}3r@Aums{H6MO3IDylUCeuqCyo!{iw}19*XfPmEA=t_ zbnP>TKei{Y>zU(~<4gF5wSMFH&hhX++VlDAYsl+8f)YKk)hZ z^Y(T*@c9To@c9To@c9V0eq#86&quheR|2;>1GueM3b*=0c%`4?Be-4PHHIJf{Q>xa z-yeXlJ|o{Na=7icGsl%WHE+?H^g+X`-TTf=Kz-v(~W-N0>bTe{ZS!EJ8Aw!OWq zeg{6)|38FpwSE^K*RtIsc&NuEdhkd+hTG@h0B-NML%6-)j^XycI)U5!a0$2Lz;n1A z2d?0D9C!h@oRM9S3gUHn*MQy(`+=y?TZmw;900Q^ixb<%jT4 z|2=}+{yc_<&yxBX-1g@QUH7*fZu|2TZr_Va_{k^B{iGHA*C$72NipHQbilz-|B8&~^XW!fpTA!L5F9WqW(&mV-yS zKZo#2y$dfUvj0c$@HyfM+|CaU=z4xIh1>bTA>7_iMsPbnIELH%QUjjNu3q^!|DzET8Bt}3xA?|@Qe0#x4(C~jt}733-$Om zJbA8o2DkhK9_znzc&*2Ortst?dVCvhuZtPn>XdMMUCiP3ez<_!`{xpF@3(9C+pZ(? z-@yM-eFy)Ddgqtz?Q*Vq7k+_y5B^nsf9u1qeu`WNJAl9bVe+{!gj;?LxBLV?{)1e{ zJB2@6mpg-Rbh&f*h1&lD9!;eGC48m%HT=5zI~5!F!yh1h?%KbbTF7;r2Qz;PyJ2!4K^Ja9i#iZm**XZgm!LdmYtqtG|Q~^xrFZ zs;}!cyi{-CqnFD2zy{u^Z{aTpWxE8wZg1b0sE6>=)Fb%o)MNNp^?g2pFV$1Heg7H3 z?fXv#x9>kW+`j)5aQpsK!tL*Z3T}U2)NuRzVg;Y+92&TNer@6J(0s6K&wp~UeD4b3 zHqQud^NitVYW)QMKJ^s-pi5-ABlz}G@eKalnY>Tt@cTVi?jI@OmtSALhcDpCv2xzI zh8OBf_~^f7UMsl09@p^IYovYyx7YOsZgsYBdtL9~U)J9h41d$!j^;hb6UT>+XO2%D zFCAaOZ9ZGLZI>O~wo9Pfp|d}F9R#*rI&hn32)E^S;kI2OxYg;wZM(#9tKWw&bbS(d zb$8iM2Jo$V3NP*<`60Z~{cQrbxy|4<=MrxDIo#%4!EHVZc&Yu@aGUcIZgp00oAVm} z#=qD5F&*#xw*9)WeB^lF@iE-iYYMk{7I2&A3~uu*;Wmdk+?HFxZJrCb)v4h&&n4XI zui&Zvdkwe!wt?GzyMfz&yM>p!KkwkSy~5ued^^VQ@gK|giUj_C^%QRRZ4KdH)O-dX z>Gk##cyL|$eT*r*x{;i}E8v!&!EL#7xb=u5Bu5bK5?Kzt# zaH~6jS9-oUh1cpi+~z-p|62Q5I=+Tm-3Fe$Q_nlYbM@};+v{unMDS}}U-qk!;~CuQ zPT-?!OFub0Q?KCG&jS9Z+Rx7M&L7(AWpzV%uJ?&_;f4ADZvCY2W3->b@e*!z=kWSe zxqh#Luhbj3^|OKBPy6WwH{G9Sw(kk%eYn+4;G?h0^#cQVrapmNKRNu-+E4BH3T}1R z@G6vk8hEW9UZuUh)=wAy6zyl|_!w?=GkE z&rg(oLU^H`z^$JF{0-XA)bSbI>X!6-OFwgXs=lV{`*Q=IYd_J|FbDM*ZguNa!$;>zKN&nz zFX7hD9KO+hHjeM$RyVjtdwrWvNk1L1F_*(7xm?v(^&D>fOyS?veoA=yBB?)z+xzVT zUc5x|HQe$`xGi@Lx4s*A{8F7WJW=l+(w?WSZv_8uUEe-DeWcV+;PyV2!lOq?eh9bx z2yV;G;MVs9zS8w4WHB94YntaNE8Eczy@Tr*O*;;kMi{-1^So(NR)=0*}?_a9iIBUh4WT;rT73 z{t9mWH}Lv!$#3A6-@-$$n~hfb=&i|&!Z4tUq#lp3%7g( zx8=rg>$?xnt}68tc&?toZG9*3D|CGec=an;-x=KcpTpDNNWOwwegU`TF5%Yq3LgBo z)L+9x^-kE{F1EfQ{8~4X&+F9j5!~vI;j14@KN-AHFX7hD9DZxHxXRFy}hi@5N>@&aO*RMTb~L1uxGqR zu1|(r|0B5dKY?4HQ@HgxgIhmy_#s!*>r&un>3+L}pQpZtTmKvQ`V(^f%nokr72cpd zfAgN>iQ_}ZGkEeNSzZnw-{3a;^E3r~u3o|i-<03^ui)1I5^nd~HgL=D91m~Uo{w$! z2yWXwhCk#UU*6x(JAgm{XYki+oeKU2^#%M)^&0*u^(Fi>>KpiDck(-^Tln9r@8B<04{p@nj#Kpx{4IL_ zcm)5?yUOpM^x?O-n|K1Z{1E=PeSN+L-0FIjst@3YsSn{+ zCxa)N&*Aq~FX5J7!24g9_w6P8VOnPmAE|HPRwwAT=k`L)hwxXZNAS0)$8f7NfdA^` z>+L^hhwz_joiY5E>JzxtDd6uqOg=YD__c2;+qZ((hsf{7*Kn(|hHoyA`ETG|t-pic zO1*QF_MELw1iz=|V|b#Tz#pid!mZ92{&>w#;LlQ@!r!1igIk>ne&o$$&NaNRzJfnU zy@6Yu9sErF-TTg;wCDL`tulgJRo}s_ zPWY$oIe$>|5&To?G5kXH1a5VP@WI=3p73klLVN+jz`SB`HS4{qL`+lLR8>(9H6$MBWj*POuZ`H3mK ze)swN`HbQ5d&D#Nv-S6Irts?>F8l2a-kk8u{oj=pJUef<_XXVQui!^${RVFN9sHh} z??ml+9(t6#F1m256T=^)brQJchj3f&7=GzYevd1MKTYcw@Si?WzkkB5&I0~Yt+RyN z^BEhsJ)dy{x92l%;r4vS9X!zIGX}S4&)J@z*n!*g8AG@|pRo(KD>i6LGe8w1V z&u8qz?fHxe+@8-kfERN)KAggX|B&a5jNy@b2DkhaUTMC7H+jL^;BVLcwhy;_3jes~C-C$uvfLbQ zb!PDN$?`pL4u6L}CvgS8SeM(tn{UZ-H}K#h@hv=6-@!-f!4d6w{z{J*b>aCPr2ih= z@(KJG+J6eS`HbPWJ3_yQz%5_E@1ywzeD$qg%YF#AI%~(b@Kd#ZaLe|5tWFpHV$Jv9 zpHT0^txgL6#o6*XK6X5JdnD<;D6A$ z4dGTlb9@TVKXm1Oe<m^8JGj*eZ_}RhMDr2c@_qPQH9vqS-<9n?f^WYnue&ka-v4uW z_7Ta?;Ke7zOSpYMT)?f)3Z85IHQefK;r9N}>9yx(9>LGj`NVL`58&U|{1CqSvi#jW zhFhK7@frMgT7M2d`c}HX!H-v8!fm+?Jk|UbZuNuPw&!N`L%7xN!C$EL`*6#r@Y6Lv zg1=8agMU~(hg7=2zn{YZ zUY?gA-;o` z>cNri`Mm7@^4!3#gg-`qmu3vVkLD+E>!)yh?s)C^8h$ff->u`FJGAFx z`N;7;{4Z_)fm@vs{0z-!@b9YUaH}(OymEZ$c;omE9!}(aCOoP=pZMq3*dOQY!Yv=e zS1*(Ir9Ry9DZF{UzK_9exg)ssJ%*P*lRh)J^)rDNFTH&Kew)J^?SBd{HDAE3{tRyO zD&g5i`kcd?o5>t1cygKK7x1n2S;O-i%XKVkcyd)aPSwD->Kk}^b;)nxR=*Rs_mlF% zZ|~cfkN%JY;HcEx+f#c6$8E6PL=u_c=HVLEj)duc=wq0eo}p1 z<{ZJT&mMeqk>q1|q27m=7wh(g$KMtoz)STEUfo{y{|Vf-dk){mlAqGAknfoVJUUwc zu7Ov_h?nr_j^ayrq37dPaO-mouf8C48hCPV@eRDu{1%>_FZmt3QIGD}-tOs5iwpHq0Kb1UFB&l$WtUh0?d_yqAe zyi{Mo<4?-|yoOt!4SaRBH~OsrPNR1%`e1<@bs7BIehhJvY$-h_Btxy%~6t{!EOI6;bAQKIXpW?yn;9C zYx?8leYJsGpBs4gBz=E|+xzDZUTQwLb9?*7W2w`Dm+CP*J5P^4!0kC}2|W0s#fq^Ypn$rQ-|7SMcOmIbXJc7wTJhc_+zt?$Vxft=@wN7s_#} z0X%-3e$RyGj~5@plP8Ez;PEZw^*e(XAClM00>1iZ@fv=wo*ds;!FSJ*ii@4R?pie@KTSX4&ZiO$_V~n7s=l#6Zo(HOt$Y7Zut^^$n7Lw!Edf!!*8j+g5O!a zf!lI-@a*|=+^=)D_S`HVIo^lgOP4!2;*Zd4_`O5Jnywo~txYgOh z&(?f!?7`>Lbv%ZDTk9lnTka4Z-Cp*GG2HSwys!BJZuvRLF}%|ADFb+|p2FkBJ7v4mPm=Fx6L|Dc@fp0nmv{-!6Y)9xdT*5T zgSF#p$G47m?$Ms7)sGzS!-HqY_qr5bzCgbp!dIHl;NdeRKY=&;JL-kwbNCak(DN*g zuN~hy-nnOcK2|?+yzhAG_}KB>@tNb5;|;v}waj?~uhqBkU?=&`z1njK)kFA|nOqOk zgC`%C*JDEeg!lk%bw+TzE_wpreopG-@HCR=(oW%4zjS=z_{#B(<3ZA%n=Q8s|D}Eo z_TV4=BYB=nAAW-)<#T)hKT3TFKj|!ap34|+^(XK^U%v%B8_M4=Gq~j|c=ia%FX&pQ zhFc#?c=R7~9%KcN)z@%4zu&+U&2Qj#et!$M?bW&W!M9`Nc;E39{vF+3BlyvGknNkn z@1dTIpB%w$Kc6^WI6im0c6<$gq3+Kc`1{p&@bvrT{(Dz&pZ4~(>s~sJhmLpQ zw!9wvlvCvI@x<|=>zwf*DK8If!$UJL!sIR*&XTLe#af9t_l?>Tv2Cx-vv>T-YU!10me6UPh3=Z@EouN~hy-Wjy#X6qF>-gi88 zeC&Ac_{{Oj@ulO9<2%R02ONA3J;xJx_2zhg-O&*K6@A@};g-)GpE+JRzI42CeCK$0 zVtWqOXV3A(@uB0H<5R~=#~1MH9WC!~OStvlIKFc{e4sN2#}mhgj%V<`_MgLhC(3nY zGsi2(m+;T%@BTH8?;H;w)SiRY={cS_K6E^DeCl}V_`>m(;~U3=2OoTWyN<_>4;&vk zK5@KoeC~Md_}cNU-OL_w-|2o>BDXQ3Eb)o;5Pph9-S@6f5!0mT=5KU`6;|ONAd;S z>dfHQM+pyWsWXRf)hoFDUB7?_=SiI!ZhzM=;fEe0-)GkF+p2HiU((+-+QIF(NBGe8 zeqzTxx^O%05y9=aM-OhtJz}^Wm*~T7J_+28dko+YxOa9gh#-0GBYTdz6X>R0gMQt5L6x8ue&+>RSB;db131us7=`{x>N ze-CaQ?>wx%U)k$1g4^q*2e*6zx7Y6gZm-`IZm-`V++M#Uxb-uJ+jh+0_WGT`Z9C?4 zeSet3JNoYe-stAGH1xXq!UYkmf|`XxNlf6w7fBip5-Un;(!UnX9| z>&wNL@E_{++YS6NKbGr_x9}UBCmuYaz5l$rC->2Z@H@R%o`Vp1P9f+BxD|xaB*;_MCsB`4DdT9{fR?kKwl5KHU0F;Lp)I z1Gx2*!tHnIhj6Pig4^%XkKtB7gWJ3&@Ly`5IsCHE$egF}mz=Bn3Hz(-0Ea->th06X`LK?x%w1t`(XjUQu8yo z?S~8aJHIIX*YLV0=K+`S*XL^*Hbpe#QSs*L{aSOjnB^ zkGtRsODkR=C}}0;m6-9`=25Fb?OQHv1^GR!7oxz;g_gS;afgd@)U5Za|Zw9 z<0QU>e^z}CKm9<7ui$@GU%>yS?!BNnzVXu}PYZ5!`f#hW4YxW2xYgN#Tb*6F)j5D4 zzLYv+xYap?+x$%6Ha|yjo1ZD%=I0o0^Rs~O{a2}T2Dds(xXsTw+~#KmxB0n%+x)EI zHa}Z0Y>xX|{#UnOxYgN)PcGN(7k-g?2mX?eOMDkzs`ubuR*&Jw%q7o|uKUjfZsR_J z+qkE28}~8X#yx}ExX<99+e5~^gj+x7@b5ib;w$(M)fe!KA0hEI{9o!z_#O9>c>nO` zxPNgV-iBM90sQL2B)$Xxs(KfG`U@n!2mgb52>*-v5dNt9OP&O7b&lXq-BIFG_@U}! z_XGI_c{EvKa=@W!L7~(+_s|{ZrjlkZrjlcZrjlsZrf21H^+Uudr6%gxYgN(+x+ao zZGMJuo1cBS&CdvK^K%6M{O4qzr*Nxt47cM^2DjtU1a8Np9B#*>Dcp`n75t|Q-G1R# zXAR%xN4ovO+v+R$ztz|9!+$J!ycaje_oeC`_$?Pod>3wY_Taz0Na92IAJqHsAH7H7 zBlvz7ix1$TdJ4a3cln$#x?Bmj z&+l`%<*DHI`F#Pm>y0b8eSU1cq&bc^-{Uo#^$p&A_@=V}Q(dFiF%QJ;ro)VruQPyh?w>%a6_#GvF34gu% z3VzD3WPR80C#d@`ZI0v9)!T5(6TrXye5t1g|B-qKw{h>ohrd5Z-jfKo`zVHRiyy%| z`^k0nG2HS@;7{9Le!pBeeD3fXUjJR5zp;XU=GM1w*2{ZYv(MjnlYGD6!*9DT4ZrQW zH2k*f((v1^OT+DYavyHjjU%}2PX=(y6T@wPGKBwB$7KZni;WjNc#MqW1RfUhy+#4I z{qP)a`{4?1`{4!L_QN&Y_Mc0*?T1%z>)RS`dAyf5=Y#dF1-JY@eD+5Tw}} z+x;gUxZQu!h5sOz<5v%E{f`_zba?9UiNgzr&mCSneC=@m70v$JdUYHgI(*>p#NlIy z=MJAaymI)`;od86e|_5y?>fBi@Yvxahi49-I=poF0{+LR{cUqzv4Y?9cDY`?hTrK_ zac|h{&l}ZS@Sm&u@I&7rdD`%wzEeDaKjk#>4*XZAi+ACNo*~|Y@0N*&@MG2c@E@v2 z@Xnc%X8=D=J%)cneF)$GEXk9=GxZVtX7v>Q*s~?i7=EdG2LF@#1pfJRBu@_C;#~15 z{0-^_{2S^s_+IBpo)Uht`W)_^FYy)p5cLK87WEo_hMJ-y)wYJMdk9Bzd}U%hQKjo*4eEXG)$S-14OG zqtBIkCh+?mEO~Oc<(a`PPX+%@Px36_mS+XGJgxt3_HCtg`f$tBfm@yszFkM^>BB8g z47WTZ_}SY^o)m6*CU6_C0{-AFCC?0Qc`CSV7fbl=|CT%}xaDcRs@YGgCx9<)e!?wJ z2>;wK^*RasuD=qG;g)9vw?1d^ZN8)P6K;75_?y2Z@pJg)>J{AbEa5wRNb-2EZuafa z&xp6+mM4H)o*w+=nm>eFo&ntUV+s5Xx_=wNEzcDG=|^3$+0Pg7Kk0KM=J57T^0~N% z*C(91$+LueCyKA&k@^}Qt9!3$_Su%(c6is}eTT;mA2~dOKR}=VHib`*lJ^~#@ZwoV zZ~C)<*R5kVUc;L%J8$1Cw+HvWD;~oAzKr7l z-aSM-hFkmyUOhwNQ@F)X;N62IKBwz)r*NygpzCsHaI2?;+kNJ9y5_0icAxnIZux6? ztbZ@z$unhrSMcar;%m77Y;iAX&WGqZ;w`wnPdR|w`;!R>v@A>7_~ z+=tuylq0ykPk8{hKF4s&KZM)+loPnUPk98l_bI1vd!Of?ub<6Zej8j(c^({Wf`8@bbO)*|-mn%kOW#M`$}daCir9`{&T% z1BWLLAH#3iU$6VY?|iiUez|~ObiqEG=RC~emF^EKxIMRO;qcnwOSmm>4d4DOd49Ej zOmn=p zp2O=CB!3An)oXaJ?j6^xKUELlv3f{<(#f0kjp2#*A%#ckIowk(;nhj9UNt<|K6uAB z>yP)9dIESc)c(Ws7l_C3`U$V!tk)2}+EUIdQh2nr_!w^SIo#V;;-_$nFX7=mBz_LJ zRH0=d|(Clwf;5Sj#J(V&2h2(E%;df--jofzYX{ABlQRHO1%Rw z+Y;Y}+k3?NaC?tf1h@By4dA)%S4Z&R&ad6fpA;UdkKy_IMf z3D4B$@YN^(XA@t+qfd!1;IVoQPt=!itKU1ZIqp_}3m)ov`S4P`4X@M#c&*-n+k4zX zc%}294-fAr^CW`D+lwdg@C~xx7{Tp%p&2~+lbkOV@VF)CMKgFc+Cjz(o;_r|@ddoR zlgzgjyi)f^&2b5If7^yX_C$GZSQqZyDt+j|`5d0;`xdA0RK0-P^JZso%TvPbd9!nP zJ^F_Heg}SJPu{DzgzvnM_zFI~X2;EXt>Kqwy!YDXeDK!tyn+_o_WwTI*Z4Nv_WwP2 zrl0pic-OySv%YPSxNS!rcyg2MS3|ldpDX)tdro@JQ+>0dL!kO9yV-V;64QV-IfiMDS>T$v>dm{t9k&4&hd30=GIxaH}(g zTOY@8@3B&62G1U;pJ(CSM~N43tA7U1_L2CKuAd|3@MJ%Uui#eC5?+5tjteWe)wzaS zo!;x4^T+CJ(X~z=ZgsZd*2e%|=z4YF{vYMMB81oKefUZ}f_s0GJOj9Gk1^cW_#s{M zr|>|147WNnxYapYT!@&H~=izi043*QgRWO^jkR} zuHm)DFX8E~l4k{9skh(IoQLJZ<@?P5Ztvmk!2P`?z6%f4d+@lY-=D(0eZ~9mL_LAW z$4dMNZv9N*$w=bIaH}(e=NdnOhp&@7IlNGx!=vBI^^gi~{anCTg2OH%dQKxQ+W5 z?tNAIkio5=6L?qSb9i~J|*NIo~{EaeC7I3SxhKHv}{1Wc%E9Z49c%t!Zc>Q+C zObmUAWcRgRhQ~_z)g$rJtwZK_c-HJU>Q!0QZj-PvNVxbD=ehQD?BVNEu^#$C!yY!)kTb)a|uYFs=t)FXny|v``-qal5 zcsubHyi)JN(@f@74{mja@a#N^@54*=2p&%)egLoEB_6}03&qFqxH@?=KQp-1If0ko zllUCIQlG-Z?@N3E&we02gL^*|uj!AJ`j>F4a|N&Vk@z*-ws-H%&GF6lllT_gJ3!or zC+aYUI&^MlQG;2hpPR^q4d z`t`CuDd4fj&)}=$B~J;DPY_?i!?()*VFkDS=bHWwiTB>p9ADdxTJT8YeRy@6q^x;`5`P=Z|&Ef$( zQ}4s0U&y#eaO>xQeyNTx+{S$fk2F4k=O2(fBe;K=cn(iKB-a6^aI3R`+j+5>x$mnn&WGAw&2wr<+$v_?L4Fn_wFR|0X)5ncn7{xkKp$G z@(^y{FDG#OUFQgH@1soNr9CGWUa4nr`yOfnw>&xAzK1H|;cIj|h2P<5x&Nwm_!@5a zmHDSM$I-mw@X+A{_$!{X-{$_hG5j58$>*I6UaL>wtFt9OhkIX<^Z6M(J^Klp{dNhr z_yxQ>mpnDx@+{$2#|m!axTasLpGU^cKHGd~!7YyuxB1Y8N4npL;GUj8B=GL{?;?Sxdf(az9(8ZsoEK$q z|1Wai`ve}JrtcYqCoh%nXQyx*mjWIfb*IgIo55{-OSt8k!)<(*biJ={1%KRb@_lRT z)MlUm{3Q9Ed*JXM{BV7aLFDiueBYMrXHxiC2gv=m8QkJac&hWEhG#d*eKJe9{XW8b zM{|Ac_Yp0)zm42Sz`;U?M3LdL3;NATtzJ`bDOL(llf?J>0aJ!%1e`j+(+x`4)c=kl8CxDmg9eDRi z65oYa>OFYgm-rA~9W365$4?fI;D!1C?mb1~V|b-Lga=QR_yiuRkKpwW3PCw&H1p}L#}VM>3fO?@Zdn{TaW&D z@euAEDn6h;Lp+8@50T}L;PLL_DP6~F0#BYM`Ez)v`>Po|x}WUdO1Sq!>DvPC|46)s zr@Ec4;n@LFk9T^r|4-NF#}%bNEVq3h(~m&YOA)c&xuan!^+OT@u{#Ea2r;$8Ykl;FbCs z9+Zo*^$>p0ljVFhg1<^VhNtQY{6h5!#uxDasF!g6DN=t0 z@2J=CP<;h|jk zd>8c?{&4jK{(AKkex7;;|AcxDuha|pP3k2)xkR?33ckZ3vR*a(k?Je>bJe}GoBcmd z-G`r{9>CwH-i4RjNu42luJIAP9ZCH$d}s9pzQ1}3KTJJ?m-pBG4?HP{^ zc%@#!|DayO?|i7N*9v|=b?=;J{~w|5!=J7mz>iSx!r!bO!at}U!Q(@vKQa6&jZfgU zdJ6xOdIsO(8PbOwzKePRf1G*=f0=p(Pt|MqN7PsF(HrzVU*|Ua|9Oq~;rDo^)E~fK zsNRJitscV9Rgd5wQIFwYRZrl5R8QgmP|x5GdY1Md{v`DR{(SWk{yy~z{^Wh-`J6R; zuJJ4QpVYncn*G1Sv!zZSen0g9K6;ysV;6pa#)t5is7LT))noW6>IwY4>M8vH)HC=m z)N}ZqpCjvAz;{5Y z>LvV8^$LE3dJX>{^%eXQb?<^^|F2T_;lET5;A{0R{6UAw`iAg>)Fb$@>M{Hj^#p!} zdJ6xidIsO>1=@f3gVhW8Gt^7?E7dFb>(y)cht*f`@2Gq4YWDvR>OQ>nLa9H1KUlpB zf1Y{>KT17LL6c>Jj{6^%(v+^#uMc^%VYl^$dR3Sm!_d zq3Q+vAoUV{oO%U+hk6aq)mQMV)xCE&`~PEgAO1V_0KWZ;WxcxahpUJ1XR1f=qt#>h zd(;#7|Ej0(zo}>Nd%Q&Z4?p2k;syL+8ehVntzN-TP_N-os_W!5qK0Mw_ zkH7H0YkU{J)k|f)Lij_~Blt_zWBAGH3H)8^DSWP;!T;-J+JE@2>IM7|^%8!xdIkTq zdJW&=<+9urd6=}@B2!rzlJ|leFcA^x_5E2|G|MW&wY6BU2+@=;74noF8rP9 zA^bA+2)M4AG^$h+3^&EbjdI3LIy@Y>Ay@KDOUc>KwgwB8Xqtv~; z+5f(}53jd6U~^wt06$0LyYLUHhw!hcNAO>($MAouC-Ci$l=VvCk5JFxk$Mh4O1*%e ztzN=Eu3o{fQLo`!{I~WW{wQ_tz0Lj~s_w&&QxD)DQ18M&qaMP4rXIl`^eU+{h997w zz+a}G!mm`%;I(=Vze&A--}Ti}PYHjhdIf)udJTV#`U-xPx_3#l|36jt;Y;-Zez(_1 zon82Y)I)gs5!sJL@clJDhCfd|fqy_fh2N;2!M8X{>dfH}Q!n5Lsh9A9dIf)*dJX@u z`U?Ilb?<%6{@*E)I(_)P)dToL)w}ReJ%m47J%Z=zG5jj^1paIF6n?j(rTz^52=yHP zEcF6DR4?HtsaNoG)NA-$eFeWk-Mh5e|GOWf{fFAZc-i05f9>U+O9>FhEkKrFz zPvCbrR_aXQ_fyZ{hpXrCW7G@y&HKppLvU{^$LE5 zdJX@g`U)O>NcO|t2b%r=s>b{9o7DsOV^5I!yYT0#hwzbl1iwT*hJR8$fqz>)g{K`k zf6m~)*Z3TMuM@TZ@Q16H@HePe@So}SQo|=2zk+{Q-Mg&W|8J`M@V}}D@cWLm|M17E zhwx{rNARQ6WB5DO6ZreoQ+U3I_8(qqd=CG;dI7)VYh}Gk`1a}*d{6Zn{zUZ^e4_46 zoBjWix)1-6dI0~OdKZ3+dI;b8b+TR&{L$(${0-^}e4?JhuTsz8zg5rS|4=XB_dZGc z4}XYy1%JGH4X+<4^I-))Oyj)|Hv2zP_u=QN2k;N7ci~s5hwz`NNARV348PC+NFNe- zte(Q(ub#oLSI^=9RxjXBI$8SGJ~IQ0U4ntBQUU-b(9RrMPF8}$|Z zZmIVF!_EHhsqVuMQV-zIQSZWEr5?gBRgd6*Qjg(VzESE-;Jd4*@B`E{_-X1n{6p#m z{4eSy{LyccdMfzS)NA;O>MQu^>fT41{ePdj5C6J)0ROpq7k;yP2yeex>W|>NtHiFyowqk00rPCbP$)ie0EZn2vpH=rh*6e?!?!$kn9>B|c=>8vmtHy`$El<(;58p#QhCf9;fxlQig}+WcgP*3J z!*lfl{yp^)zS~&pui%eWui>v$U%^v#?|+;9pQ`)t&#MRUU#NHC|56X(+rM4=4}ZLR z41a}s0zXYXg?~{!ga1T5hyO>tfbVds)LFuN>J|Kz>NWf%^%XqWM&_+oH2Z&s#{2NP zEAavR;~L+E|3f{5-}4>XfA}8iF+BXJEH{Dgukk7TQ1uM{di5MWQ!n7D-k({*f2Hvi z{J!s$^{U~IQeVLjQ}-@!_WynAKKu{r0eqX&WVv1Vf$Aar2=xg5HuV_(E%gNc2lW)b z<>^vS27i!x4u6Jv0UxQC@Ke+)c&=Wb=jz_aoBjW-x)0y>3|X%LzMFa%{zUZ< z{!;Y_eu{bwpQV?0q?7q@OP_M@It+Y|5|+oPxXEV?}}#s z|D*9fymO}ZAO1M?F8pxy5dLQM2>xF682&}|1pY(y6n>YpbpFG4R?p!FsTc5}dI>*8 zy@Fq%UcH+-4>RtG2)I<1KJ%WEwJ%(SQp1>FCDf|!W z8T>!$IehzbbpFF%u3o}luU^5gRj=VcQD4DtR`)*9?EgXMYX9LcRuAAGQSZV(tscVf zc%I~s;5(|v@B`Ho_z~(U{7vc^{9^SS{w4JS{!{f5zWw=9e+7S-dJR8NeFcA|y7$Ru z|4&o*;g_ff@Xx7t;eS>S;rEzm|KSf%kKqTXC-C~-a$c0ekJR_>O&ngppQrgtxaCl|&uIM6;iSwub-d&hmb!wZr{SH~VAp9fyYwA2>X5_}JmO!)NfP7xG-M3U2i;;di(|_A_hv zp6ad7H2d&K^)}q{cOBk`pL1|;bDvo3@R7qahff_|I(*^qmBU+~ZT7+H58y{?f4Xps z?>jtp_{iaz!>90E>zTo=p331%hkIAuejnNn?>fBi@EAVTc`|Z%=J2V*ONTEUzH)f$ z|C)WUIs=FI93DA*=}5K8qY~eVaMFa`@8WUU~cD(uUvV-Eti4z^$GT z{xpq`;ICDW;g)9v&ozDwxA+`B*Z2Z{qk0Lq^T~z7R}OD|q1iXf6F9u*@W|mqho=so zIJ|K9+~GCco?K!kQ+@2@dhTC&!1GqhxvIDm~UAR4$vIn>P zA-s6IyeG5|_imK;W=8O?`T)LCkKyT!@_eTu+~!Z}@QK3VnWjpo0(j2c; zpGVz-hrheS=K7=$Uum8;+{V4@@V>)i`08PDydJ^RJ;YPEEq4OXcar!59tYwxcy|Z! z3SO%(;I`bA!&~!apDjLccn@yRpO4_BJ|BJnxA+8Z&#NE7?RoVn+@4oIhTHti=vvPN zZu2~cTb?Q0=6M0P^_{_c`gaMhw4OOUy-vz{4-;uN`Gt^=Q*EZ&1(f9O`5=l}HKUwM{z4FAYQ^7%1=|6Y9zzw>(}egZ#G zy?{Soy@X$+UcsYs$IW}^7x2$$eEZsF-^@F3%iD!#zn9PTJ$SA@gj+ocd~WOO@Dgr$ z=kV1+>Z#z~55&Fen(J%zwBX;@dio9@z%6eK@9J||hwxB+0=If{cu~psceTS;aLc=f zCs%48zSitRs@{cLJw5o%+Mkib$8gJ=!B;PndM0r1<>GU=)lKVcxru9r6K7(7{5?-7y*9qtFQhg1#dc1Em`*5Jv6FNMCTiyXY zK1u3{;fZ<%w|XYwZ)w|zp_TkPimFKzj;8te{f4SB+WI&uKkFhmYWvH-%^VeETsxSD(SHKPCJJT95bbX8qK zeg)6l@Ly?s4zF9sZm!o&;j#WbgBM#! zdXF-yMSBWHQc+qUYw%iPEbx+`)C;iFczWM^*)Ag$1)`unhAdUBa(Cl-j--ou~mHvMl zUfd*o2;dgqf!lI>aH~6nM}L+4eR!-sg4_D0@L1Qkba(}~ybE~wGpVPBSL*%`oBgzU z+VGQY9y)vox4a2Fez?vGU$rEE1-J8%8Xj*c@k_YHui&;^??=tP z-Bvf;ySwD~;l6qZxApDAKc?$DcK8Htd2@LEJh{Jm3SX($@XzV>*d^TRT*1Gjb+&%o z>`xHMa((zh|3837he~`0Zt-2XEjNT)-Fs~IYaSn7s<+|xy=MTgG`<73?>+nQ?x)+E^Z6lsrFjy##gFLvcM1;%(&sTeRL|hS zfBvu;uL(TT_#B@5H*DgkaKA6hE#cjR#pm=xbUwhtqh$OR^k+zX4X@Ofa2u}`UE|kq z8!zwY&G}>Z$F?2bb$H+5vBO6W&m2B=c^Qonyp;lH{>J{MBm zk+}b>=K3zw+i<&|DuCAq%6-2b_|bR$;byn=^x?nJ_y}(K z2XOE4QfCam;W9nm!R>yk1a9|Jjo=TTN}d${h*M;}Ch(U&`WKu23o)R9M zDn5tLUnJ{W!M!biuvzW`ZuQjgRO?*AYxNb}#$^q+{NAsd^X;~N!S8(DcQU=bFcd z+k9@rEq?&Fes$pAd6Vpyy71rXa(nPcujThIA$;f6wVVB0AAZV}GLA94y8kyf@k6*B z$5Xf+$H(yCZ9m!M$>7I)Tjvk_)>Pti_&?RB@Grbk;tTjrZxWxucTun5`@UY{mvF0d z1-ClaaI4c>Hs_Dk*@9c0KHTc;!H=6sogv)n?8EoDQsN`{0qO(zojxJ)G5p2qL-;Gy zGx&>6mpl`=)tSTpl1cm&ev5hm|LmC(KZD=@Eb$T^s4w9iPvTc_t8)#%-yJ31`(1N< zcT{h|f2r=nAAcvw(}wreL-_vplK4K{>Wtu@@+E!%ze+uZpRtw158*edC-AlU1fCuu zd2+bbIfZX~v+M^7`2Eyp@Sm!e@B?mTJQkbG^j-@P&FCe$n?OK7jvAy#v4F zLgFKOM|=RcI%Bx?a|pM7CUEQL2yXpM;nvS7{MyG!odw+LoWZYqyu_FAN_`GL_aKR{ z;5Vx;;D1;5{?HuXYj%`8Ex6U`!>ylfxb-uDTR%H+>t`2k{T#se{-tb3G2H4L!h>H+ zd;;H9eFVQjJ%vB{HxZZhsn76aI3QozwU(+AHXa14*cB1CB6&4S-l7UyLt@2;q#Jb2)8;D`0ihl_z}FT zp2BZdAH$!0wdBd*&sU$p4|}eRO9j9F6*^wwI#Cv~g zj{A4jTkyS)ka!<{wt5@>XY~M{A1Qe{@b{~C;h$3P!SAS_qeJ+cFL>(a^ZNk)r4P#I z{TTi&^&$Lb^#uN@4@sU8eESdUbw&7f>SOpvKO*rNe20&UPv9?C&*2|cpTZCSnB*zo z7pTwRm#UX=>+>9bnD)PhAFsZIpK_(t-Wp|6gAx9*YF!p(d~ED?Eisd@iyG@bm1?0tHk%=*Q-Zx%QJ)@^hU{(!moI<_!w?^ za=7K0!9T0{OSt7(z>DG$n?A1`-ug?kZx$cGzhlo!ba>?Op~F-7oAf&81b(J^4!3${ z4zC=(bhvk8vk#WP?eMO{`woxcc71*Xx9jsM+^)}$;T^pmox$z8`UGy*&vUq4&z!<7 zPXV{ENC3jWte$$qAFQ*&Hi@@R1%Zu7PSf1`f?7{V9oefSS{ zk^C_{+*N!Cx8=!{@U#4=hRzp zoBsj)^0!N#9{eWt5PqjqCB6@Tqk07Yx%vQp=sP4&4FBmn#fR{xoF<;Ye|5U}2!7}p z;wgN$OneMKRy~9NP<;aLoGE#7_;Kn}_&3xG`2J@}o*6t-FX1<<&*6_fTk=%!OVtNKzJ%ZV19E;)p3%Fd zIWC2I3vPJ=_;&hzXb=7g{oXT#Tb=>@K}SeE3H-V55Ff#9xf%S;TF(S-%Prux+&TPY zt*3(D_a$;1T*5!CzJl9wTemj*Y;ju*|)Pae+zDT0=V_32mez!GleI2kvs+5^336ur-r{}E%RXsw>;k8n*FpqZTJI!FL?sE<>|qH z_d|(~;QRkb=O^6qB=En#TjIy?XIvzn!7a}ee#|w}&k}x%`W$X~YKO1k^WVzz5WK%P z`?Lr`d71`=cxN|i|@ey zuJK*C#rNSyX?z5? z@dfcI{KM)6{NSr4eg^;iSHvs$)AqVvcvQo$zV%0&_$B!F&L4ZecN=c;UHBajko!e@aLW_It&Tq2t{+D5BSOhPfLkA8xaAqbtq%!&-_|2H z*S*K^BlWnD!;iJ&1>C;xDBx%A+TG-zJG_QJWs5U5+wU5F#J1v|C+}-&ZL)gaz8{s( z=|22~zdU9W(SdjGFL^@vF1v{L;g%d8Y|Wp-Ezbmg`3|z&0)CD94Bp#O;!F7H z>T~!H)GPQlJ4v1e{1^Yw<1+mI{}f-tZN2HfuF6O!!6GYerX_iD)=?(3%KQ3!EL=-cWm~ptK;IsEl&sj`D5j{ z8N!Qwq(6Q5*1L;Ga62y=!tJ~$f!le}2yW*^DcsIy#_-$DTi~{To4_qk4!8Z=6#jo7 zll{XC{wD9D>L7@NaAU0&ek3_)_E7aEouZ%wxA-~y!a~+}0k`-iywLbH+~QkzZuZ}f z;{n``vmLm_hj2UY_u+QjkKlIPAHeN+9mB1jA>6i$1a5goaN90YxaA+iTl#kfKT*#^ zCUAQ{NDjC6gG}M?{f3-(74X~66C7T{N0-YyS;0?L_wLdhcZ>Jo=V^QozWb$j+dQ8$ zgm=~Z4j;l#K2h={@YB^Z_{aXS-kkqT;Gb8|;k*1(;%9LCoK?abo%a6-E8N)3;hhOt{ zId7afymI&we#RAh${Fh2n*Di_*5ku1z60NW3pqaz;dgxJKR5Ga06**_;xYX1=ZX*E zU;gI5HshPXcRgR?NARzzr||3c{`Mx%82+n?(mvPlf4@iKm+&ht7GJ@w&ujR%a*6j^&3SU`d&OJut=}i^!=HYs zcpLs7^#K0o_e*>Seuoc;cj4Qq_uvEd5dK2-KK$92N&X0aoo*K~{FR@T_k@ldp26Ru z&;Oso_q#&&12g!)eSOp%)F<%vC#23P{My6yyc)jGCnbIXFVvTC%d>{> zednKU_A~yL&Hmf*t_?r#{?~8f1Ne@={o7{$*@0XB5T4yju3Pru79YbCjUU1-PXf0( zMsPc?OX0`qa~sC+N|&3#EzbmQ=Z87`i+Vrg%;6RMr#g-`{5!ASdvhFIJKVo}a~vP_ z8j0_~-!|Q6lP83qyq8>G8aO*ui?>o;@&-){fT?8+T>}&^ZjJI2;dgqg9qnJ{t#|?`f#fwg4_FL2Jm3F?xxNd z-c=vMEl&cs=l^8zk#)LZw&xPM9FJMipEIga$<$rB_#g1_#pM{nly5dQGH%5gA-e|#qU?F@eD17y3H z!qcPWd&Uxe&OhG0x&BbWce`BfyRPB;s;}UO-C6bz-o2Xrx&M!)ejh&hjC{Tb;Cmk> z?|<*Y57p&{@DuesB!Z9iI&%zvqV_X^KloJne38P3y4(zYwt5cVA(8bh;8&k7`@<6c zTlEUQTVMMR-}-?vPgd|k`{~`g+5gkDKR*1V-DJNV!0$DYI=k@0zc1q(!e5}jgBUnG zaroHbIsAt@&kMLMckb{Se)mty_OgOoo|fP2n|T1Y?X>6c$l*hWr*J#2P2jfN!r^m= z*A8Dh+~2C%2U~8(;i1C^4o@6Dc6jdanZqlGFCFe}ef#U%hQD9uPX})O3E|(@_y}(C zLwM^mGCxOfi_hTuYJ3j2_!<1aHGU4a_!|BmjbFhnzO_xWZ{O1RHr(R7@Vk6g);EM( z{J`M}{N4|h{q`7cd2;ymZ3~uoi+>XCXhkM&L`(W{Hhj$&`cX$lnSNoR0w|t3w zzDwa2pTVupslzMyK2Mh8^#X2rRt|4%cl-Sb9Nu$y7lmJ8jN~ zr|=@UXyXOEx@5BPIlTKm@d}>ZE!)H|;g$Ld9y~zeTlZ=9Emrs8^}pY}$=`v8{}J!P zqxa{V_&&T)kKpO-{7w82zWS?pLO)-YJBCLS@eH2%^8BkQ+@9B0!0mZ`Gx+dla-V7m zx99cE;n8Wo-h3Xc;P$+}1>Bz3SHtad#1d}#SMd7DGOla5J+IHZZ*$!3d3`OoJ+IG) zCtJ(>X~X^d_c!C%g?rb^xb)!V{Uknu*E>l303Lm7hfV$j-n~Y)ixE6K{(?<>24AU9 z;Mv!=-^3U2=*5zM2Df=z!B=NoyvehGU;I?Lp1E>(tKA$Iiw_*$b9e-Q;D4XD`TP~b zpYR*`UO0ij>7L_Fd4ZeFnGvY6Z{EmU*~< zd*77h)(&4fdHok!88ehX#Ka=C&8eX6C zh)o{v{>|~S_%__TK;i?q#rNpHkmZJOTW+7O^+oVtBFi1Xt)3We*V%^f@Q->v0Jr1g z2yXdPy8b6*iO=B{U&E`zC4LFFc<;ZO z^P!3)zD3vN`f#he4PU)b@&s_JrvuO4BIiF{xaH}=bBzz-mcI|Tens$F`!j$SvD6>K zlNXB*;pt1o6Z(DSd~yuWzah_U&fw8E#V7DU&u3=v{8jJTY}X|`dbRi*o{eib>JL++%x3!{>zv}r?=Ky}~GxytkpOU~osMi6;@T-5Pzr%t@50%d;Q+RN( z>^BPfZ*|_nBlQxVEG2#p_iqrd;Hml=o*yRLofkCwX?3>Xbu95d+<&on8y>$zJb)K3 z6Ys!-my1X6>T2-;Jot?CGlqL#mG~h%xLiDecQt+lFRzvO6yCi~dtl76Yg&*8Qm zRq#mT7x4T8lBb6Imx;F?fN@WxpFZ5iy$w%B(uV+U{p`SVjqk$4*GZlpyikwf@z3SB zKZ565{$q3fErnbB1RnfC^5k&KGlg3n1>Eijn8CeYOa2mWpLgbP%TvMa^UeYu?tANI zeOK`G+p^p>Jb$Fb`wwi6yZ3d8@4~CA#3T4S&XVKE0A8!d@J!F6hVZBVR*vH-{9k9w zdB_C*g&)iDv~c*`;WhlI&bv0}6|G&GeTY6G>(zm0KNs)A%MXbU;dL!Orfd8ZUVT8~ z3%FhXoWt$NUJpU&50uB+m*SZYjQoSL)ub&3?vrm-rUEQ1{{9JtV#j z&(#C?O1%U3?-JbxXtI9uHVnD;r9Kk z*J;krm40vAf(JWF{XRTXZ^MI~BtC$z)I0DZkoYb<+*!N_&(uSBt=@-650E?&JXasU zOZAwp^LYqg>HQ2T-0o)>!@WzSo($eqpTPb1Nqi13)Ti+DQi(6%#rwr)@bClTB|KA~ z!)x^lUR)-57I1GWUc&?RCEVuo3SNIi^0anq&fEH<;y%3GUyc_Y`T^oyxVM|+>BIep zh)3{bYdJ3+!qaWU6ZlHE-!a_#hvd)TVMpqm!lT{93wWycbUa zg2#H^(t1d<|H*shJjaLEc07Ww-Xq7IEhHs2^$2cx2JmVmc@lW7K7w1G6mIoQ;Q4NnKd0+_p2Cwa%ea^D?$5;M@Zg$v zZ02DF&;N1W#+UFyeFeAmTEio~uhM^5b9`gS$Z9(-H8hIeP;OZr^)!`>dv z@e0*jaI43M*AJ8Xg*xz+dKaGWDe*mcwWo}41TP;UK7eO?4L9>PhI^T;?+EUzr*QA? zvY#KrbN${whZpKoxb>%iXV=U2HHRm^5wGBuX92JEeuEW!rM`w+9&gX)_*PfT`9K?9 zs|Rq)(}CMO4B@5D&pzDdVFb7R*btuT{w;yqeryE)xxU9FbNJNZB|LkD9CsG*Tzw7q zI~Q%{VY}Pxa~X&S^cTu@*MnE;A-wpqoR<#ZrFslMK!1-ga(L$Osl!W$FC4ydcruZKtQm3jg{<}BIYj^M$)&)SSv27iS51b&Qq4!?3M$uoujUVm>`!n+TX z?QQ{&_7Jb(mS+vm{!8NhM>P8x?V#H=-12lC-iHVGl{_)MEk1->{uG|xQ{pFZ?_T0L z-15vEUO9Z}aBr_>e=L97;a!LK;iv2G{bTsW`rOEo!!w6Z9bP(o;qaBiTaRq^!Rid) zulusxN8N>ApdP~019iUyj~_1{!>`caUymG~!IMWwo+-T8OT2(v{yDt6hs4+LU{CQS z-12yjYWA(x>tk(r^gziIz%5S?o}MJfmk93vkN5y?$F&4r9xd@>czTR@2JgOFdxGi@8kA5uUmB4HD z5!~`*aR1wqX9};>3;6155HFk9jTl~BDn5jVzmWP9c zsec5oHBSm(sgL27Cxhpjzkrt=f771|o~tk57GJ|B`u7s>VB^;*Ge&A*1{yGgv) zYt9qP(}EWo@5BA~OaD9Y_@Wy(^>pDD--kz|{;dXz~5bk|I>P+A^KSyxO zlfrF&j^TFyb`GEIz1;L+3b*)@uJ?P-;g+X@TOA9y)nCISy{~Kuw?3@kmS+vOK6v{y z=a2pFrcKx1-2`y^-A#wCzq{$e?RPglxcx3Bgxh-c;r6?m2yW{&fTzFs;bt5Ycyz;J z<0H5|H#LQ4ZEw_;Dy#%!o3@%o;lo}n_9u` zxv2|yslVT;;UClU93DA*=kd`@J#T@@H^g|DM1-J^#$%_3`q(-jsf^oNpBH`~-=g!K=54SMZhk0v?Se zzJ^zi*>-cDxul;e@hiA@n)n)?oG$Ji(40TXnc^*YeU`Wn56%~F!%Ou5UaNQD*+lYm z;kkMbUR@~hA>6i$fx{Drj~$*neCF`V;Y){mk8Sq+u>b@_Z=QPeB|&c{DLFp z_oQ=ps$Rh@egV()?;38ON0#tH^RM9cxn>QwJYLxBr+uzz!Gi;i-fTw!y#1{w%I93T z#fR`x>+HiVPXxC*2JpSUEz6DJ@#Cb4jnnZOf`AHnVSl_|XY8X4aS{AT@~W)8Rb z89dTFCEW7N;Z{clxBdJA9vm%o)^IysEa8@C1-IkH8s63X{^OeSr+cg{w@ughE<9K7 z!7Wb+w>tXpQ+2r!yigy&Z9c^CQsakkn-61nt??QBnol0Q*)AsVS+I*dM+I)%;}o79 zFa0dwwq4KQmZyZE{j!FM=W@~_~j=2^on-g|s=KFll*Zu=P@Uh8t(bp5;^z%5S)Zu_e) zJbJyXS0Db^w}?k@iyy)>&6B__&j@aHr10(DCd(beBlQe!`|Sxl*7zK5eVD>W$Lo7n z;ip|I-)GI?=czB?(=#Q{5`NqBNe*hxhufY{LbvCWz;Am#3EZA562R^GAsx7F7hSmJ z>A`Kg2;o=kveoAIgAx3W*Gb=E_%`YZd}s9(exP~=f0=p?KS8~KkJU@KeV@B<_{!m} zCp5>=@&pd=IXrUs(BUb3=Wj@#Gq}|=b$IFUg~L}4Z#~h`2Z#3@9yxsI@YLZGhZhc? zJG^%I+Ts3_Zody5hldUyI6QIq*x|XuXAZ9%zI3?Pzy0-XJG|@gK0NBm@3Lcf_GJT2ECf`dY@Z_aZ-w1BU#}pnMCHcp2JHBLa%QJ!7@g;{_{wX}uItzGug**pfM%Ow^ zc=$Vc?%y0+r6_`wovCK5}^G@TtQ~hcDn?*853T@I6nI-{ZHQ z-0Va4g(t}8eR!qbfv^7hludjHk8c+5!;|C1V|b}PgoiKgZStq|mxzzy{s*46iO=EX zW#UtKSM!(f@|*wOe4jOk->B~ysp0k<+BMvsfBi@Yvxahi49-I=poF!r?22x1!tcL*Vcp{4#xSOXTn&e7j@h zxq>O&=EKC{g~R7?I}fShhwA2U8E&GofBZHIRq-gkHmxBbHiZsVRgeCqJh;R}ba9Nv0n zvkz8J;P9TqBZm(io;rNu@WSD9hu02YJKTTP?f0SM@X+A{hbImnJ3M#z%;A;8mk#%y zef#U%c6is}eTT;mA2~d8_|)O0!xs);IlT3p+wVi*@SejXhYuZ|I(*{r!r^m=*A8Dh z+<)%v_o3tP(BT7zCk`JwJa_oa;g!Re4)+GPzrJmUcOBk$cnsg-d-6Fbf!{+th2LA> zSDV3~eXzWzAcqhCBVNF_()=Yn37)$79JGL^>NPxhfW$B1x%vto{!%_qt>N~*3GaE$ z{+qWP?!#?)0er3JGd+h#4j(!^h1>fqCJrwgK6iNS@U_GJ=QsOi^>iE_!r!X*`3xMM zI6Q|Jca`_il<@p_^0~E!r|RBe&H7{Y03ND`@IXC=d+I5?Uh3y-c&T2(bM+dY==D19 z1*rcz$sfRd^$`C5=(_Ld_wDNN{|YNEP!QXs5JXu93K#;!tki6mGE_!tAhd!q97a)~ z5H~;(6p9m;2qPv5AQC8Mi*2?jZ80mTlwr0)7-m*bhWRr3JID9loTKOObN}??-1pUe z-Pg;qthXdrpOW|l9^Xm+Po2RV9ajMlUn}PmDtP%-?LWNvig@s_ZvB;d5B{D{$#c9T z$48FGj?Wy=;MYA`o>RJXymWlyc;omU{;p%>dqns*-Ts&l;K}%YavllZs!!m_T_rw- zr|MI9rk=p#yGx!KJh`WM3jdcYN`Z_=~qVi#<}!i(45@=(tPZvCm@rN(dJ<7++gkf()Po;^I) z_(;i38x9;p}b zSjW4DTRjy#(fAEKKQTVcO9Qt&J9zZh65qm$zk9$TPw(NFFa5o$5MFA0AKqSGu2&zz zZQYLG(H~3v7@k~B>Y2iATnRkY_!+#u-i;6A%IG?-1-wzu;f3z!S8%JRgf|+$hDSG& z_hSvW{%qkxjc?#r|D>F++r$55CFkYBM|9`Wd;tH$JLGpdrtn~L!QuaR3H)uLoZp_q zKdkp#<#78wh8ns|N9Z#>KVZ8I)NeF@{Hj2|G_a`$2);rzhb!EXE&w4Px_X?T-@bSCkcq4*mdcDU0Zr6JZ;ko7+!J{wA|4(ChaH04VZt*ERy-4EcaEs63;a4Pn z3AgPQaI1R-uf8pLO1RathTA+=@J#F9z-=CDxaHr%r~0~q55FUI?%?fr#anp!J@Gv} z-H8W}>aMq@_}O8<-G`4~D;~iuegv=oCK@(1-#Vw6}&h@t_!N*?F+>> zaEou?@rxvW2eE|9EzFRz)b=O<-GD_ zCUBd_7#`~HEKlJ!j|trJ&*0Xt6dq~*Ioy87IfL8pI4|I}K9?YeCr8QqbOlc@C0@cU zenY>E#MgAqzk|n@koXpE+ug&h?%=WA^%LoKd+g-0~0M)~^v= z^N->A(b9(ry!|8b7~Wh~d5<6+G1XH*lMm8gBWwaO+nC|L^u z*g4dMTz&nuq5@352ec!}e4$8*P5j#rLv9d8})J-*uqt3Psl z>ZJLUZ~bbJDT;qbV_nfk=> zx#PLxE5|Fxw~qJHZhz8SKISm*Aw0g7cpn}dCmzAWTZ<3ijrtIt-$vp`@azq;9>(xW z;}dvtmc-BCsd@@;ml8jRr)P_2@cbO{1w49{cn;6hm+)MD4IkcC`cT26jd;yO?E1tvK3&fZ3tQIfe zmHG-^t8d`RLh{t`RDBC?PM7!wK7PLV4j#WiyoFaU6yL*b{RdC(u9KneuOfK(M#(dP zH|j%p_GXD6!Na$TkKxJN#3%5m6p!JV`V^k4&*9Nd@?`Mf2jUBO_(Sm=p8ZIC39o)E zUcj55h_B#wJXXSkpGtfUxAnh;k3S&s4ZQrI_zs?YSiFTd9}(ZflS(}JhweHl)O+w! zeE_%mhww%}??&+W-Ll;=Jb1781fIQ5JcbAF7oWn%>IpnnpTX^OErZ+V+5+C_=UomT zUP<=nOL(PTz+3edJiM~xDdG0Hu!c7pzlEpAN}dK@Tt|EdA4cLWJi4y<9$u&iPwB3o z;7=vK2Oq14@K}8akFF z`k%scji1AdKb7z4IXwT>;BdURgg3tyFW|v%#4C95hDRLoH1P40PCR&UYInZcW94|S z2e<3BBDh_zHHJr5{p&;i2|T}0o;Q-f3-uZO1gSHFPsZW}JiFB7u-ytCeo?Qdg(vTM z^dWu+&(D@RgL$_<<8O)g;MG8{2sb>O@PLn(de5^jBKjrd=`ZIW>&(m1I zgD1-UTm?K*ui(kYWL<6GPk*wUuWsNU{+QfvvWMIAM#6vW_S1X-|I}0EIXq*>r|{8M z?#r9OEl=in32*eio;5svyY#JsCl`L>a6W$nZ`5me{%wih!VC2V9_#)1dwBnb!^8Qs z@U(6}%?FN;9iKX$!v9&HgRyYDaC{B_nclxv!>|4)a{tZ_-dvzOje_Iq%vGlmbB5IuAfrNqzR(K+HN zJXc@B#~+aEgbTRUxq>H^#Fy|~eNF$E#8>d>JxbJSh=1shFhIecyVuuPvEus3?AKA;!}7Vi_hW7Ux^p+ z@v$62E~b1MwPOtMB3217v?2Jfl0m(QEYo7w~2(@gY2X zuy`MyJVZQ#mnVr2;L*dxV|ct3pTeULNSz5h|GLD_;NicEr|?SS=kWNO5}&~<^%cB$ zlD>c8Ht%bA`&51Z!lP65{R>a$;x#-tO?(Sa)q{WP&Tq1L(Bb{wgIk>;-0JMZt>KVMgNa7dp{Cna#Jovu&8eZlPJgmV#V@Z>)vegbd*Q#^(zpAetJn|Fw3 zaO>v+9=uQDbGRLUF5yFsFW}kxCC>`ps@L%Jbh&SR3%B*z!1EVN{0?5JxA5>K62FHR zXNm{^+@0U>rQ!qn<7GVz;WqChc&z)$F+5YB!0RVT{umxTMSKd+)iZeXeL4PIz^$J- z+>Sq&a6A4i;CB4Eg4^+D3Af|VExi4T-2c+Rtc_>OoF zo~jSw)!DZ`9EXhHHt%D2sK>(-xE&|Q@c6Zoe+qBU6HnmD`Qi(B`$0KRp2Mx5OZfN` z5?{bm^%Z>hNr^Av!DqzR@Kn8lH}8=3yn|amTX?Md^F7@5^TBhw^IN}9^7r7$`^7_e ztv-U=eflvxys11tdNwaHxL-x4w$jeb~a!`MUgnWCwqX`X0Vk?>(=(PClXD zhueKyL%7|CHG3He*27c?ar4Nncd&k4m zyM3@c1INdXPaRJkU%>DCB>BH*;rJSEzk^UazH>Y{qdQ*9(|3I6_ym5`De~O%#PPY~ zx#KIxE62Bvw~qIo-|d6dA2~j9Ja&BMc;@)h@zU{)G;O+#__%5;fuR{_?BLWFmQbA_|);#@dey|C!%nC?Rf3@&ha4cj@Lf-`*5pg==j9( z#PPY~x#KIxE62Bvw~qH-((QwdH*$RBcG;O+#__%5;meQQhk@f`$ES{`jxQW99A7(LJHB%~c*T*&+jo5E_{8zV@wwx< z<15E2$G48Rj`z;$_Tm1oko$-u$48FGj?Wy=9A7$KI=*qdaeVK1xIA(n29A#%pE{m8 zzHq#7eC>Gc_|Ea*l}8?L-|?a26UP(B=Z@!&uNX#;ZmM2y>h&AeCv4Yc<)u+KG=36$48FGj?Wy=9A7$KI=*qdaeVK1`069~ zVc_`K@u}mf;|s?N$JdV6j_(`~UUTH}_8lKOK5;y8eC~Me_{#Ch@vY;n3He*#_`7Sz2o6)kKBg=-1d`W$ES{`jxQW99A7(LJHB%~IIlZi8&}`) zq2m+B6UXO{=Z>!&uN>dP|KZDWpI7U6@BD5bEIx94?D*92)bWMmh2v|-YsYtv2d_W!c>9hI9iKR!I6ikgcYNh|<@na| z*74rI9=Q*Z<0Hpo$7habjxQZA9p5OJ_SpCIue{NneE z<73CCj;D?<94{PSJ6=1!b39me`(xwnJ3e%L;&|ft-0|G;mE)D;TgO|+dv82)A0o#` zj>nGA9M2qII$k=yalCPS?|As8Bllt8_!xeQ-d{X*Jav5Gc;Wck@!Ij7@!0X1_j?W#>9bdtZxtCneSvkISymh?y&Tbzpf8_Yc@!0X1A3HvEJav5Gc;Wck@!Ij7iFA-_1T9f_mw_JaO?8`o@)FMZhaoXtZ^#*RwZ`{M}`HjH`yW_Io+wH;a_jW_Lz3=*P`#szUe(}13Tb?2O;&lc8 zSaplTemHh~27lR^vfp09s~<=|3;21Bd=FhaUc<-Vk>_0P;Q3J}ALh5Ee@uVJ^F!VK z*XkjBc!t#3hbQV0eEfWgAHW;+A-sHn#E;<33&qFq^hM$mc%>f0!xu~Z6yB&O@K${W z4|BA^#Qz9AHwTXB>xDW zK1qBGA3s@q0#E-zJcb8P5ud_i^#oq1&*14(B~J>^)aUR*J%cyfYajZ#fY&#d4^EWl9+dE*`WjxUSMc#)OP&opoQl`*LVXJ#K3L)#c&5IC*Xk|2c!=cL!%Owx zBi;2`tM}lxo-B`c)iq<&~1IfZ9S)O zThDX2t>+AG>v;jU^_;_PJul(WpUFIy@bKp1Yj~ty!DICeyjHK_$t@)R7Csz`H}Fb* z2aj(l@h!Yi-@{w=;G^C3S=~zV^x(C62yfNT~$;T#3)%nfd}Aze?hBc%i<8SLy{_k2hBE_80Pb zTEUZFif`bldJQksxA5>+lBa=}>N|M$YyEtOmwWL&eEb{npz5yAT)hWx)I)gr|0GWz z9{g53f=B8D_*i`iZ=WXLnEbcGP@lqU^#oo%L-Nev@jr>D@aUQ1b9kJIXYfXS z0Utg~;&XVWzJ$lmmiPjmsITCedI`7B!8JU&&Akr$jT&C5Z{gupWPTg?SbYbNt}5{@ zyi(u8^Q%dG@UiattgbHJgU8np58;J+AKt1*@TxC)2Jl*a2yfL#aO?9J9{#KRzQ7b- zy+MCB0bZ-m;K54bQ+TF6hlg*J_zd2tFW~8$BtC}+Zx&y|WAy@FsITDZTO>~juhiG@ zM!kYtpEvMYe;=WNm)Dc|-NECxins7geGgCGCh@_)b=PO`cJUs(RuAF9J0!jj&($M% zqdtHS-zj;9@ZeqIBY3Djh7Z*zaO-mn&z>jW(`WGUEA{(3JXW8>GxZFfoGp14@ZcQr z9A2w0;lZmUzJTZID|n+`!iTSxJZpIH8u1Dqs&C*!^%`z{-oo4W$vn37wfG)hzf9^0 zKi*xR^~=Tk@bqc=eTV*Z@ew?Jo#ct>uNR-fvrF9j@cEL`FDX8!pQp!f^z+4+@bcQy zhmwA*_!?e3Pd-m;`a*mQZ&uoW`WvM1--jn}mHpump1w_d1P`w% zd182UjQA8@+4%~1eX7jw9NyURGrWDZ_8&gf^K~VB{1RCYYk2c}sk4T+e-PioW8E*c z@Z{YRzlXPa9w7XWZvTUmJyia%V=yl>PeE2pwZtVSMx6h?|2p`{G z-tPl=aNY2*-61@EmTY$d&(vdh{76}!GkBt&(r+U5Ea0hn4o|+T=ilH~e+h3NCC@+K zz=J1?*Yw+6`p}0hy!^O4x3+~B_m=-h?BV5SB|i8>cV6Z@w=oy z6+F0{)W3n(`n{=vH|jfh`f>R`Q45bQCH?Gey7L%aM?8er-@4Rc{q*6%=`yY%ygg5R z1g~{JFoqXzk?~I9rFsG%{#fdn!RxEZy3OFlt;84b{5bI(ZsS_P!-vZItAyLQ*7QG; zan7I$t5Y zeu}K~0lZNk!fn1r@Z|2Y|B2zL`V^kuL*f&7e32ZV%;AZ829Nc4W&uwI@;)lysrm|T z<0|3JW2DXvyj8E^(a93Og=g=O=cu>v_6y>BxV=w<&vfVaI%mmqQTmP#9iPCTq1SaM zj?W#>9bY+KIlgtgb-ef4ZXc}v$nlZmvEwuNr|&G+(aqtu-5h@OT_nDMTl^Y+SB>Am zExvJl4}YxY>0Qw6&vVrK@N?A%@HeTC;FbCW{sr|Z-0DvqUpQXCZ*A8#IbJ)yb3FK5 zw?8+!tIXE`e)03(;r5*Q7;ev*pTg}q^9kIpADh8#yD8kBGe3u0o(yi+p)KH+KZl3< zdPzU^ZinOW0{+6+{Pu8t<_bPPy*YRZPybntd)IKA-`eq=<3Zh>N6XW9eCYVZ@dW;V zUzg`;&mGSlUpZbmzID8Hy!T(-K3JWR<0Hpo$7habjxQZA9p5xj$9Ikg|9#}~_TdkFw_JBRbbJE;>>c$yD*ToDJpA18mE#rs(|;xV z+Zz5seQwFl@!$*H@mhS}@uA}r#}mirj^~cA9IqVTI^H_o`{I%N5IH__Ja&BMc;@&L ze*Fi^{I1|OUzOuq_%rpsl@|WMe~|pam%4qh_&)p#AGpimy6XYl;>Yllo+|lcxW&)l zJAE!t27j0S{=yO-SH~WHccy@6PmwxH_}~9rerJ5+c;omUe($ZEhY!Ep?VI_)@v-Am z#~1J}Wk7Lhp&!aLcoUH+TExVY|V$+lS&>lBWlcwf+!p z`3H`V9iKX$!askitiud`;}6MwxJ$=N$2X2Qj_(~0ztZj7)AjRZ0Jl2Fj!zv=;rF|= ztlNd-1^oJR>01f^bM*>t`L~X@@Xzb>MtWcE_Tj{P$#W(n$48FGj?Wy=9A7$K!mn_e z^rwPb{aeRd$9rFM`r!D;@!0Vh{1cav--XE>U&23l6ZsvV((#SsjpKXA!>@PyVA~xy zK6ZTScnGA;Ez8_)@KI)rG73f9WNc3NK$Lzhgd!=Y{@18gB6m_*h@(@Fe`99G}A*-EIM|UMt&O!7Wb-FEsxeK76(0 zsp03pMtlpm_!b^(o;}?11Q&Jte{mgfJHHyj6YX;!o~lQ1%QJx6dDmO-ey(hH0k73_c%#2-xuk1+0k=M^;5M!bZrk0!Exv(UA9ir- zLkqV)?BUjj;5*&*WA*gl)`yU;edxoj4-wq*58&3XAv}7O%-0AWtB>KKzF#KrNIi!C zr=H)KIiA6@Z+}(xC-C@(avq?7CqETm!SmCveK>zo!tMRFhS$0dE4ae1o!|(Ot zmmQvKv4+?8m-V@YXAcnH!wZcMzSr%8<>|o-{reDZpGSSTZ8w5P|M%m=x*fnR&k$~( zYa_VjAHyrHa{|w`4>7z}pTdU^lD;MI^hEI){5CpYbNEBl7w{&O>vaowc5S_m7hb8C z@J4+N&ySTnTe!`81GjnK!EN4KxXsrdZu1g+zq_t%-g|J%6T)rY`|#!*y&nNyoU8XE zz%4$84>f)Yw>$~l>X^an8$J5)|J)QFy;}e81GoKT1`h_3X92hUWDZYmDDf+Jr1g|= zi{HRY%~QiI&lYZVG;r&~4&G`#E!_IBhg%R-Uqx5;_+0$yBOu3ufjExv*$*OK@R-15|L zt78kd&+!I6JXZ4W;5NT4-16+4?XmugqM#LU&AfFg3tB!23~0X8eXbz;Wn-Y zUTOReZsTgYX9Bl6Vz{l_DZJHs61eqe z2DdyZ-1;+zH~%R0=kW40@g>~iOZZsh*Ko^I!L5!Bym*>yw}w~hTe$V1f!7+pgIgb3 z_yeA=>*Pn>b@FE~5D(!ezEC`ZKVE$ZA0PLS!~1Ij4<7d5gU4`-pTYA-NPG&nJaf3! zk-=@9Ea2@z*8|-8yo6hx0&aa?!J8AL{t6yGNPGjg_y%6zN8)#I%hSTGjy*hmu;dAT z+@1GQy$82Ggz!q^`*7>S2%a7N*N1tZ!ejLWZt*jCq_0!B9rw=RwdT*@cKp16Tb>+l z$InZ6_y!qQ32#Q?Yq-VN@c8x;zlB?#25xoi;I=+n_*m=Q!)<|p~enWWn zy6Itl2k>Mo;~K&(egbd5BJnZY@=W1YM*_F{XYf+%OySmtIo$GOaO=YYZu_wUZu^-P z+~O;^?e{it+wawI+wX1RR(}JxdUkN@LkqV&d${!>_-S|jSpFW|`W3?Myi=cky6m4L zc%?pokI#_!A>2O4Cvf|mjo}tQgWKnR3b)VwIov+?Gq`>3FW^>B4!3z(!tHavfZM#R z;FiCH5B2pL-s*8h1s^_L`n-Y1bGaV7hPTg<_$~ZWPk6=Q{M!zG<^$w-V-KI{^MQN+ z(_L?;YMwrPr+LP3I}T6idi+0w+wp%2x8wgg+>ZYEs#13x9`7PYydu?}q?R!TEx9=T&xP9-4;I)FG&C7&-2kBc3w|-6G!5t+&fsfT^aC_gS@bpfSXAZaH%p7jVflIi> zmvB2SUBm6Tw1V4l=>~4cr8V5@*}`pJ8n_*o?%*~rE!^_&;d6Z*{H(hUgNMlRa}S=Y zhw%8J65ofnCy7UJyAFBecZT*bkmS+sN^)rFnd?k+09nT$KIbJ!wb-Z=F_rKl# zTm6yaBgbRMXO3r%mvH;OR>SRk;udb-6C1dFPu#)n`&|pS?e5|BJu&!2w{MoG2e8u!;Y;0K1aI_v>i{11^!pUNy@FhCGlJI|KZb|LNuDXZy0v%$xA-}Hta&oHeb@831t##O^@yIZ)$w{Yvj9&UXIe%W0=)`uS4>JQ;o zPakf5h~SoI0JlC2;g){{w|{W)HXXHo>pD^KR#DdT^Vs5N`GK;TO+4-0}?I7tcG~@{i!wuQA-d zr%&Lqo?nXT`h9Q;4_CUMfye(XK8FWi6wlxmzl3L+r+{0Y6+F?`CEWVChL67_^;B@1 zmkr$V)Nq@ZE!@V{!fm^IxW$LR?yfiMLmzH^h~U{z!mXYW-1;zvTb>Er`Vhk{ z{}gWhO5nC%n!#h8uavI)pE+I6TV`}qj~#q z>vIIJ&(-s^aGS3o-13azHeXY?<)6cCTp8TPwSe2Wa=6vAgxhutxQ%NCw>%}>#Uw@9oSMW-`hKE0v^Eo?s{WI|vZt=bU*Ig%><_Y1Jr%%_s5!~i$0MCCR^$g)Q z?<2V78N+SfC-CU?_dooC|Gq}ZP@L1y)aLbd!t&Sx;*E|KhRA0fZ4<+34tl`#& z3U1@t!fm?^+~W7}SnCXai*=&jgIga$xYgf>TRjon`Y?c7o*~@&FoIkDG2Hq!frt9s zm>6E^c&BjN4Z z)Ns4bY74h{Y2cQB2cPNd7M|#JTzhz-9{jGmK9j$f>%@BSR6T^Be2UzkJ8*mqxBo{> z;dY%~0=M`%+^!qU;C9{M0&dq0=5X6jF5y;B0k?Tv!7Wb-w|QK{Eq?_c>+22N-d{C* ztk*Yg;r9M&;Q4jrddT4S-FYvk^8C*TUY{sFfLr_!zSHfE;LU?2&lujSPvF+)7#=)C z@=W2@=Q&;TFX1+>0&e44!EIb6+{U$r+qf#YjcWt9an*1e*Osp1YT${!-oZodTMLiX z_we#0>2vUh?mDT|dvLpsJ%ZbH<^#CJkKuOR`vh*+y~l97?tKck>%9}W)iZl{AR>+qNGO1*#=ua)ceSMcOK@e*$P=Z)iy<9o-$|Ld*?%RhkI z_55SFU2i{uTYLhy>;GqPyZ%3g+x7o*xUGi_ZuKnSwjOf0t%oJt)m8n=6a*IEcYNsh1a9A(61aV@nZYeS zgWLD41>C-8<#hd?wS-rCpI`yEdRA~-4<+34tl_pED!Ap}z$f~;h8Oz1ZwqhL8+iFk z{XPq?)LVFRxf5ijkLu3*_-(TP@54*=2ws;GKY))OBm0XX-1;_x$M29lW4QHy0=GOd z-1qNUpQVkzIMEZU;lhLFVVo$d&+aC_wYtNxI}ke;(JMa51u|+`W(WoKYe)k zmy#!fTb~DT%QJ*qpGR=(bL{xc@eH0ECF@}ck1ru!z|%{Kui*K~(w`C@T}I;9@I<|W zTYon2RO4&7^=AvW{`4-{o!|PjN6B@+@K}8axA+mf)$NVpHjfkd@M*H$7;fX8!Yxk% zxAA6h%U{54Tr0SZtAyLQ)^Mw*g4=dCa2r<*w>(?8jjMrM{vCX#uUq(7`@Dze>cOSD z>%qRq_2A{xWxhgq?{%`DiQu;0Mvljh&m7MjUpihozHz*9eD8R8>2BX_yaUI_j!zv= z9bY(JIKFngc6{e}aG4{Ix9|AS@rmP!<8#Mz$5)P5j&B`r9q%1|j~tI3&*04! zxI!|i&i8g6;EaJ!yr54ZgNUbmk%t_W`98o+H_ zL%7v5g4=e-a2wYIZh2z3jcW?G{0Y3#@z4H$F4rNX@L2mlhud{x89WSioxrPWKkV@N zUcqzq4cy{u_(ETA;ntr99v&;(-NCKTE!^_#;nwH=A9dG>!*M>8oz?u=h_yYze&FL?cuR{ zaM|vBS$q#(>EDNN>sudQY5oXq{U5+B&k%0?kKvX-h12Mw?gjWxe=V3;0d(QdD z@!0VUUVLnH_&i;}$8Y(`OOB0=ZP)h_WmvCKRD`;e+9SwKnb@zYq;$PD){aV z@_ns_|3bZiM_<(6jfIC_5fA6)4 zkKp!v_1N*5>6hud~@`0!&A zzk;{wB|Lto#Bbo^cZ=6>+wKltoFTt67+kU2pYR3ZJ$U;<@esaxl&sr6eEcGbkKnQT z0G>bRyNCV55N>%!@IvFq@R>fxb?SKP_`>nR@wMZ%<2%QLu-kvDzwh|a@rmP!<8#Mz z$5)P5j&B`r9q(P~$bE<$A2}X7K65;CeCc@U_{Qad%8|$0cYNsh#PP)O93K7geGkVKCA_`7_!@5U6@0F*H*h-+so|+^cMG@U znFeloc5pkM>0Pzk&*2GD|A2lc@gZH~NAOm+H-_7B@&q1ho)~V&+f%sZN#J(8ox!bd z1>ELq1-JPs;Wl4uxb?Y$+jci_o39#fdA4wyuLf@Uckr3MZsD1(pFO-%53bf-5B5E@ z2hXmc>jZA|IDrp!{ls*g_bJ@gPXf1jpTTXrDcsi29Bz3sxUHWB-16t}P+u?M;~U)g zuzx7viH>{s>(B|P|Z-Jig3roZD*!(XA-bM71uuHKzri|@nj_kf1*D3tGsV|eql z;}7GV!n0?HC-5i}pTUEf93Q6e@v|g;4o}rHxP7l#z%z}{;r6{|3Aa9!j&B@q9N#-0 zUZXoNw%vi_W5=hCFW|`^%l*+S_)xusTl^ZH>gx(_`>_qY*8DZx_J>=z^Ucl}5;|h526nTEj8lFB? zyn=IxaA4qHeY?XjcZ8P?T+X=-WYCu zn8K|O3EcWHgIoP6-1;zwTOTsG{cOFX4TCUBK;rkQIEaeJkO19nl(|=<@_B zxUJi*<1O5NXKD}6J|w?$+PhYF{aAbmf7YAz`X#u<58#7SCI1L+@niV8nm>kH{1iUE ziX5-b;1-|4Z+F#K9iG3J!7Y9Pf0Ncz!h?Irez=C`>Mgvwo5b(omM6G&xBp9vgWI|d z;kMmA+}3{tw>$&5t^Xn1@{izat#b^w`;I5@Li-cLt1C-?rttQj;t9O@fqb6M>Aw=s z=o-I-r@xc<0&e-&@K}H6rGhuQ-3{F8uIay(?QY>#PXo7k+`%)gzlGa8?%|d{IJUdq zGK+)fnm>dWznA*^@Z=BT5xl*k%;NxVzjHcveCl}W_`>nR@wMZ%<2%QL>va2R%Y23dh%u*N*Stw*PG5kJNgCsM{Zl@4-*j_&(fzXLjiL#PP)O zIo#^W;E&UKa=67W;iqZ*3U2$83U2$84czu8HQe?mTe|K~8o0gRcW~REv~b&>?BTXQ z39j3nNBdpfzT-p3CypnM&mGSlUpZbmzID8Hy!WR^?nC7G$nn_mnd6z`OUFycH;y-s z?;Q`XcjP_{93MMAbv$)^;dtTr8gB333O+eoj#q2A#c$y+zO(FacW{eu;g9^fvPNJ@DntC0UzI2 zzQ--$kI?uP{A<^Ix%`eH{A7*az(4gj@;=(aA6e@A7d}_t!%Owv4ZHLEZ|Z$`puf{M zgcsM5^)sSJ;$wJnUGWJ#x}JCpPp>3CgEv-n&t^|7UzmJc57q-^EAp-)_WX__aPQK7+sX0`Uy~ub&rR z!ms-!@e=;Ft@s9Be^tDJpYe6^J^ZE@iHC!3AJU!p0N(qN_!yqG;#2q~eS}e%<55TliVG74O}o+lRp&#Uprjg7^sD zzl(Sb-`-t(27mrvh-dK6-bZ{1e_1SE!XNfP@eTanr{WF#wL7W{G<2+{?Vt27x3ht#MkiaJV(5SUwI+EgWur{@!-$8 z<9*f(#QX49o+&MdiYsKgAquwB%!yok)@fG}f?-Z}#fB!!5E&PS= z7jNOe`k;94X5Bu#{iEU$eDiVf5&T!55Rc*G&x+6BU;Hoe4F2jbiZ9_m_^NmbKeZ9x zz_0Wj@dp0T?}_i>AODefc=K)_hCdY_z_0WR@iF`}zY(9pkNur^3V-%d;bA|&fDeuq zFW}F)lPffqyA;v@L?rs6UD zLw_Saga0TI&)`3Kg!mGEk4K4@@S`6mzJdSc6T}<%C!Z+3hu{9m;^8g3eR%&<#Ru@a zKV5tb|IM?+r|{#SBc8(Vun=FszyCt<0)B&Bd<}o!OT}yWF=vVI;5UAycyO!kcpvsE z@jm>6=ZO#D$GlN|0*~J+p1|MyPVqVX0c-Ibe%?pKSMYCsT)cum?~~$N_%ALHZ{a_z z#e2tf`|ye{h)3|Jd|7-1f5%tEWBB%K;xqUME)>t;zxs~&68?-IikI+T{X~2Nf588W zH}JE6Exw2U)$hf_TX*~L(Mw$Euzw!FpLQAXG5lA5BtC`z{T0Pi_`|OzzJL#|DPF*T ze5`m0Kk5476@0Et{0LsFkKxHk z;-~QR_TmZLwmXNvMaR2<*UyvlT1)u5G=2rI)YtI%EUBl4H|krs)!D-1Crh5*ZM%IA z|3N&2H-9TWfX5FPAHr?B6UP(B=Z@!&uN%$ms`6uv= zjz5OmeFsx`s`Hh=?Y@H_!Qu0C0Z;x%JcnES3ZDN=;!C*2Z{V$Nw}#tx zw{WYwfycVt9o*_^;r4%%J-pC7!5y&P^tqHhxaAM&nzs*cG=Btde=dC+z|&uf58>Ib z#7FR7-sEx=#9VTPG3R*2w^F>tqPGc^tuQ zos8kOP9|{s|5^;Ud6_w$IlgqfbbRA@;1AV=K=MUBUT+-!e_`u*>v-?ayYrr%c6+(+1D;$YK7fDc=5ic0g1_f_$I0gc z{2@;~{@^pmGslQCV}zlHQO zgIoL(UcT+W4)>vy@cN#=Kg{DAo_t2)Yk2UN62FDlpOg3&o*pmpdwB3!i4X7G?OQ#O z_&)p*I^F?%qCSErcauCZJXN2Mw_4=h1{EFk#<@ykK^HDjk zvVni(HZs3kcz-CqgWpVj55KGSr+1fbpYN&hefR^_2k?igkKpHP{t5gA_mMiM@VC^z zJFK@9{@Z_P4(oFcKY1(rfgJwD3m<>Tvw~mrZSfNRGxat6Nq4-`Ay4J_#_<|%+iT$O z|C-dZhbJ$T^%LB+J1-XBhd=7;k|%;&{0P3)?T+EL-3i?4j^U?V=BtN!nZm7}1pcMl zefAJPgIk^y{ymMK!!3UX5A^i{{$%Y>4$q!=$;13E;bVPHR{{Tk=2^kFy8hSj|5M+< zf2`-(8u%q{DesFG{@&NT?67|b?$%uomOq4B{sBDvN4ei{48PBDpFYgX1b!WjkKtE6 zP4Z0P@3`g3^8SSnUncWDhg*COkIs z#&COIPvOtf_ylf!n89s-mBDR)wSe3HDu>(tY6-XfOaZt3$qH`cD&dxA4YzSs@c+H9 zykEBPH$OnUf!pWT9&Vps!9BX`B)WvIANbwWL-=JbDe-;y$?6gOm`h3g0RB7mA^h=| zmiQ6;-Rfib@6;#oQ+^pKD@tX@PE_z4E~hI$-FG!f4IDC zw}4;k^^$)Dzx`z;zJlNCJc-}HPty1X{%-Xh{G_8Le{j$4dbmiv2mh@e=S1*JT_k-T zz<;Seg#X1EcRYOWm^hxofAA>1kJa(q@xt-a@e2M6{eQ<6{=Qr3aWXs$P^W|QlJw#}fD@kCJiC;IXo9|!e@Ep_y{8QTJ0{-=1%X(YEQ+>UL-{v{d3?5$~>pz7*Ouc~H`dm9+!>#@;e0XKqAGYw{>*vBAUcE;9^_Shg z{rEdle+akuKHRoDfLq-|_)Wem`A6{M)n{<)&jS8Cov$VQw#UimMG3!`dIdjSy@r2H zj{|q`@2I!%|JFRgy}SMVu6hW+;;p652tHIF!ryR$tp5r8yMHbo!!3RW|BdEJ;g)9( zw>mQTv3Hj3F5nMR&*2yEui$^D@dfYB9aC@KT z@W0jf=?Z@CEhT>m&vvrjD)={Vqw552@ipAG+rX{v9sCxzmHaLIj_T3^xErZt)S^&T9?ec3x`;xAR&f zxSiJ;!>yhP+}>X?+|FxF;r9MY;Ff;|w|=E?dyd>3ZqJd+;PxE31^lymJ}`&d`dPxC zsOx9z_zrG)TlkkUSwDODMe2jU>aGW?X9$0x){{D(!7c9s{!h=9dUE*l)hoEI=Plgo zY~W{UoqPC;UoP7X?%y46rTd={e)KCPz7Mzf2yWXQ!maKR{4X^B7=EI93b#Hi;MRv6 zo}VT6#joIRy@iacgxm3d1^>OqZ{QYR!)?0_-0I%J?=X~lTKGggdO&x+tPdl&^eG$PI8b5$r{19&29mB2e3H(1ae+>V;dIq;XEaBFN0{&+0L*sZ0 zx4e7!Pah|J3m(+%=Wo@AaI13yw>o3^$F6P?Pf|Eu!Y%I_zSZN63jSU77H)O+rrkbRogw_Mw9eS^1a5g}@a8n>XA1v` zdI7gO*Kn(|fTb(KV6s>aszvWeByE#0# zqI_>E;5&_9!7aXo+jc9s)xCk=OTC+3%UL+f?NCuZr96=;g)9tw>o0@F}mF;{MPCT+`cc*;CIpZ6mH*_=kR0y z;)aJluZz=Q(TmD}E{UY~j|225xzFaO*=0KVN^> zp!cxuIx&wNA2}Yw?Kxu!{KVVJ{}EF7_<;mfReh(_(_B^x_{?D4ff?IqIzwe#o zy0snLu4ilEANcjx4(G}D@adm?>EPktbo+eb@%sN1_~{Rp=L8Pn-@A-lKRa%U{ADr`uh_->P20zpTE2+q^Vzo0lEj=B0(( zb%x>JcIV|)ua`db;m5ySdtW8yFN35+x3|PxLuz)gxmF*Be?Zp3O~J-^)QD&Nj-yG`~p7K*E#$jFC*)A z2`@B%0sqiFFFNe6R&dKx!e6fW*YLM#{u+Mvi{$$AE!^T;_2pH5AUvri|c^f z=VJ)}BVD(BxUKUDZg~c9o8KY)AMPyupTN(2vGgH^Tl@@u+&{^6gDKqd%;8o?27jy8 zvw(j_J%?K#mhi7?d;zyUtl-yrne1mO_!YDd8@R*uCgXAf?D2;sNW_&(hFFoJ(3mwBJUFQ?;5;1)lFNBTO2|3=3(hyPAJgJ1S8vOX7Z z%ag;ertwSo3w|p5u@e4oFOYd(!!5pse^K*n;g+X?TOB+2t6wDBZQ=K`{R!OWH~72m zdU%+|_uw|a1NeLN^K=3~T|I_d{1hJQ>jZA|GJ{`1*I^2``JKZpPX@R7E#UV!T8@WT z@V|bAte+AdyYHe4onTr>f`h=cpI( z{lCe5ktO_?o67gH3U1@wI^H_od$iLx_)_Z}!r!VshFd*Tc%|_(_+=j<*U!)4*5?J> z@)z*`(EKIb;y3Uc-%jRh3%{584*p>EJ>2T-J;v!LJkdNu_^Ik+_>0tI`1yax5ATZv zZsVQ9|7<7gY5}+S0&eqC!Y_BWu0y!x**f0Bm(P`Yf?2n3_PqKK{+-WDd<3`t58+nN z1pZy^=M-++ox#ujPucDqZrfeJZMy~h$GY7T9-k}uE4by^!fhURaGS3^+~%uya<|Wx zKXQEJcGsiQ> zm+<@Oc31HGsc+zg`WF6f^&Q;m4<6s`!$seb`<#%dI_`@~6f~V>={59$geD*o%PYbs?gC}(R zzt%h<-10Fo>2;RO_wmX0~5B$vG{|IAv zuFq+lz?)yo^BZG$p!aW1;m18m_LC|6Z(l0U-CDr2K;Dl9{5MaK^T{i?#aHn0QIcl^ zw>&l6>e#|<|I@$&+i$>a9ky`GvxnO{3{L6JZ!*%)5qPE^!K2$r{1`sIl=NW&kJV$i zeJ;%4_PLP4?Q>xcAL;%vgIgaKaNBR^aO>w1Zg~p0^>YQk`f+lhwQ%`ZH=z0CUr9^FAahPUcd zcyuR;PvFftQqK%NJXbu0mzrk|k6$J68N5(mz$^8fex^RJ2_8N4v4?(^@alB&HT(kg z3jTBT4g5i8NS+#=pCrD8Cl3>E;I-!2!K1&G_!ge3@8Okt@Z|0~JR^}jJ$S7i!dvw| zywW~La6672!R7!-QB=rV~riI@LOSyC=t$Fj88DhRBMt9b}biBwBRy^VsXU zdOYU!>;32F`M5sUTyxEPXJ+T{UhQWIPc(iGj|$1ZfLH2Ec=3ISui(`s;wyOi199&y z_3>G%H{kxI65oVZ>Mgi;nZ)~WU%d^tJ_m5`OxccIc&Hx1U##APr|L00K1=fV;oe8Z z6ZjSC19SOpqeFFDBF8On~^?3>(Z!6oYg!>N{pTh(7 z1^htuCH$M}6+C!^V1e+>V1&xE%)zxQ*u-yqrk=3;GwtmvHYSaqn&Q@#ei>ya7)?Bj-y#y!l)mKk&tm z#6$WO;$3*C`^gv{{ZQij@aoaxDcpOE_z)hxM%HT#k6tT2fybW|FW||i#Aon@o*ypY z>9eJtB|O&SuXkL%|H+AxzX8wnx{VJn)Z6gIS@QilfP3dkJzaQHJ%UGLiSNPRrSr@u z@H6%M^$>pXi{*Oe2)f z2Hd{)HQ`oI3vS;ZeYoXm!|nTH0Jr=dxb-W9zvhi{y`l^Mt$GAM;Y||XgE#d$Lkzd= zK5%&E@QK3gRPm=pVA>8ux9G*CQ2!F_4GX6*K#b5Qk zb-3L}n8Gd348EP_pTjNB626zluiz)BH{M?FXQtkQTYMY-WsUE^ZU4}P+y0>kxBWvO zzNv1<6#l8_N}n_Mjp}2#{l3x!?mbWPEFHdrTVC&kdf#H*uQuR`dIxUxgz$%IJ*mSp zxaA$e$EVAFehkmmOSsiDhd)B=X}zPqzUFPX$=T{xn_RuETq9%NxV} zkIMN&A0DWW;8xEV{!FcB;qVG>c~|i2rBaXgu6iH51I0V=t}Zu(Tb*6_AsQdU#~WxL z;DP=nCAsd?t`B9QI1 zfZKWC5?*S21-J9S72J;djkLZU?Rk$D{2tvdZMfY(4dHhGv`e@9w(vmj7xv(G|1^f% z{mnky`jf!z{^$`wko+aGYw}M;#6+F99>hw;mj}uSlCv3oNKEo#5<}+-;<5$Z#_u98|_Z^n^@V^`==eHr;_U94Y_UAF&_U8%Q>KrONTGv_gpIXPrdin z`}2$kUccThEx5fG?89HK?{~N1_FixRxBOlB;oHf3`VsuwXUTjEeYm}sn!qi72)FlJ zGq~j$!L5!l+}>}U!0r9k9B%KoPT}@`YXP_Sp=NN~UJLl}WAgiJD~Gq=SKq$TA@ci8 z0sJua2;M(j;(PF8)d%p?4v_d1ezy7;zQchMKY{P6p2J_UiClju;RpM2J*|RYZ1Xdm zRPVzX`uoT&_yfE0d2hq*`NIzUr5fLZAFkeq7njL(i~;=f8b5?T=7mzv2)>{C1itq^ z5mGBsx3A<`!YzIUf3C(i-e2$YLFz4drPp)X@Ow4B1J8dbee1$6x<`KR zpa-|#FYCke8?^s$|HZPtL-@|>BY5^1xgI-#zh2{~@DHlb;2ZBR%bmlYsJ?_hOML}@ zy?WyV_5Rzu94+{>Un0v5;Aib4^DT7Y`Bnc~9~WYHq27lFyX~-k-Xn!)>O**Q*G<;( zV|cXt=4+q8gC|RT0ne(3uH$F$_vrf0;r6>HOL+KH$?py8{ahR+^)%q#O8Vo&<2Oir z8(wJs5T3qP;=AzRXz>^xs`u%;N&P82y+islgtxx^wDt2;V~0;2UOIf~aPNcle%f+d z4i6mOh3|UdGuQRU@Cz=K^PGXhGkAKV{9fJ!Zr^uuxW&)l_PwKoTl^Ak-?J*XEq4XC zy1ft8`)TLN4Y<|QgfH~_R|{@=e7K!&x8asQfLp&haQmJW!tHxj7jECPB6xJKd@g!$ z8&?T@^kvy^r*PX3WblU^Ap6NN+~RZirTU(40k?YQ4zJ+jO*dQb$5!z8hU?b*VeiBB z?Y>ZNz_S}Az6l?zx8PQX4{z))=T{;8V|U5#O!eT!290(73A|Jvz^%>{p6@7mhH&o* z^8IlPx9_JDxWyN6`<^?4Tb>ebbA9mpJ&t#m3@FdgY z8vS(f7~a(Q0X!@vK82_1BluW-47c;)DLfiU{sR6_{T?xg?{?!J^4vcBqL<2X*30Vs zwD=bMR~p}j|BwFeTL|~A+GstVyKrAUf+y-dc&Z-5o7c%W8NhGWI)`wJAHzT0mGjl9 z!%K%R9qyf0@2BN&IXrN9*Wt0l2M*61K5=;A@VUb)hc`~Y|33H*?>Ibic;Dfv!$%I! z9X@mT!r?22H_y2LKD6QA-ABF;hVX~(BJILiTSfczCvWT&Hb2JcN(+I!PC9 z@1;f#?>Rh%+wv0lRtL#`IEC+`p2451K87Evp2HLM0{#K@68>rR1$?Sr!4KB!7>%>) z+r`{>cn5yxfpR?|a(ExUc;m+F<4X!pdh$JG2)Fn#JULk6Cv?q|!>x`f+`s)n>v{@! zpgx1!b$}8cYWy5--$xd3>+=e}I987P&5zc%i+S7OA$;SH%X@-7hbImn!q3;|a>wvv z^*BCtcnLpF=Pg;nEsyuH`ubXY%i)2;yAF>XK5%&E@QK3Ibi zc;Dfv!$%I!9X@mT!r?22H$Q&=eP}y8ba>CN@Y3N+hkKv6|MhJ-JaBl| z;jzO94$mAuad_eIxx*`mH_pEQKKKsrI6QKA-{GmlM-I;&K6CiO;VXwX&$<6Tv>hHg zyyx)5;X{Xy9X@q<>F}k)y-(i%`nDV%IK1od*x>_*XAYk@ym0v3;g!Q1pSu4(_zv$l zJaTv+evY08rVby$-?)!_@6H`QbNIsHD~C7Ft@pu}+je*e_g}QtdcMR6{@5+#`a|F0 zsl!JOpTf7kQSP(P;P!o|g#YV7a=zz{>+8GNQSLuB;4j!%>h~QU!Tl$0y*|I~!7WeX z@S(%U4xc)_bokQY-lyw*usT}~4;s}k?S zqYK5`@VD(F-ycJV_Z&Wimqlwm&NH~>FW_U1pTRAD1y42J`&@l}Ek1zf7fU@IxW)J3 zo?I>C!JE|A ztNgyMFWi>vJG|rY$l)p6-$|A`gxhkb@bQi^9tya{&mG?QLVbOkkCo-N>32zg0=VUm z;r_#=o<7{-Q-_ZnK7;!wJ#0OGO1R};I^6qWeSIyyV4Q~fB78w4(~WTa(Lh2sl!JO&mBH<_`=~U_ys%5ym`$p*ZW}Jc6jLU z9(>CO>wJ9Ibic;Dfv!$%I!9X@mT!r?22H!r;ZKC~SkI=tub#Nk7Sj~zaB zcDkCMecKT9UeP;;PA}h6NeWLpTl<;$?>joc;l<}K3KdDKj8+s zKG1P^1V3B%OEKK?3>==pFKEi~bOJ9om-iP6c)qpx3~uoYc)pFqFX0yNeXZV~=9UuQ zfZKALaI3ooZ|ZV=xYg5!+x_1FUTB^U-0uH|aLeC?TfZWB{4iPH9z1A?$MERk;(d7j z2=N4-`OWqD{1BczMm&T2JBW|q-79n+47fe7JE3cy9BzG{!Yxk$w?5C{h2}5eeXVm2 zFExGv&vumcUBc6y#4C8Rv-k>r-#pk~$9QhZ{Mapcq3*-|hf91LZuvv_Sm)X9!fl@I z2%eWR|8@`liwEg>HGIdf$oH2a{FFeh8;l)3b$IFUrNg~%)ca}6Z8CfePn=#yby*zh1f%`v|-+3(H;lIUaaBl~hw`2kLcN6!f_5Os?+q`LU^X$h39&mGlrMyDcqJjglAe$1|O@B;JNzP;S;*nQ^2jx8GNDfB|Ltw^k)uF z)EDqneF?Wdd*7;WFY9vyKGyy>;hsMC*n&6JeYmgQhL5+G{cQ*@)VuIt2Z@j1(T?H? zef78XbC?-C{G(hC%;AeuCC?P@RgaPDa_~&OqI+_Ga0QQ!m;B9(>iv)2C*FcD{;|_~ zxdGg}S3H8p&ymkv0{4%3(0U%N3?Axpsv~%Mqr6X=!|iv{OL+4ivfr4){kwj%?tcXj z)SKU~_aWIr`rLvy|1R%S1aMzHf=4^)@AJYJ4}Ijip9#Et#8vA$2XK2|GK1Uuk~#f? zzshsJ^nc2JZw`;Q-DX`+1us7<*MV2?v3m33dfy857TlgA4dBl?PR=*F4v*oMXW;P6 z;RU?;;oqF6_ZVdPJz4AWX&d(Egpz#B^ou8-h@U3#Z7{PBnQTjiITl|!+_eTo2<(a{) zjuM`{PnJ7}r|JuMroMz*o(ewJ_!T_dS>DTQez!h;f+xx6t_8RF0AAcK_w_n(%M-$_ zjxIcWhP)RU!HYX3e-CcsA%-WKrw_OBFogS0l+Q&5|F7fkSbr`?@cGlWmw6ZA-s5ju z$4}s)=Fj2d$4UGYZg~oLuJJQ?@iD1?0k8Z&uj^UDE#CWHeY^YHNqhrtd75ymqXqZ% zy)z#ksJG#^9Rql%@g2Br#~wW1LO$0qJUsu8>pt}1gZ<>XK?1k$`vZ7+w~WISZuJl0 zmM4Q-{W*NxmhbOVcz&xaw}AIvEcMUeHhxNYsd?sb8;1+H1peck|Wc{*^bBZS-junW)kka{Ax?N@tn%M-(Gzna2r91h_&4l}ro!x7xZ z&lsNRIG@069OiJ#GlknYEa0}EpTpC`_51{G@hf;5OT72}`gpKB4Y<|OgxhhU1&?(< z@58MRZMYp50=V^|0}r1n-`^wnV|JJCBR#mqC-9>>5hdsu50-Y@4(-Bo!sw;;6Kv$DEsiQy;z?69l$LiW6sDctgx z@Jj1kz%70S|GUOFF0J=%8*cm61-#Nc72KBFnAQ7c?mN5#-}WUke!6hW6T=^?@d0OJu({f*-8$6S&0}4xhu{u6dSpeSg{eQN2Hz_w4n&C{6g=HNFiWYyJ-0;v@J4 z8Xv=7@=e+93H)uRoVDIRr*O+Zg0~Nl?KOd0d;#B0<4d^3FX4M>{0eUI%`58t++X8; zxW#wiM{0Z*Zt*c);}g1WuOWP>@gw-*k<7D^!#}F=1^jxQU#^5(o+bQz&9j1AeDlhB z-!9U4A8yMH;FhQB@Yvx4hiCBn<^zG3TIUpQ@g@9s8oz*B{L10YAJ_ZySL+Yl@^s+4 zyj1sNaEp)Odun_FxA-Al<45rKcyfL|fm@ye{tnGk!YzIY|GdVp;5L73^C$JbU90gv z+~Pa%VpG{4cHtHu!~drF6S&0>;r^X+J~M(_d=7uyfwCP7xW&)muh94<+~U2T*85}L za(DngS@VZ*%hQ8@P2>A;i%;P{()bK+@e_v^4xhs}IY|1sgj;^^s(ODOqw!6+#kb+l z()bR1q5J0uZu4>V;V;%a1GvR!@I>RsaEqThyo8T`BJ=ev;n7EB{=f=ezJAm7^^+Am zJzCr=>-`Ll5pTdl^(NfvX~T;nB~JjiIy-QyGlW~6UAWa5!L807-1->9gEvc^eflO3 zS@$i4=W~5e3hrGep23^yBe>0LI)*Q?-0GaetRiID z&I)dQT*3X{NuA!$>fF03Lkf59>S~c)6!M2NJ@q zo*umUD5)ogTb+Hn)|tSq&H>!&OyO4N5bo*U8GNDZHGTJQSP9JW4Y{LWXPXMnTBlmZ@ z@WoT~z7O0!k3D$s42h57-tOXkxP49&xYaX+H=ihZGPu<_f?J(qxYapYT!@ zj|Du`^_{`gq)fvLA&Mw^QjNsPC9z3{B>WtyH-tvs~^@oAOGx*~#m+L1Jc=%x%Z#mq* zNS>RW!sF8Kc&70sJU&zM%;BZF_lx@Wjc=5C8gTzy@g}^uMZ5*C)O~ok zl=wEh{G)gP4{sIk!ISG{{Ks&svk$Lsl=uYh-y}YOCpU|yaPJoJAv{sf;l(GU{wdt* zEa0K`c?M6^OL#Gs{BwBp8Sw?YP;dOQzTMMnMAkW+M;r2O7;OXrWKY%xXCC{Iy@Lc1E@aRr`P6=M9PvPF{A1&t(aI13$ zZ~jpFP{M6|&f%fPFW}|nl4l7IXX4Fk>f62gTqUNqh#+{w+R&d!EeqUcjp@rJpmn)mg%; z|C0DQJh@$-2VTJamc%dN$-~7f_(Hw)tNM1&?~wKK;kMn|aN92haN93+;I>~1;kIAu z!fn5lz`dpPVF0%}Q+TL-8^W!h8N9ed@{i!nKZ}pysrn3FeqTSoaNF*4xP9IiaQhrB z;r4m2;P!c6!R_Un7hx6gZ*uJIAvyI7XngD2`K+~04f_3>y(*YlqY zUg-XO1h@VC7#{z1K*7@7ntI zEsqdyz{4ZO1Ns}~{k{&|wtEPVkCpf?+|K7Cc&70^xc?T(6T>t0A-uXMxc_WE@f zFoSzr%lIkbxxUA`q;D?q6+GKiyz$%mb{VU;;qeos&H(;~-^ueQA^drV%X0-0e6I(} zb6+w1X1#Bc!2hV8!vCS3!M%g!zS0=Jsd^6IUcG=nLA`_r!9DBozl2v;%6pED>+1bX zE*EdZizmtPq6-i8y{bMu(f4_W@M?G2E*X6Hp7sI$T=g8jzj^^bOudA^T73b3qk08D zLEXE)-kwp9r_# zbDYBM_Z$njJy$=2m-@SnCET9Jp2IEA0&dS^FX7Q%cdf^{_q+P`I{7?tA0Gcn-yesM zUnfWNhzR9yTlIsTW z_}Stec>Xh4uO2*nh}09q(@);L?(+cdJxk(Kc({l72%bG(>KVhwyGi^M-h7V4&*72A zui)XX+J_tJ{n>ltE7$e=aDNNAe%^*J)B||@FsZW(Z{8&Li6Z#xZk73>Q+V}Isb>iH zHW$y}slMl)!@Vt~{wX|FFW`0^eg+TqK0*nv-YfOY;gQBK;PJzxo+bQ{cguUk-i`I` zV)G!i93H^$dyWfk&r8G(AHZ$76L@v1e2>fF7C(cZ@szXI&mYd=7GJ@Czk@vQrbxBNZ$qAk}s2k__seP0i5&*zWeXX^ahIo#$cn!#h*iM%vaEc z7dl^Y7hdZ8?R|Kq^Pdmlh57`Z=;wU~53GK8Hk133jV0=Tk~}BVhG#lobQd1qA@h4g z@bJrW{@;TSc5ScUACKYo`@DVnA2(Q^=Ol3Zo!FM()qn7@Qcon`2!1w z&mCUDH{3|>UpM|(@3Xn@@DAL5Z#072?^*O6o;o~-C;IuC!fm;w!

CZmqBHow`44 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%0DXAM8~5%<}hXXlO0 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%0DGrebB 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

nli&mXHLU$5V4HX+P$`uy~4BvB=is?MnwQ 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 r;`+TkPia&Zn$ncBZQ25pu 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%0Dw$a*meQpZ8s6b!gCfv^@lQMVuxhpGxF!#z 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¥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%0AuTG0U#Jr4ujZ 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 z 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⁣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

AN#B4?!`y=dG@Z*^m2(Zo7ZqQHuCZ@ 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

hu49+n-CJ~N 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

-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 }BN60edLUJdvP){PyV=z9$SbsX1kFtLC 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�GXsK%D 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

X!yz|4P&KjKJ&9!@2B-w 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

&Y~q)PG_iPXMHAz~uEY17|FNDTxy9X=X- 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

Jua?8H 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≪^9@g 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%0DCmR|B@YG0{~j4LCT_FF-vW!1_8t@= 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

_|2EbXLj~xyJ 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

{8_4=j*mh^nw@CPO)=35#jciT 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 gl&C9BBY)*As>mKWu2ZkO4^YfCM*si- diff --git a/build/main.js b/build/main.js index ae6608b..4f7ba7f 100644 --- a/build/main.js +++ b/build/main.js @@ -68874,115 +68874,130 @@ function installBaseSelectorsOnce() { var dbRefs = 0; var setSelectors = false; var preloaded = false; +var initPromise = null; +var closePromise = null; +var getCurrentInitPromise = () => initPromise ?? Promise.resolve(); +var getCurrentClosePromise = () => closePromise ?? Promise.resolve(); var initDB = async ({ skipDbPreloading } = {}) => { - console.error("@@@@initDB", dbRefs); - if (isClosing) { - throw new Error("Cannot init DB while closing is in progress"); - } - installBaseSelectorsOnce(); - if (!dbRefs) { - const backend = import_npm_nconf2.default.get("database:backend"); - const persistence = backend || (production ? "fs" : void 0); - const options2 = import_npm_nconf2.default.get("database:backendOptions"); - const ARCHIVE_MODE = import_npm_nconf2.default.get("server:archiveMode"); - if (persistence && persistence !== "mem") { - const Ctor = (await globImport_database_ts2(`./database-${persistence}.ts`)).default; - const instance = new Ctor(options2[persistence]); - await instance.init(); - currentBackend = instance; - const cache2 = new import_npm_lru_cache.default({ - max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 - }); - currentCache = cache2; - const prefixes = Object.keys(prefixHandlers); - if (!setSelectors && true) { - esm_default("sbp/selectors/overwrite", { - "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { - if (!bypassCache) { - const lookupValue = cache2.get(prefixableKey); - if (lookupValue !== void 0) { - return lookupValue; + await getCurrentClosePromise(); + const thisInitPromise = initPromise ?? (async () => { + if (isClosing) { + throw new Error("Cannot init DB while closing is in progress"); + } + installBaseSelectorsOnce(); + if (!dbRefs) { + const backend = import_npm_nconf2.default.get("database:backend"); + const persistence = backend || (production ? "fs" : void 0); + const options2 = import_npm_nconf2.default.get("database:backendOptions"); + const ARCHIVE_MODE = import_npm_nconf2.default.get("server:archiveMode"); + if (persistence && persistence !== "mem") { + const Ctor = (await globImport_database_ts2(`./database-${persistence}.ts`)).default; + const instance = new Ctor(options2[persistence]); + await instance.init(); + currentBackend = instance; + const cache2 = new import_npm_lru_cache.default({ + max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 + }); + currentCache = cache2; + if (!setSelectors && true) { + esm_default("sbp/selectors/overwrite", { + "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { + if (!bypassCache) { + const lookupValue = cache2.get(prefixableKey); + if (lookupValue !== void 0) { + return lookupValue; + } } - } - const [prefix, key] = parsePrefixableKey(prefixableKey); - let value = await currentBackend.readData(key); - if (value === void 0) { - return; - } - value = prefixHandlers[prefix](value); - cache2.set(prefixableKey, value); - return value; - }, - "chelonia.db/set": async function(key, value) { - if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - const existingValue = await currentBackend.readData(key); - if (existingValue !== void 0) { - throw new Error("Cannot set already set immutable key"); + const [prefix, key] = parsePrefixableKey(prefixableKey); + let value = await currentBackend.readData(key); + if (value === void 0) { + return; } + value = prefixHandlers[prefix](value); + cache2.set(prefixableKey, value); + return value; + }, + "chelonia.db/set": async function(key, value) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + const existingValue = await currentBackend.readData(key); + if (existingValue !== void 0) { + throw new Error("Cannot set already set immutable key"); + } + } + await currentBackend.writeData(key, value); + const prefixes = Object.keys(prefixHandlers); + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/delete": async function(key) { + if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); + checkKey(key); + if (key.startsWith("_private_immutable")) { + throw new Error("Cannot delete immutable key"); + } + await currentBackend.deleteData(key); + const prefixes = Object.keys(prefixHandlers); + prefixes.forEach((prefix) => { + cache2.delete(prefix + key); + }); + }, + "chelonia.db/iterKeys": () => { + return currentBackend.iterKeys(); + }, + "chelonia.db/keyCount": () => { + return currentBackend.keyCount(); } - await currentBackend.writeData(key, value); - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/delete": async function(key) { - if (ARCHIVE_MODE) throw new Error("Unable to write in archive mode"); - checkKey(key); - if (key.startsWith("_private_immutable")) { - throw new Error("Cannot delete immutable key"); - } - await currentBackend.deleteData(key); - prefixes.forEach((prefix) => { - cache2.delete(prefix + key); - }); - }, - "chelonia.db/iterKeys": () => { - return currentBackend.iterKeys(); - }, - "chelonia.db/keyCount": () => { - return currentBackend.keyCount(); - } - }); - esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); - setSelectors = true; + }); + esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + setSelectors = true; + } } } - } else if (setSelectors && currentBackend) { - currentBackend.init(); - } - dbRefs++; - if (skipDbPreloading || preloaded) return; - await Promise.all([initVapid(), initZkpp()]); - preloaded = true; + dbRefs++; + if (skipDbPreloading || preloaded) return; + await Promise.all([initVapid(), initZkpp()]); + preloaded = true; + })(); + initPromise = thisInitPromise; + await thisInitPromise.finally(() => { + initPromise = null; + }); }; async function closeDB() { - console.error("@@@@closeDB", dbRefs); + await getCurrentInitPromise(); if (dbRefs > 1) { dbRefs--; return; } - if (isClosing) return; - isClosing = true; - try { - if (currentBackend) { - try { - await currentBackend.close(); - } catch (e2) { - console.error(e2, "Error closing DB"); + const thisClosePromise = closePromise ?? (async () => { + if (isClosing) return; + isClosing = true; + try { + if (currentBackend) { + try { + await currentBackend.close(); + } catch (e2) { + console.error(e2, "Error closing DB"); + } } - } - currentCache?.clear(); - dbRefs = 0; - if (false) { - preloaded = false; - currentCache = null; + currentCache?.clear(); + dbRefs = 0; currentBackend = null; + if (false) { + preloaded = false; + currentCache = null; + } + } finally { + isClosing = false; } - } finally { - isClosing = false; - } + })(); + closePromise = thisClosePromise; + await thisClosePromise.finally(() => { + closePromise = null; + }); } init_functions(); async function createEntryFromFile(filepath, multicode) { @@ -75977,6 +75992,7 @@ async function startApplicationServer() { await startServer2(); } async function serve(args) { + await initDB(); try { try { await startDashboardServer(); @@ -75995,9 +76011,6 @@ async function serve(args) { try { await startApplicationServer(); } catch (error2) { - if (error2 instanceof Error) { - console.error("@@@@@", error2.name, error2.message, error2.stack); - } console.error(red("\u274C Failed to start application server:"), error2); throw error2; } @@ -76006,6 +76019,8 @@ async function serve(args) { } catch (error2) { console.error(red("\u274C Failed to start server:"), error2); process12.exit(1); + } finally { + await closeDB(); } } var module11 = { diff --git a/src/serve.ts b/src/serve.ts index 52dfa72..5a674c4 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -7,6 +7,7 @@ import { deploy } from './deploy.ts' import { findManifestFiles } from './utils.ts' import { startServer } from './serve/index.ts' import { startDashboard } from './serve/dashboard-server.ts' +import { closeDB, initDB } from '~/serve/database.ts' type Params = { port: number, 'dashboard-port': number, directory: string, dev: boolean, 'manifests-dir': string } @@ -78,6 +79,7 @@ async function startApplicationServer (): Promise { } export async function serve (args: ArgumentsCamelCase) { + await initDB() try { // Start dashboard server on port 7000 first try { @@ -100,9 +102,6 @@ export async function serve (args: ArgumentsCamelCase) { try { await startApplicationServer() } catch (error) { - if (error instanceof Error) { - console.error('@@@@@', error.name, error.message, error.stack) - } console.error(colors.red('❌ Failed to start application server:'), error) throw error } @@ -111,6 +110,8 @@ export async function serve (args: ArgumentsCamelCase) { } catch (error) { console.error(colors.red('❌ Failed to start server:'), error) process.exit(1) + } finally { + await closeDB() } } diff --git a/src/serve/database.ts b/src/serve/database.ts index 279f92f..484735e 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -190,187 +190,155 @@ export default installBaseSelectorsOnce let dbRefs: number = 0 let setSelectors = false let preloaded = false + +// Operation queues to serialize access +let initPromise: Promise | null = null +let closePromise: Promise | null = null + +// Helper to get current operation promise +const getCurrentInitPromise = (): Promise => initPromise ?? Promise.resolve() +const getCurrentClosePromise = (): Promise => closePromise ?? Promise.resolve() + export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } = {}) => { - if (isClosing) { - throw new Error('Cannot init DB while closing is in progress') - } - installBaseSelectorsOnce() - if (!dbRefs) { - // If persistence must be enabled: - // - load and initialize the selected storage backend - // - then overwrite 'chelonia.db/get' and '-set' to use it with an LRU cache - const backend = nconf.get('database:backend') - // Defaults to `fs` in production. - const persistence = backend || (production ? 'fs' : undefined) - const options = nconf.get('database:backendOptions') - const ARCHIVE_MODE = nconf.get('server:archiveMode') + // Await any ongoing close operation first + await getCurrentClosePromise() - if (persistence && persistence !== 'mem') { - const Ctor = (await import(`./database-${persistence}.ts`)).default - const instance = new Ctor(options[persistence]) as DatabaseBackend - await instance.init() - currentBackend = instance + // Queue this init operation + const thisInitPromise = initPromise ?? (async () => { + if (isClosing) { + throw new Error('Cannot init DB while closing is in progress') + } - // https://github.com/isaacs/node-lru-cache#usage - const cache = new LRU({ - max: nconf.get('database:lruNumItems') ?? 10000 - }) - currentCache = cache + installBaseSelectorsOnce() + + if (!dbRefs) { + // First-time initialization + const backend = nconf.get('database:backend') + const persistence = backend || (production ? 'fs' : undefined) + const options = nconf.get('database:backendOptions') + const ARCHIVE_MODE = nconf.get('server:archiveMode') + + if (persistence && persistence !== 'mem') { + const Ctor = (await import(`./database-${persistence}.ts`)).default + const instance = new Ctor(options[persistence]) as DatabaseBackend + await instance.init() + currentBackend = instance + + const cache = new LRU({ + max: nconf.get('database:lruNumItems') ?? 10000 + }) + currentCache = cache - const prefixes = Object.keys(prefixHandlers) - if (!setSelectors && (import.meta as ImportMeta).lockDbSelectors) { - sbp('sbp/selectors/overwrite', { - 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { - if (!bypassCache) { - const lookupValue = cache.get(prefixableKey) - if (lookupValue !== undefined) { - return lookupValue + if (!setSelectors && (import.meta as ImportMeta).lockDbSelectors) { + sbp('sbp/selectors/overwrite', { + 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { + if (!bypassCache) { + const lookupValue = cache.get(prefixableKey) + if (lookupValue !== undefined) { + return lookupValue + } } - } - const [prefix, key] = parsePrefixableKey(prefixableKey) - let value = await currentBackend!.readData(key) - if (value === undefined) { - return - } - value = prefixHandlers[prefix](value) as string | Buffer - cache.set(prefixableKey, value) - return value - }, - 'chelonia.db/set': async function (key: string, value: Buffer | string): Promise { - if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') - checkKey(key) - if (key.startsWith('_private_immutable')) { - const existingValue = await currentBackend!.readData(key) - if (existingValue !== undefined) { - throw new Error('Cannot set already set immutable key') + const [prefix, key] = parsePrefixableKey(prefixableKey) + let value = await currentBackend!.readData(key) + if (value === undefined) { + return } + value = prefixHandlers[prefix](value) as string | Buffer + cache.set(prefixableKey, value) + return value + }, + 'chelonia.db/set': async function (key: string, value: Buffer | string): Promise { + if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') + checkKey(key) + if (key.startsWith('_private_immutable')) { + const existingValue = await currentBackend!.readData(key) + if (existingValue !== undefined) { + throw new Error('Cannot set already set immutable key') + } + } + await currentBackend!.writeData(key, value) + const prefixes = Object.keys(prefixHandlers) + prefixes.forEach(prefix => { + cache.delete(prefix + key) + }) + }, + 'chelonia.db/delete': async function (key: string): Promise { + if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') + checkKey(key) + if (key.startsWith('_private_immutable')) { + throw new Error('Cannot delete immutable key') + } + await currentBackend!.deleteData(key) + const prefixes = Object.keys(prefixHandlers) + prefixes.forEach(prefix => { + cache.delete(prefix + key) + }) + }, + 'chelonia.db/iterKeys': () => { + return currentBackend!.iterKeys() + }, + 'chelonia.db/keyCount': () => { + return currentBackend!.keyCount() } - await currentBackend!.writeData(key, value) - // `get` uses `prefixableKey` as key, which now that the value is updated - // is stale. We delete all prefixed key variants from the cache to - // avoid serving stale data. Note that because of prefixes, `cache.set` - // can't be (easily) used to set the key, as transformations could happen - // on the unprefixed version. - // Note: 2025-03-24: We benchmarked `.forEach`, `for of` and `for`. - // Which one was faster depended on the browser, with no clear overall - // winner, but `.forEach` was faster on Chrome, which uses the same - // engine as Node.JS (V8). - prefixes.forEach(prefix => { - cache.delete(prefix + key) - }) - }, - 'chelonia.db/delete': async function (key: string): Promise { - if (ARCHIVE_MODE) throw new Error('Unable to write in archive mode') - checkKey(key) - if (key.startsWith('_private_immutable')) { - throw new Error('Cannot delete immutable key') - } - await currentBackend!.deleteData(key) - // `get` uses `prefixableKey` as key, which now that the value is updated - // is stale. We delete all prefixed key variants from the cache to - // avoid serving stale data. - prefixes.forEach(prefix => { - cache.delete(prefix + key) - }) - }, - 'chelonia.db/iterKeys': () => { - return currentBackend!.iterKeys() - }, - 'chelonia.db/keyCount': () => { - return currentBackend!.keyCount() - } - }) - sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) - setSelectors = true + }) + sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + setSelectors = true + } } } - } else if ((import.meta as ImportMeta).lockDbSelectors && setSelectors && currentBackend) { - // Re-open DB - currentBackend!.init() - } - dbRefs++ - if (skipDbPreloading || preloaded) return - /* - // Preloading logic preserved for historical reasons. Preloading should no - // longer be necessary, since `chel deploy` can be used for accomplishing - // the same in a more reliable way and without requiring the `fs` backend. - // - // TODO: Update this to only run when persistence is disabled when `chel deploy` can target SQLite. - if (persistence !== 'fs' || options.fs.dirname !== dbRootPath) { - // Remember to keep these values up-to-date. - const HASH_LENGTH = 56 - // Preload contract source files and contract manifests into Chelonia DB. - // Note: the data folder may contain other files if the `fs` persistence mode - // has been used before. We won't load them here; that's the job of `chel migrate`. - // Note: our target files are currently deployed with unprefixed hashes as file names. - // We can take advantage of this to recognize them more easily. - // TODO: Update this code when `chel deploy` no longer generates unprefixed keys. - const keys = (await readdir(dataFolder)) - // Skip some irrelevant files. - .filter(k => { - if (k.length !== HASH_LENGTH) return false - const parsed = maybeParseCID(k) - return parsed && ([ - multicodes.SHELTER_CONTRACT_MANIFEST, - multicodes.SHELTER_CONTRACT_TEXT].includes(parsed.code) - ) - }) - const numKeys = keys.length - let numVisitedKeys = 0 - let numNewKeys = 0 - const savedProgress = { value: 0, numKeys: 0 } + dbRefs++ - console.info('[chelonia.db] Preloading...') - for (const key of keys) { - // Skip keys which are already in the DB. - if (!persistence || !await sbp('chelonia.db/get', key)) { - // Load only contract source files and contract manifests. - const value = await readFile(path.join(dataFolder, key), 'utf8') - await sbp('chelonia.db/set', key, value) - numNewKeys++ - } - numVisitedKeys++ - const progress = numVisitedKeys === numKeys ? 100 : Math.floor(100 * numVisitedKeys / numKeys) - // Display progress lines between at least 10% increments, and no more than every 10 visited keys. - if (progress === 100 || (progress - savedProgress.value >= 10 && numVisitedKeys - savedProgress.numKeys >= 10)) { - console.info(`[chelonia.db] Preloading... ${progress}% done`) - savedProgress.numKeys = numVisitedKeys - savedProgress.value = progress - } - } - numNewKeys && console.info(`[chelonia.db] Preloaded ${numNewKeys} new entries`) - } - */ - await Promise.all([initVapid(), initZkpp()]) - preloaded = true + if (skipDbPreloading || preloaded) return + + await Promise.all([initVapid(), initZkpp()]) + preloaded = true + })() + + initPromise = thisInitPromise + await thisInitPromise.finally(() => { + initPromise = null + }) } export async function closeDB (): Promise { + // Await any ongoing init operation first + await getCurrentInitPromise() + if (dbRefs > 1) { dbRefs-- return } - if (isClosing) return - isClosing = true - try { - if (currentBackend) { - try { - await currentBackend.close() - } catch (e) { - console.error(e, 'Error closing DB') + + // Queue this close operation + const thisClosePromise = closePromise ?? (async () => { + if (isClosing) return + + isClosing = true + try { + if (currentBackend) { + try { + await currentBackend.close() + } catch (e) { + console.error(e, 'Error closing DB') + } } - } - currentCache?.clear() - dbRefs = 0 - if (!(import.meta as ImportMeta).lockDbSelectors) { - preloaded = false - currentCache = null + currentCache?.clear() + dbRefs = 0 currentBackend = null + if (!(import.meta as ImportMeta).lockDbSelectors) { + preloaded = false + currentCache = null + } + } finally { + isClosing = false } - } finally { - isClosing = false - } + })() + + closePromise = thisClosePromise + await thisClosePromise.finally(() => { + closePromise = null + }) } export * from './db-utils.ts' From d6bc4c6546e09a3a01b13170ebf5745bf2358ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:21:53 +0000 Subject: [PATCH 54/71] Various fixes: * Add `etag()` middleware to all static asset paths * Add new options to the `chel` command for preloading and for `chelonia.json` path * Switch dashboard to Node API (was `Deno.serve`) * Add missing import to dashboard so that it loads --- build/main.js | 231 +++++++++++++++++++++++++--------- scripts/dashboard-esbuild.ts | 3 +- src/pin.ts | 13 +- src/serve.ts | 46 +++++-- src/serve/dashboard-server.ts | 19 ++- src/serve/dashboard/main.ts | 1 + src/serve/routes.ts | 8 +- src/serve/server.ts | 4 +- 8 files changed, 247 insertions(+), 78 deletions(-) diff --git a/build/main.js b/build/main.js index 4f7ba7f..64ab03c 100644 --- a/build/main.js +++ b/build/main.js @@ -12771,29 +12771,29 @@ var require_nconf = __commonJS({ "node_modules/.deno/nconf@0.13.0/node_modules/nconf/lib/nconf.js"(exports2, module14) { var common4 = require_common(); var Provider = require_provider().Provider; - var nconf8 = module14.exports = new Provider(); - nconf8.version = require_package().version; - nconf8.__defineGetter__("Argv", function() { + var nconf9 = module14.exports = new Provider(); + nconf9.version = require_package().version; + nconf9.__defineGetter__("Argv", function() { return require_argv().Argv; }); - nconf8.__defineGetter__("Env", function() { + nconf9.__defineGetter__("Env", function() { return require_env().Env; }); - nconf8.__defineGetter__("File", function() { + nconf9.__defineGetter__("File", function() { return require_file().File; }); - nconf8.__defineGetter__("Literal", function() { + nconf9.__defineGetter__("Literal", function() { return require_literal().Literal; }); - nconf8.__defineGetter__("Memory", function() { + nconf9.__defineGetter__("Memory", function() { return require_memory().Memory; }); - nconf8.key = common4.key; - nconf8.path = common4.path; - nconf8.loadFiles = common4.loadFiles; - nconf8.loadFilesSync = common4.loadFilesSync; - nconf8.formats = require_formats(); - nconf8.Provider = Provider; + nconf9.key = common4.key; + nconf9.path = common4.path; + nconf9.loadFiles = common4.loadFiles; + nconf9.loadFilesSync = common4.loadFilesSync; + nconf9.formats = require_formats(); + nconf9.Provider = Provider; } }); // @__NO_SIDE_EFFECTS__ @@ -61591,7 +61591,7 @@ var require_websocket_server = __commonJS({ } } }); -var import_npm_nconf7 = __toESM(require_nconf()); +var import_npm_nconf8 = __toESM(require_nconf()); function getLineColFromPtr(string3, ptr) { let lines = string3.slice(0, ptr).split(/\r\n|\n|\r/g); return [lines.length, lines.pop().length + 1]; @@ -69650,6 +69650,7 @@ var module9 = { return migrate(argv); } }; +var import_npm_nconf4 = __toESM(require_nconf()); var VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/; var RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g; var projectRoot; @@ -69778,7 +69779,7 @@ async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { await copyFile(sourcePath, targetPath); } async function loadCheloniaConfig() { - const configPath = join62(projectRoot, "chelonia.json"); + const configPath = import_npm_nconf4.default.get("appManifest") || join62(projectRoot, "chelonia.json"); cheloniaConfig = { contracts: {} }; if (existsSync(configPath)) { try { @@ -69802,7 +69803,7 @@ async function updateCheloniaConfig(fullContractName, contractName, version3, ma version: version3, path: pinnedManifestPath }; - const configPath = join62(projectRoot, "chelonia.json"); + const configPath = import_npm_nconf4.default.get("appManifest") || join62(projectRoot, "chelonia.json"); const configContent = JSON.stringify(cheloniaConfig, null, 2) + "\n"; await writeFile2(configPath, configContent, "utf8"); console.log(green("\u2705 Saved chelonia.json")); @@ -69818,7 +69819,11 @@ var module10 = { describe: "Output directory", requiresArg: false, string: true - }).alias("d", "dir").positional("manifest", { + }).alias("d", "dir").option("app-manifest", { + default: "", + describe: "Location of chelonia.json", + string: true + }).alias("i", "app-manifest").alias("appManifest", "app-manifest").positional("manifest", { describe: "Manifest file path", demandOption: true, type: "string" @@ -73430,6 +73435,101 @@ var bodyLimit = (options2) => { } }; }; +var mergeBuffers = (buffer1, buffer2) => { + if (!buffer1) { + return buffer2; + } + const merged = new Uint8Array( + new ArrayBuffer(buffer1.byteLength + buffer2.byteLength) + ); + merged.set(new Uint8Array(buffer1), 0); + merged.set(buffer2, buffer1.byteLength); + return merged; +}; +var generateDigest = async (stream, generator) => { + if (!stream) { + return null; + } + let result = void 0; + const reader = stream.getReader(); + for (; ; ) { + const { value, done } = await reader.read(); + if (done) { + break; + } + result = await generator(mergeBuffers(result, value)); + } + if (!result) { + return null; + } + return Array.prototype.map.call(new Uint8Array(result), (x3) => x3.toString(16).padStart(2, "0")).join(""); +}; +var RETAINED_304_HEADERS = [ + "cache-control", + "content-location", + "date", + "etag", + "expires", + "vary" +]; +var stripWeak = (tag3) => tag3.replace(/^W\//, ""); +function etagMatches(etag2, ifNoneMatch) { + return ifNoneMatch != null && ifNoneMatch.split(/,\s*/).some((t) => stripWeak(t) === stripWeak(etag2)); +} +function initializeGenerator(generator) { + if (!generator) { + if (crypto && crypto.subtle) { + generator = (body) => crypto.subtle.digest( + { + name: "SHA-1" + }, + body + ); + } + } + return generator; +} +var etag = (options2) => { + const retainedHeaders = options2?.retainedHeaders ?? RETAINED_304_HEADERS; + const weak = options2?.weak ?? false; + const generator = initializeGenerator(options2?.generateDigest); + return async function etag2(c, next) { + const ifNoneMatch = c.req.header("If-None-Match") ?? null; + await next(); + const res = c.res; + let etag3 = res.headers.get("ETag"); + if (!etag3) { + if (!generator) { + return; + } + const hash3 = await generateDigest( + // This type casing avoids the type error for `deno publish` + res.clone().body, + generator + ); + if (hash3 === null) { + return; + } + etag3 = weak ? `W/"${hash3}"` : `"${hash3}"`; + } + if (etagMatches(etag3, ifNoneMatch)) { + c.res = new Response(null, { + status: 304, + statusText: "Not Modified", + headers: { + ETag: etag3 + } + }); + c.res.headers.forEach((_, key) => { + if (retainedHeaders.indexOf(key.toLowerCase()) === -1) { + c.res.headers.delete(key); + } + }); + } else { + c.res.headers.set("ETag", etag3); + } + }; +}; var import_npm_pino = __toESM(require_pino()); var prettyPrint = process6.env.NODE_ENV === "development" || process6.env.CI || process6.env.CYPRESS_RECORD_KEY || process6.env.PRETTY; function logMethod(args, method) { @@ -73477,7 +73577,7 @@ function initializeLogger() { console.error = logger.error.bind(logger); } var logger_default = logger; -var import_npm_nconf4 = __toESM(require_nconf()); +var import_npm_nconf5 = __toESM(require_nconf()); init_zod(); function extractBearer(c) { const authorization = c.req.header("authorization"); @@ -73654,7 +73754,7 @@ function installRateLimiterSelectorsOnce() { } function getStaticServeConfig() { const isCheloniaDashboard = process7.env.IS_CHELONIA_DASHBOARD_DEV; - const appDir = import_npm_nconf4.default.get("server:appDir") || "."; + const appDir = import_npm_nconf5.default.get("server:appDir") || "."; const dashboardDir = import.meta.dirname || "./build/dist-dashboard"; return { distAssets: path5.resolve(path5.join(isCheloniaDashboard ? dashboardDir : appDir, "assets")), @@ -73700,7 +73800,6 @@ function serveAsset(c, subpath, assetsDir) { return Deno.readFile(filePath).then((file) => { const headers = {}; if (basename72.includes("-cached")) { - headers["ETag"] = `"${basename72}"`; headers["Cache-Control"] = "public,max-age=31536000,immutable"; } if (subpath.includes("js/sw-")) { @@ -73717,12 +73816,12 @@ function registerRoutes(app) { limiter.disconnect(); clearInterval(limiter.interval); } - const FILE_UPLOAD_MAX_BYTES = import_npm_nconf4.default.get("server:fileUploadMaxBytes") || 30 * MEGABYTE; - const SIGNUP_LIMIT_MIN = import_npm_nconf4.default.get("server:signup:limit:minute") || 2; - const SIGNUP_LIMIT_HOUR = import_npm_nconf4.default.get("server:signup:limit:hour") || 10; - const SIGNUP_LIMIT_DAY = import_npm_nconf4.default.get("server:signup:limit:day") || 50; - const SIGNUP_LIMIT_DISABLED = process7.env.NODE_ENV !== "production" || import_npm_nconf4.default.get("server:signup:limit:disabled"); - const ARCHIVE_MODE = import_npm_nconf4.default.get("server:archiveMode"); + const FILE_UPLOAD_MAX_BYTES = import_npm_nconf5.default.get("server:fileUploadMaxBytes") || 30 * MEGABYTE; + const SIGNUP_LIMIT_MIN = import_npm_nconf5.default.get("server:signup:limit:minute") || 2; + const SIGNUP_LIMIT_HOUR = import_npm_nconf5.default.get("server:signup:limit:hour") || 10; + const SIGNUP_LIMIT_DAY = import_npm_nconf5.default.get("server:signup:limit:day") || 50; + const SIGNUP_LIMIT_DISABLED = process7.env.NODE_ENV !== "production" || import_npm_nconf5.default.get("server:signup:limit:disabled"); + const ARCHIVE_MODE = import_npm_nconf5.default.get("server:archiveMode"); const limiterPerMinute = new import_npm_bottleneck.default.Group({ strategy: import_npm_bottleneck.default.strategy.LEAK, highWater: 0, @@ -73783,7 +73882,7 @@ function registerRoutes(app) { if (name !== "gi.contracts/identity") { throw new HTTPException(401, { message: "This contract type requires ownership information" }); } - if (import_npm_nconf4.default.get("server:signup:disabled")) { + if (import_npm_nconf5.default.get("server:signup:disabled")) { throw new HTTPException(403, { message: "Registration disabled" }); } if (!SIGNUP_LIMIT_DISABLED) { @@ -74308,21 +74407,21 @@ function registerRoutes(app) { } ); app.get("/serverMessages", function(c) { - const messages = import_npm_nconf4.default.get("server:messages"); + const messages = import_npm_nconf5.default.get("server:messages"); if (!messages) return c.json([]); return c.json(messages, 200, { "Cache-Control": "no-store" }); }); - app.get("/assets/:subpath{.+}", function(c) { + app.get("/assets/:subpath{.+}", etag(), function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); if (isCheloniaDashboard) { - app.get("/dashboard/assets/:subpath{.+}", function(c) { + app.get("/dashboard/assets/:subpath{.+}", etag(), function(c) { const subpath = c.req.param("subpath"); return serveAsset(c, subpath, staticServeConfig.distAssets); }); } - app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", async function(c) { + app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", etag(), async function(c) { try { const file = await Deno.readFile(staticServeConfig.distIndexHtml); return c.body(file, 200, { "Content-Type": "text/html" }); @@ -75052,7 +75151,7 @@ var publicMethods2 = { socket.send(createErrorResponse({ ...request }), () => socket.terminate()); } }; -var import_npm_nconf5 = __toESM(require_nconf()); +var import_npm_nconf6 = __toESM(require_nconf()); var currentApp = null; var currentHttpServer = null; var currentOwnerSizeTotalWorker = void 0; @@ -75301,16 +75400,16 @@ function installServerSelectorsOnce() { }); } async function startServer() { - const appDir = import_npm_nconf5.default.get("server:appDir") || process9.cwd(); - const ARCHIVE_MODE = import_npm_nconf5.default.get("server:archiveMode"); - const host = import_npm_nconf5.default.get("server:host") || "0.0.0.0"; - const port = import_npm_nconf5.default.get("server:port") ?? 8e3; + const appManifest = import_npm_nconf6.default.get("appManifest") || join72(import_npm_nconf6.default.get("server:appDir") || process9.cwd(), "chelonia.json"); + const ARCHIVE_MODE = import_npm_nconf6.default.get("server:archiveMode"); + const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; + const port = import_npm_nconf6.default.get("server:port") ?? 8e3; if (CREDITS_WORKER_TASK_TIME_INTERVAL && OWNER_SIZE_TOTAL_WORKER_TASK_TIME_INTERVAL > CREDITS_WORKER_TASK_TIME_INTERVAL) { console.error("The size calculation worker must run more frequently than the credits worker for accurate billing"); throw new Error("The size calculation worker must run more frequently than the credits worker for accurate billing"); } try { - currentManifest = (await import(pathToFileURL(join72(appDir, "chelonia.json")).toString(), { + currentManifest = (await import(pathToFileURL(appManifest).toString(), { with: { type: "json" } })).default; } catch { @@ -75901,22 +76000,22 @@ var upgradeWebSocket = defineWebSocketHelper(async (c, events, options2) => { socket.onerror = (evt) => events.onError?.(evt, wsContext); return response; }); -var import_npm_nconf6 = __toESM(require_nconf()); +var import_npm_nconf7 = __toESM(require_nconf()); var getDashboardPath = () => { const baseDir = import.meta.dirname || path6.join(process11.cwd(), "build"); const dashboardPath = path6.resolve(baseDir, "dist-dashboard"); return dashboardPath; }; async function startDashboard() { - const port = import_npm_nconf6.default.get("server:dashboardPort"); - const host = import_npm_nconf6.default.get("server:host") || "0.0.0.0"; + const port = import_npm_nconf7.default.get("server:dashboardPort"); + const host = import_npm_nconf7.default.get("server:host") || "0.0.0.0"; const dashboardRoot = getDashboardPath(); const app = new Hono2(); const staticMiddleware = serveStatic2({ root: dashboardRoot, rewriteRequestPath: (p) => p }); const indexMiddleware = serveStatic2({ path: path6.join(dashboardRoot, "index.html") }); - app.get("/assets/*", staticMiddleware); - app.get("/dashboard", indexMiddleware); - app.get("/dashboard/", indexMiddleware); + app.get("/assets/*", etag(), staticMiddleware); + app.get("/dashboard", etag(), indexMiddleware); + app.get("/dashboard/", etag(), indexMiddleware); app.get("/*", async (c) => { const staticResponse = await staticMiddleware(c, async () => { }); @@ -75927,28 +76026,40 @@ async function startDashboard() { }); return indexResponse || c.text("Not Found", 404); }); - await new Promise((resolve82) => { - Deno.serve({ port, hostname: host, onListen: () => resolve82() }, app.fetch); + const server = createAdaptorServer({ fetch: app.fetch }); + await new Promise((resolve82, reject) => { + server.listen(port, host, () => { + const addr = server.address(); + const uri = `http://${addr.address}:${addr.port}`; + console.info("Dashboard server running at:", uri); + resolve82(uri); + }).once("error", reject); }); } -async function watch(args) { +async function deployManifests(args) { const dir = args["manifests-dir"]; + if (!dir) return null; const manifests = await findManifestFiles(dir); await deploy({ ...args, manifests: Array.from(manifests) }); + return dir; +} +async function watch(args) { + const dir = await deployManifests(args); + if (dir === null) return; const manifestSet = /* @__PURE__ */ new Set(); const watcher = Deno.watchFs(dir, { recursive: true }); const queueName = "internal:manifests-watch"; const debouncedRedeploy = debounce(() => { if (manifestSet.size === 0) return; esm_default("okTurtles.eventQueue/queueEvent", queueName, () => { - const manifests2 = Array.from(manifestSet); + const manifests = Array.from(manifestSet); manifestSet.clear(); deploy({ ...args, - manifests: manifests2 + manifests }).catch((e2) => { console.warn(e2, "Error deploying contracts"); }); @@ -75962,8 +76073,8 @@ async function watch(args) { continue; } if (event.kind !== "create" && event.kind !== "modify") continue; - const manifests2 = event.paths.filter((path8) => path8.toLowerCase().endsWith(".manifest.json")); - for (const manifestPath of manifests2) { + const manifests = event.paths.filter((path8) => path8.toLowerCase().endsWith(".manifest.json")); + for (const manifestPath of manifests) { try { await esm_default("okTurtles.eventQueue/queueEvent", queueName, async () => { const realPath = await Deno.realPath(manifestPath); @@ -76000,13 +76111,15 @@ async function serve(args) { console.error(red("\u274C Failed to start dashboard server:"), error2); throw error2; } - if (args.dev) { - try { + try { + if (args.dev) { await watch(args); - } catch (error2) { - console.error(red("\u274C Failed to preload contracts:"), error2); - throw error2; + } else { + await deployManifests(args); } + } catch (error2) { + console.error(red("\u274C Failed to preload contracts:"), error2); + throw error2; } try { await startApplicationServer(); @@ -76045,7 +76158,11 @@ var module11 = { describe: "Directory for contracts", requiresArg: true, string: true - }).alias("m", "manifests-dir").positional("directory", { + }).alias("m", "manifests-dir").option("app-manifest", { + default: "", + describe: "Location of chelonia.json", + string: true + }).alias("i", "app-manifest").alias("appManifest", "app-manifest").positional("directory", { default: ".", describe: "Directory", type: "string" @@ -80308,7 +80425,7 @@ var parseArgs = () => { }; var parseArgs_default = parseArgs; var parseConfig = () => { - import_npm_nconf7.default.env({ + import_npm_nconf8.default.env({ separator: "__", parseValues: true }).argv(parseArgs_default()).file({ file: "chel.toml", format: { parse: parse8, stringify } }).defaults({ diff --git a/scripts/dashboard-esbuild.ts b/scripts/dashboard-esbuild.ts index 162ae61..0e265d8 100644 --- a/scripts/dashboard-esbuild.ts +++ b/scripts/dashboard-esbuild.ts @@ -80,7 +80,8 @@ async function build () { '@pages': './src/serve/dashboard/views/pages', '@forms': './src/serve/dashboard/views/components/forms', '@validators': './src/serve/dashboard/views/utils/validators', - '@assets': './src/serve/dashboard/assets' + '@assets': './src/serve/dashboard/assets', + 'vue': 'vue/dist/vue.js' } try { diff --git a/src/pin.ts b/src/pin.ts index 51baf52..f1f45b2 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -5,6 +5,8 @@ import { basename, dirname, join } from 'node:path' import process from 'node:process' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { exit } from './utils.ts' +// @deno-types="npm:@types/nconf" +import nconf from 'npm:nconf' const VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/ // deno-lint-ignore no-control-regex @@ -185,7 +187,7 @@ async function copyFileIfNeeded ( } async function loadCheloniaConfig () { - const configPath = join(projectRoot, 'chelonia.json') + const configPath = nconf.get('appManifest') || join(projectRoot, 'chelonia.json') cheloniaConfig = { contracts: {} } if (existsSync(configPath)) { @@ -214,7 +216,7 @@ async function updateCheloniaConfig (fullContractName: string, contractName: str path: pinnedManifestPath } - const configPath = join(projectRoot, 'chelonia.json') + const configPath = nconf.get('appManifest') || join(projectRoot, 'chelonia.json') const configContent = JSON.stringify(cheloniaConfig, null, 2) + '\n' await writeFile(configPath, configContent, 'utf8') @@ -237,6 +239,13 @@ export const module = { string: true }) .alias('d', 'dir') + .option('app-manifest', { + default: '', + describe: 'Location of chelonia.json', + string: true + }) + .alias('i', 'app-manifest') + .alias('appManifest', 'app-manifest') .positional('manifest', { describe: 'Manifest file path', demandOption: true, diff --git a/src/serve.ts b/src/serve.ts index 5a674c4..d9322ad 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -9,16 +9,32 @@ import { startServer } from './serve/index.ts' import { startDashboard } from './serve/dashboard-server.ts' import { closeDB, initDB } from '~/serve/database.ts' -type Params = { port: number, 'dashboard-port': number, directory: string, dev: boolean, 'manifests-dir': string } +type Params = { + port: number, + 'dashboard-port': number, + directory: string, + dev: boolean, + 'manifests-dir': string, + 'app-manifest': string +} -async function watch (args: ArgumentsCamelCase): Promise { +async function deployManifests (args: ArgumentsCamelCase): Promise { const dir = args['manifests-dir'] + if (!dir) return null + const manifests = await findManifestFiles(dir) await deploy({ ...args, manifests: Array.from(manifests) }) + return dir +} + +async function watch (args: ArgumentsCamelCase): Promise { + const dir = await deployManifests(args) + if (dir === null) return + const manifestSet = new Set() const watcher = Deno.watchFs(dir, { recursive: true }) const queueName = 'internal:manifests-watch' @@ -89,13 +105,22 @@ export async function serve (args: ArgumentsCamelCase) { throw error } - if (args.dev) { - try { + // If we're running in 'development' mode, then we preload contracts from + // the `manifests-dir` directory _and_ watch for changes to automatically + // re-deploy. + // If we're running in 'production' mode, then we also preload contracts + // from the `manifests-dir` directory, but we do _not_ watch for changes. + // This means that, in production mode, deploying changes requires a manual + // invocation of `chel deploy` or restarting the server. + try { + if (args.dev) { await watch(args) - } catch (error) { - console.error(colors.red('❌ Failed to preload contracts:'), error) - throw error + } else { + await deployManifests(args) } + } catch (error) { + console.error(colors.red('❌ Failed to preload contracts:'), error) + throw error } // Start application server on port 8000 second @@ -150,6 +175,13 @@ export const module = { string: true }) .alias('m', 'manifests-dir') + .option('app-manifest', { + default: '', + describe: 'Location of chelonia.json', + string: true + }) + .alias('i', 'app-manifest') + .alias('appManifest', 'app-manifest') .positional('directory', { default: '.', describe: 'Directory', diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index cf2529d..52fdcd4 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -2,6 +2,8 @@ import path from 'node:path' import process from 'node:process' import { Hono } from 'npm:hono' import { serveStatic } from 'npm:hono/deno' +import { createAdaptorServer } from 'npm:@hono/node-server' +import { etag } from 'npm:hono/etag' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' @@ -24,10 +26,10 @@ export async function startDashboard (): Promise { const staticMiddleware = serveStatic({ root: dashboardRoot, rewriteRequestPath: (p) => p }) const indexMiddleware = serveStatic({ path: path.join(dashboardRoot, 'index.html') }) - app.get('/assets/*', staticMiddleware) + app.get('/assets/*', etag(), staticMiddleware) - app.get('/dashboard', indexMiddleware) - app.get('/dashboard/', indexMiddleware) + app.get('/dashboard', etag(), indexMiddleware) + app.get('/dashboard/', etag(), indexMiddleware) // SPA fallback: try static file first, then serve index.html for SPA routing app.get('/*', async (c) => { @@ -41,8 +43,15 @@ export async function startDashboard (): Promise { return indexResponse || c.text('Not Found', 404) }) - await new Promise((resolve) => { - Deno.serve({ port, hostname: host, onListen: () => resolve() }, app.fetch) + // Start listening + const server = createAdaptorServer({ fetch: app.fetch }) + await new Promise((resolve, reject) => { + server.listen(port, host, () => { + const addr = server.address() as { address: string; port: number } + const uri = `http://${addr.address}:${addr.port}` + console.info('Dashboard server running at:', uri) + resolve(uri) + }).once('error', reject) }) } diff --git a/src/serve/dashboard/main.ts b/src/serve/dashboard/main.ts index 04f22c9..647d16a 100644 --- a/src/serve/dashboard/main.ts +++ b/src/serve/dashboard/main.ts @@ -1,4 +1,5 @@ import sbp from 'npm:@sbp/sbp' +import 'npm:@sbp/okturtles.data' import Vue from 'npm:vue' import router from './controller/router.ts' import store from './model/state.ts' diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 8fc9e94..db60c99 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -18,6 +18,7 @@ import { Readable } from 'node:stream' import { zValidator } from 'npm:@hono/zod-validator' import type { Context, Hono, MiddlewareHandler } from 'npm:hono' import { bodyLimit } from 'npm:hono/body-limit' +import { etag } from 'npm:hono/etag' import { appendToIndexFactory, lookupUltimateOwner } from './database.ts' import logger from './logger.ts' import { getChallenge, getContractSalt, redeemSaltRegistrationToken, redeemSaltUpdateToken, register, registrationKey, updateContractSalt } from './zkppSalt.ts' @@ -264,7 +265,6 @@ function serveAsset (c: Context, subpath: string, assetsDir: string): Promise = {} if (basename.includes('-cached')) { - headers['ETag'] = `"${basename}"` headers['Cache-Control'] = 'public,max-age=31536000,immutable' } @@ -1034,21 +1034,21 @@ export function registerRoutes (app: Hono): void { // SPA routes - app.get('/assets/:subpath{.+}', function (c) { + app.get('/assets/:subpath{.+}', etag(), function (c) { const subpath = c.req.param('subpath') return serveAsset(c, subpath, staticServeConfig.distAssets) }) // Dashboard-specific assets route (when IS_CHELONIA_DASHBOARD_DEV is set) if (isCheloniaDashboard) { - app.get('/dashboard/assets/:subpath{.+}', function (c) { + app.get('/dashboard/assets/:subpath{.+}', etag(), function (c) { const subpath = c.req.param('subpath') return serveAsset(c, subpath, staticServeConfig.distAssets) }) } // SPA catch-all route - app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', async function (c) { + app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', etag(), async function (c) { try { const file = await Deno.readFile(staticServeConfig.distIndexHtml) return c.body(file, 200, { 'Content-Type': 'text/html' }) diff --git a/src/serve/server.ts b/src/serve/server.ts index b5bf6bf..6c9db45 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -384,7 +384,7 @@ function installServerSelectorsOnce (): void { export async function startServer (): Promise<{ uri: string }> { // Read configuration from nconf - const appDir = nconf.get('server:appDir') || process.cwd() + const appManifest = nconf.get('appManifest') || join(nconf.get('server:appDir') || process.cwd(), 'chelonia.json') const ARCHIVE_MODE = nconf.get('server:archiveMode') const host = nconf.get('server:host') || '0.0.0.0' const port = nconf.get('server:port') ?? 8000 @@ -397,7 +397,7 @@ export async function startServer (): Promise<{ uri: string }> { // Load chelonia.json manifest try { - currentManifest = (await import(pathToFileURL(join(appDir, 'chelonia.json')).toString(), { + currentManifest = (await import(pathToFileURL(appManifest).toString(), { with: { type: 'json' } })).default } catch { From a714cc50c8089deb8932d3c1217133bc0661a009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:36:47 +0000 Subject: [PATCH 55/71] Feedback --- AGENTS.md | 2 +- build/main.js | 2 -- src/serve.ts | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8d3453d..d49eb4b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -264,7 +264,7 @@ Build process injects: - `import.meta.VERSION` - Package version from package.json - `import.meta.ownerSizeTotalWorker` - 'Owner size total' worker path - `import.meta.creditsWorker` - 'Credits' worker path -- `import.meta.initDbOnce` - Allow the DB to only be set up once +- `import.meta.lockDbSelectors` - Lock DB selectors upon init ### 6. No Network After Key Loading diff --git a/build/main.js b/build/main.js index 64ab03c..d3f88f7 100644 --- a/build/main.js +++ b/build/main.js @@ -76127,8 +76127,6 @@ async function serve(args) { console.error(red("\u274C Failed to start application server:"), error2); throw error2; } - await new Promise(() => { - }); } catch (error2) { console.error(red("\u274C Failed to start server:"), error2); process12.exit(1); diff --git a/src/serve.ts b/src/serve.ts index d9322ad..0b4bd7a 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -130,8 +130,6 @@ export async function serve (args: ArgumentsCamelCase) { console.error(colors.red('❌ Failed to start application server:'), error) throw error } - - await new Promise(() => {}) } catch (error) { console.error(colors.red('❌ Failed to start server:'), error) process.exit(1) From 000902cabb058eb103d90e2a47aaf3d896ff9421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 18:08:32 +0000 Subject: [PATCH 56/71] Feedback --- build/main.js | 21 +-------------------- src/serve/database.ts | 2 +- src/serve/index.ts | 12 ------------ 3 files changed, 2 insertions(+), 33 deletions(-) diff --git a/build/main.js b/build/main.js index d3f88f7..6e09a4f 100644 --- a/build/main.js +++ b/build/main.js @@ -68899,7 +68899,7 @@ var initDB = async ({ skipDbPreloading } = {}) => { max: import_npm_nconf2.default.get("database:lruNumItems") ?? 1e4 }); currentCache = cache2; - if (!setSelectors && true) { + if (!setSelectors || false) { esm_default("sbp/selectors/overwrite", { "chelonia.db/get": async function(prefixableKey, { bypassCache } = {}) { if (!bypassCache) { @@ -75687,13 +75687,6 @@ function installSignalHandlers() { ["SIGUSR2", 11] ].forEach(([signal, code2]) => handleSignal(signal, code2)); } -function removeSignalHandlers() { - for (const [signal, handler] of signalHandlers) { - process10.removeListener(signal, handler); - } - signalHandlers.length = 0; - signalHandlersInstalled = false; -} var exit2 = (code2) => { esm_default("okTurtles.events/once", SERVER_EXITING, () => { esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { @@ -75710,15 +75703,6 @@ async function startServer2(options2 = {}) { installGlobalExceptionHandlers(); installSignalHandlers(); } - esm_default("okTurtles.events/once", SERVER_EXITING, async () => { - try { - removeSignalHandlers(); - await stopServer2(); - console.info("Server down"); - } catch (err) { - console.error(err, "Error during shutdown"); - } - }); return await new Promise((resolve82, reject) => { esm_default("okTurtles.events/on", SERVER_RUNNING, function onRunning(info) { esm_default("okTurtles.events/off", SERVER_RUNNING, onRunning); @@ -75728,9 +75712,6 @@ async function startServer2(options2 = {}) { startServer().catch(reject); }); } -async function stopServer2() { - await stopServer(); -} var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i; var getMimeType = (filename, mimes = baseMimes) => { const regexp = /\.([a-zA-Z0-9]+?)$/; diff --git a/src/serve/database.ts b/src/serve/database.ts index 484735e..2eb9b7a 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -229,7 +229,7 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean }) currentCache = cache - if (!setSelectors && (import.meta as ImportMeta).lockDbSelectors) { + if (!setSelectors || !(import.meta as ImportMeta).lockDbSelectors) { sbp('sbp/selectors/overwrite', { 'chelonia.db/get': async function (prefixableKey: string, { bypassCache }: { bypassCache?: boolean } = {}): Promise { if (!bypassCache) { diff --git a/src/serve/index.ts b/src/serve/index.ts index 0bdfe3b..927ad5e 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -118,18 +118,6 @@ export async function startServer (options: StartServerOptions = {}): Promise<{ installSignalHandlers() } - // Register a SERVER_EXITING handler for this startServer call - // This handler self-removes when it fires - sbp('okTurtles.events/once', SERVER_EXITING, async () => { - try { - removeSignalHandlers() - await stopServer() - console.info('Server down') - } catch (err) { - console.error(err, 'Error during shutdown') - } - }) - // Start the server and wait for it to be running return await new Promise((resolve, reject) => { sbp('okTurtles.events/on', SERVER_RUNNING, function onRunning (info: { info: { uri: string } }) { From eb29cdc09b625303674d8d079eac761553e76cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:05:36 +0000 Subject: [PATCH 57/71] Fix missing `chel` and added `.gitignore` for a more permanent fix. --- bin/.gitignore | 6 ++++++ bin/chel | 1 + bin/chel.exe | 1 + 3 files changed, 8 insertions(+) create mode 100644 bin/.gitignore create mode 100755 bin/chel create mode 100644 bin/chel.exe diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..dd6144f --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1,6 @@ +# Until we implement , the files +# in this directory must _not_ be version-controlled, as they're placeholders +# used by the post install script. However, running `npm install` on this +# project will result in overwriting the file if the post install script runs +# To avoid this, all files under this directory are ignored. +* diff --git a/bin/chel b/bin/chel new file mode 100755 index 0000000..14726f0 --- /dev/null +++ b/bin/chel @@ -0,0 +1 @@ +placeholder, will be replaced by real binary. DO NOT DELETE THIS FILE! diff --git a/bin/chel.exe b/bin/chel.exe new file mode 100644 index 0000000..14726f0 --- /dev/null +++ b/bin/chel.exe @@ -0,0 +1 @@ +placeholder, will be replaced by real binary. DO NOT DELETE THIS FILE! From e95c9e636c4243534e2f3925747db11b83186658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:26:58 +0000 Subject: [PATCH 58/71] Protect chel --- .github/workflows/pull-request-bin.yml | 42 ++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/pull-request-bin.yml diff --git a/.github/workflows/pull-request-bin.yml b/.github/workflows/pull-request-bin.yml new file mode 100644 index 0000000..4911b93 --- /dev/null +++ b/.github/workflows/pull-request-bin.yml @@ -0,0 +1,42 @@ +name: Reject protected-dir changes + +permissions: + contents: read + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + reject-protected: + runs-on: ubuntu-slim + env: + PROTECTED_DIR: bin/ + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + - name: Fail if protected dir changed (unless [bin-update] present) + run: | + BASE_REF="${{ github.event.pull_request.base.ref }}" + # fetch base for diff/log + git fetch origin "$BASE_REF" --depth=1 + + # if any commit message includes [bin-update], skip the check + if git log --pretty=%B "origin/${BASE_REF}"..HEAD | grep -q '\[bin-update\]'; then + echo "Bypass: a commit message contains [bin-update]." + exit 0 + fi + + # list changed files between PR branch and base + changes=$(git diff --name-only "origin/${BASE_REF}"..HEAD || true) + + # fail if any changed file is under the protected directory + if echo "$changes" | grep -E "^${PROTECTED_DIR}"; then + echo "ERROR: Changes detected under ${PROTECTED_DIR}. Rejecting PR." + exit 1 + fi + + echo "No changes detected under ${PROTECTED_DIR}." From 43b1949178f03194faddac2d3339e5a4317222e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 19:28:10 +0000 Subject: [PATCH 59/71] [bin-update] From c0c39b9104107cf3b57012619d90283645c21fcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:09:41 +0000 Subject: [PATCH 60/71] Review --- build/main.js | 31 +++++++++++++------------------ src/migrate.ts | 2 -- src/serve.ts | 18 ++++++------------ src/serve/dashboard-server.ts | 6 ++++-- src/serve/database.ts | 8 +++----- src/serve/index.ts | 10 +++------- src/serve/routes.ts | 7 +++++-- src/types/build.d.ts | 3 ++- 8 files changed, 36 insertions(+), 49 deletions(-) diff --git a/build/main.js b/build/main.js index 6e09a4f..766d1c2 100644 --- a/build/main.js +++ b/build/main.js @@ -68881,9 +68881,6 @@ var getCurrentClosePromise = () => closePromise ?? Promise.resolve(); var initDB = async ({ skipDbPreloading } = {}) => { await getCurrentClosePromise(); const thisInitPromise = initPromise ?? (async () => { - if (isClosing) { - throw new Error("Cannot init DB while closing is in progress"); - } installBaseSelectorsOnce(); if (!dbRefs) { const backend = import_npm_nconf2.default.get("database:backend"); @@ -68951,7 +68948,9 @@ var initDB = async ({ skipDbPreloading } = {}) => { return currentBackend.keyCount(); } }); - esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + if (true) { + esm_default("sbp/selectors/lock", ["chelonia.db/get", "chelonia.db/set", "chelonia.db/delete", "chelonia.db/iterKeys"]); + } setSelectors = true; } } @@ -69593,7 +69592,6 @@ async function migrate(args) { } catch (e2) { reportStatus(); console.error(`Error reading from source database key '${key}'`, e2); - exit(1); throw e2; } await checkAndExit(); @@ -69606,7 +69604,6 @@ async function migrate(args) { } catch (e2) { reportStatus(); console.error(`Error writing to target database key '${key}'`, e2); - exit(1); throw e2; } await checkAndExit(); @@ -73770,6 +73767,8 @@ var errorMapper = (e2) => { return new HTTPException(410); case "BackendErrorBadData": return new HTTPException(422, { message: e2.message }); + case "BackendErrorConflict": + return new HTTPException(409); default: console.error(e2, "Unexpected backend error"); return new HTTPException(500, { message: e2.message ?? "internal error" }); @@ -73789,8 +73788,9 @@ function notFoundNoCache(c) { return c.body(null, 404, { "Cache-Control": "no-store" }); } function safePathWithin(base2, subpath) { - const resolved = path5.resolve(base2, subpath); - if (!resolved.startsWith(base2 + path5.sep) && resolved !== base2) return null; + const normalizedBase = path5.resolve(base2); + const resolved = path5.resolve(normalizedBase, subpath); + if (!resolved.startsWith(base2 + path5.sep) && resolved !== normalizedBase) return null; return resolved; } function serveAsset(c, subpath, assetsDir) { @@ -75689,8 +75689,8 @@ function installSignalHandlers() { } var exit2 = (code2) => { esm_default("okTurtles.events/once", SERVER_EXITING, () => { - esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, () => { - process10.send?.({}); + esm_default("okTurtles.eventQueue/queueEvent", SERVER_EXITING, async () => { + await stopServer(); process10.nextTick(() => process10.exit(code2)); }); }); @@ -76016,6 +76016,7 @@ async function startDashboard() { resolve82(uri); }).once("error", reject); }); + return server; } async function deployManifests(args) { const dir = args["manifests-dir"]; @@ -76077,17 +76078,11 @@ async function watch(args) { } })(); } -async function startDashboardServer() { - await startDashboard(); -} -async function startApplicationServer() { - await startServer2(); -} async function serve(args) { await initDB(); try { try { - await startDashboardServer(); + await startDashboard(); } catch (error2) { console.error(red("\u274C Failed to start dashboard server:"), error2); throw error2; @@ -76103,7 +76098,7 @@ async function serve(args) { throw error2; } try { - await startApplicationServer(); + await startServer2(); } catch (error2) { console.error(red("\u274C Failed to start application server:"), error2); throw error2; diff --git a/src/migrate.ts b/src/migrate.ts index 570c806..1893a72 100644 --- a/src/migrate.ts +++ b/src/migrate.ts @@ -124,7 +124,6 @@ export async function migrate (args: ArgumentsCamelCase): Promise } catch (e) { reportStatus() console.error(`Error reading from source database key '${key}'`, e) - exit(1) throw e } await checkAndExit() @@ -138,7 +137,6 @@ export async function migrate (args: ArgumentsCamelCase): Promise } catch (e) { reportStatus() console.error(`Error writing to target database key '${key}'`, e) - exit(1) throw e } await checkAndExit() diff --git a/src/serve.ts b/src/serve.ts index 0b4bd7a..f00735f 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -84,22 +84,14 @@ async function watch (args: ArgumentsCamelCase): Promise { })() } -// Dashboard server function -async function startDashboardServer (): Promise { - await startDashboard() -} - -// Application server function -async function startApplicationServer (): Promise { - await startServer() -} - export async function serve (args: ArgumentsCamelCase) { + // `deployManifests` / `watch` will open the database and then close it. + // By callig `initDB` here, we ensure that the DB isn't closed. await initDB() try { // Start dashboard server on port 7000 first try { - await startDashboardServer() + await startDashboard() } catch (error) { console.error(colors.red('❌ Failed to start dashboard server:'), error) throw error @@ -125,7 +117,7 @@ export async function serve (args: ArgumentsCamelCase) { // Start application server on port 8000 second try { - await startApplicationServer() + await startServer() } catch (error) { console.error(colors.red('❌ Failed to start application server:'), error) throw error @@ -134,6 +126,8 @@ export async function serve (args: ArgumentsCamelCase) { console.error(colors.red('❌ Failed to start server:'), error) process.exit(1) } finally { + // Safe to close because the server has opened the DB, increasing the + // reference count. await closeDB() } } diff --git a/src/serve/dashboard-server.ts b/src/serve/dashboard-server.ts index 52fdcd4..88784cd 100644 --- a/src/serve/dashboard-server.ts +++ b/src/serve/dashboard-server.ts @@ -2,7 +2,7 @@ import path from 'node:path' import process from 'node:process' import { Hono } from 'npm:hono' import { serveStatic } from 'npm:hono/deno' -import { createAdaptorServer } from 'npm:@hono/node-server' +import { createAdaptorServer, type ServerType } from 'npm:@hono/node-server' import { etag } from 'npm:hono/etag' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' @@ -15,7 +15,7 @@ const getDashboardPath = () => { return dashboardPath } -export async function startDashboard (): Promise { +export async function startDashboard (): Promise { const port = nconf.get('server:dashboardPort') const host = nconf.get('server:host') || '0.0.0.0' const dashboardRoot = getDashboardPath() @@ -53,6 +53,8 @@ export async function startDashboard (): Promise { resolve(uri) }).once('error', reject) }) + + return server } export default startDashboard diff --git a/src/serve/database.ts b/src/serve/database.ts index 2eb9b7a..56c8d5b 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -205,10 +205,6 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean // Queue this init operation const thisInitPromise = initPromise ?? (async () => { - if (isClosing) { - throw new Error('Cannot init DB while closing is in progress') - } - installBaseSelectorsOnce() if (!dbRefs) { @@ -281,7 +277,9 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean return currentBackend!.keyCount() } }) - sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + if ((import.meta as ImportMeta).lockDbSelectors) { + sbp('sbp/selectors/lock', ['chelonia.db/get', 'chelonia.db/set', 'chelonia.db/delete', 'chelonia.db/iterKeys']) + } setSelectors = true } } diff --git a/src/serve/index.ts b/src/serve/index.ts index 927ad5e..328312f 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -5,7 +5,7 @@ import 'npm:@sbp/okturtles.events' import sbp from 'npm:@sbp/sbp' import chalk from 'npm:chalk' import { SERVER_EXITING, SERVER_RUNNING } from './events.ts' -import { startServer as startServerImpl, stopServer as stopServerImpl } from './server.ts' +import { startServer as startServerImpl, stopServer } from './server.ts' import { initializeLogger } from './logger.ts' console.info('NODE_ENV =', process.env.NODE_ENV) @@ -94,8 +94,8 @@ const exit = (code: number) => { // must be synchronous. sbp('okTurtles.events/once', SERVER_EXITING, () => { // In case there are asynchronous events, wait for them to finish - sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, () => { - process.send?.({}) // tell grunt we've successfully shutdown the server + sbp('okTurtles.eventQueue/queueEvent', SERVER_EXITING, async () => { + await stopServer() process.nextTick(() => process.exit(code)) // triple-check we quit :P }) }) @@ -129,9 +129,5 @@ export async function startServer (options: StartServerOptions = {}): Promise<{ }) } -export async function stopServer (): Promise { - await stopServerImpl() -} - // Backwards compatibility: default export is startServer export default startServer diff --git a/src/serve/routes.ts b/src/serve/routes.ts index db60c99..a66c970 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -225,6 +225,8 @@ const errorMapper = (e: Error): HTTPException => { return new HTTPException(410) case 'BackendErrorBadData': return new HTTPException(422, { message: e.message }) + case 'BackendErrorConflict': + return new HTTPException(409) default: console.error(e, 'Unexpected backend error') return new HTTPException(500, { message: e.message ?? 'internal error' }) @@ -249,8 +251,9 @@ function notFoundNoCache (c: Context): Response { } function safePathWithin (base: string, subpath: string): string | null { - const resolved = path.resolve(base, subpath) - if (!resolved.startsWith(base + path.sep) && resolved !== base) return null + const normalizedBase = path.resolve(base) + const resolved = path.resolve(normalizedBase, subpath) + if (!resolved.startsWith(base + path.sep) && resolved !== normalizedBase) return null return resolved } diff --git a/src/types/build.d.ts b/src/types/build.d.ts index a195654..d7ab461 100644 --- a/src/types/build.d.ts +++ b/src/types/build.d.ts @@ -1,7 +1,8 @@ interface ImportMeta { VERSION: string, ownerSizeTotalWorker?: string, - creditsWorker?: string + creditsWorker?: string, + lockDbSelectors?: boolean } declare const logger: { From d9dd908d111b59b62409a9add730234b9a0b62f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:42:18 +0000 Subject: [PATCH 61/71] Simplify error handling --- build/main.js | 143 +++++++++++++++++++++------------------------ src/eventsAfter.ts | 2 - src/get.ts | 2 - src/main.ts | 7 ++- src/migrate.ts | 32 +++++----- src/pin.ts | 98 +++++++++++++++---------------- src/serve.ts | 2 +- 7 files changed, 133 insertions(+), 153 deletions(-) diff --git a/build/main.js b/build/main.js index 766d1c2..93f00bb 100644 --- a/build/main.js +++ b/build/main.js @@ -3071,7 +3071,7 @@ var wrapTransaction = (fn, db2, { begin, commit, rollback, savepoint, release, r import { Buffer as Buffer11 } from "node:buffer"; import { mkdir as mkdir2 } from "node:fs/promises"; import { basename as basename22, dirname as dirname22, join as join22, resolve as resolve22 } from "node:path"; -import process13 from "node:process"; +import process12 from "node:process"; // deno:https://jsr.io/@std/path/1.1.1/_common/assert_path.ts function assertPath3(path) { @@ -4098,7 +4098,6 @@ import { existsSync } from "node:fs"; import { copyFile, mkdir as mkdir3, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises"; import { basename as basename42, dirname as dirname42, join as join62 } from "node:path"; import process4 from "node:process"; -import process12 from "node:process"; import process10 from "node:process"; import { createServer as createServerHTTP } from "node:http"; import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "node:http2"; @@ -69206,8 +69205,6 @@ async function eventsAfter2({ limit, url: url2, contractID, height }) { messages = await getMessagesSince(contractID, height, limit); } console.log(JSON.stringify(messages, null, 2)); - } catch (error2) { - exit(error2); } finally { if (dbOpen) { await closeDB(); @@ -69292,8 +69289,6 @@ async function get({ key, url: url2 }) { } else { await writeAll(Deno.stdout, data); } - } catch (error2) { - exit(error2); } finally { if (dbOpen) { await closeDB(); @@ -69517,30 +69512,24 @@ async function migrate(args) { await initDB({ skipDbPreloading: true }); } catch (e2) { console.error("Error setting up database"); - exit(e2); throw e2; } let backendTo; try { - try { - let toConfigOpts; - if (args.toConfig) { - const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); - const toBackend = toConfig?.database?.backend; - if (toBackend !== to) { - console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); - } - toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; - } else { - toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; - } - const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; - backendTo = new Ctor(toConfigOpts); - await backendTo.init(); - } catch (error2) { - exit(error2); - throw error2; + let toConfigOpts; + if (args.toConfig) { + const toConfig = parse8(await readFile2(args.toConfig, { encoding: "utf-8", flag: "r" })); + const toBackend = toConfig?.database?.backend; + if (toBackend !== to) { + console.warn(`--to-config has backend ${toBackend} but --to is ${to}`); + } + toConfigOpts = toConfig?.database?.backendOptions?.[to] || {}; + } else { + toConfigOpts = import_npm_nconf3.default.get(`database:backendOptions:${to}`) || {}; } + const Ctor = (await globImport_serve_database_ts(`./serve/database-${to}.ts`)).default; + backendTo = new Ctor(toConfigOpts); + await backendTo.init(); const numKeys2 = await esm_default("chelonia.db/keyCount"); let numMigratedKeys = 0; let numVisitedKeys = 0; @@ -69659,58 +69648,54 @@ async function pin(args) { const version3 = args["manifest-version"]; const manifestPath = args.manifest; projectRoot = args["dir"] || process4.cwd(); - try { - if (!manifestPath) { - await loadCheloniaConfig(); - return; - } - console.log(cyan(`\u{1F4CC} Requesting pin to version: ${version3}`)); - console.log(gray(`Manifest: ${manifestPath}`)); + if (!manifestPath) { await loadCheloniaConfig(); - const fullManifestPath = join62(projectRoot, manifestPath); - if (!existsSync(fullManifestPath)) { - exit(`Manifest file not found: ${manifestPath}`); - } - const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); - if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { - exit(`Invalid manifest version: ${manifestVersion}`); - } - console.log(blue(`Contract name: ${fullContractName}`)); - console.log(blue(`Manifest version: ${manifestVersion}`)); - if (version3) { - if (version3 !== manifestVersion) { - console.error(red(`\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})`)); - console.error(yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)); - exit("Version mismatch between CLI and manifest"); - } - console.log(green(`\u2705 Version validation passed: ${version3}`)); - } - const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; - if (currentPinnedVersion === manifestVersion) { - console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); - return; - } - if (currentPinnedVersion) { - console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); - } else { - console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); - } - const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); - if (existsSync(contractVersionDir)) { - if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); - } - console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); - } else { - await createVersionDirectory(contractName, manifestVersion); + return; + } + console.log(cyan(`\u{1F4CC} Requesting pin to version: ${version3}`)); + console.log(gray(`Manifest: ${manifestPath}`)); + await loadCheloniaConfig(); + const fullManifestPath = join62(projectRoot, manifestPath); + if (!existsSync(fullManifestPath)) { + exit(`Manifest file not found: ${manifestPath}`); + } + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath); + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`); + } + console.log(blue(`Contract name: ${fullContractName}`)); + console.log(blue(`Manifest version: ${manifestVersion}`)); + if (version3) { + if (version3 !== manifestVersion) { + console.error(red(`\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})`)); + console.error(yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)); + exit("Version mismatch between CLI and manifest"); + } + console.log(green(`\u2705 Version validation passed: ${version3}`)); + } + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; + if (currentPinnedVersion === manifestVersion) { + console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); + return; + } + if (currentPinnedVersion) { + console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + } else { + console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); + } + const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); + if (existsSync(contractVersionDir)) { + if (!args.overwrite) { + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); } - await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); - await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); - console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); - } catch (error2) { - exit(error2); + console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); + } else { + await createVersionDirectory(contractName, manifestVersion); } + await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); + console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); + console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } async function parseManifest(manifestPath) { const manifestContent = await readFile3(manifestPath, "utf8"); @@ -76105,7 +76090,7 @@ async function serve(args) { } } catch (error2) { console.error(red("\u274C Failed to start server:"), error2); - process12.exit(1); + throw error2; } finally { await closeDB(); } @@ -80394,7 +80379,7 @@ var parseArgs = () => { const commandModules = Object.values(commands_exports).map( (c) => handlerWrapper(c) ); - const yargsInstance = yargs_default(hideBin(process13.argv)).version("3.2.1").strict().command(commandModules).demandCommand().help(); + const yargsInstance = yargs_default(hideBin(process12.argv)).version("3.2.1").strict().command(commandModules).demandCommand().help(); return yargsInstance; }; var parseArgs_default = parseArgs; @@ -80435,7 +80420,11 @@ var parseConfig = () => { }; var parseConfig_default = parseConfig; parseConfig_default(); -await handlerState.postHandler(); +try { + await handlerState.postHandler(); +} catch (e2) { + exit(e2); +} /*! Bundled license information: scrypt-async/scrypt-async.js: diff --git a/src/eventsAfter.ts b/src/eventsAfter.ts index d420a88..af56043 100644 --- a/src/eventsAfter.ts +++ b/src/eventsAfter.ts @@ -21,8 +21,6 @@ export async function eventsAfter ({ limit, url, contractID, height }: Arguments messages = await getMessagesSince(contractID, height, limit) } console.log(JSON.stringify(messages, null, 2)) - } catch (error) { - exit(error) } finally { if (dbOpen) { await closeDB() diff --git a/src/get.ts b/src/get.ts index 591e065..071bd89 100644 --- a/src/get.ts +++ b/src/get.ts @@ -35,8 +35,6 @@ export async function get ({ key, url }: ArgumentsCamelCase): Promise): Promise await initDB({ skipDbPreloading: true }) } catch (e) { console.error('Error setting up database') - exit(e) throw e } let backendTo: DatabaseBackend | undefined try { - try { - let toConfigOpts: unknown - if (args.toConfig) { - const toConfig = parse(await readFile(args.toConfig, { encoding: 'utf-8', flag: 'r' })) - const toBackend = (toConfig?.database as TomlTable)?.backend as string - if (toBackend !== to) { - console.warn(`--to-config has backend ${toBackend} but --to is ${to}`) - } - toConfigOpts = ((toConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[to] || {} - } else { - toConfigOpts = nconf.get(`database:backendOptions:${to}`) || {} + let toConfigOpts: unknown + if (args.toConfig) { + const toConfig = parse(await readFile(args.toConfig, { encoding: 'utf-8', flag: 'r' })) + const toBackend = (toConfig?.database as TomlTable)?.backend as string + if (toBackend !== to) { + console.warn(`--to-config has backend ${toBackend} but --to is ${to}`) } - - const Ctor = (await import(`./serve/database-${to}.ts`)).default - backendTo = new Ctor(toConfigOpts) - await backendTo!.init() - } catch (error) { - exit(error) - throw error + toConfigOpts = ((toConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[to] || {} + } else { + toConfigOpts = nconf.get(`database:backendOptions:${to}`) || {} } + const Ctor = (await import(`./serve/database-${to}.ts`)).default + backendTo = new Ctor(toConfigOpts) + await backendTo!.init() + const numKeys = await sbp('chelonia.db/keyCount') let numMigratedKeys = 0 let numVisitedKeys = 0 diff --git a/src/pin.ts b/src/pin.ts index f1f45b2..ab7687c 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -26,72 +26,68 @@ export async function pin (args: ArgumentsCamelCase): Promise { const manifestPath = args.manifest projectRoot = args['dir'] || process.cwd() - try { - if (!manifestPath) { - await loadCheloniaConfig() - return - } - - console.log(colors.cyan(`📌 Requesting pin to version: ${version}`)) - console.log(colors.gray(`Manifest: ${manifestPath}`)) - + if (!manifestPath) { await loadCheloniaConfig() + return + } - const fullManifestPath = join(projectRoot, manifestPath) - if (!existsSync(fullManifestPath)) { - exit(`Manifest file not found: ${manifestPath}`) - } + console.log(colors.cyan(`📌 Requesting pin to version: ${version}`)) + console.log(colors.gray(`Manifest: ${manifestPath}`)) - const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + await loadCheloniaConfig() - if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { - exit(`Invalid manifest version: ${manifestVersion}`) - } + const fullManifestPath = join(projectRoot, manifestPath) + if (!existsSync(fullManifestPath)) { + exit(`Manifest file not found: ${manifestPath}`) + } - console.log(colors.blue(`Contract name: ${fullContractName}`)) - console.log(colors.blue(`Manifest version: ${manifestVersion}`)) + const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) - if (version) { - if (version !== manifestVersion) { - console.error(colors.red(`❌ Version mismatch: CLI version (${version}) does not match manifest version (${manifestVersion})`)) - console.error(colors.yellow(`💡 To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)) - exit('Version mismatch between CLI and manifest') - } + if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { + exit(`Invalid manifest version: ${manifestVersion}`) + } - console.log(colors.green(`✅ Version validation passed: ${version}`)) - } + console.log(colors.blue(`Contract name: ${fullContractName}`)) + console.log(colors.blue(`Manifest version: ${manifestVersion}`)) - const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version - if (currentPinnedVersion === manifestVersion) { - console.log(colors.yellow(`✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)) - return + if (version) { + if (version !== manifestVersion) { + console.error(colors.red(`❌ Version mismatch: CLI version (${version}) does not match manifest version (${manifestVersion})`)) + console.error(colors.yellow(`💡 To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)) + exit('Version mismatch between CLI and manifest') } - if (currentPinnedVersion) { - console.log(colors.cyan(`📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) - } else { - console.log(colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`)) - } + console.log(colors.green(`✅ Version validation passed: ${version}`)) + } - const contractVersionDir = join(projectRoot, 'contracts', contractName, manifestVersion) + const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version + if (currentPinnedVersion === manifestVersion) { + console.log(colors.yellow(`✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)) + return + } - if (existsSync(contractVersionDir)) { - if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`) - } - console.log(colors.yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)) - } else { - await createVersionDirectory(contractName, manifestVersion) - } + if (currentPinnedVersion) { + console.log(colors.cyan(`📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) + } else { + console.log(colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`)) + } - await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) - await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) + const contractVersionDir = join(projectRoot, 'contracts', contractName, manifestVersion) - console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) - console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) - } catch (error) { - exit(error) + if (existsSync(contractVersionDir)) { + if (!args.overwrite) { + exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`) + } + console.log(colors.yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)) + } else { + await createVersionDirectory(contractName, manifestVersion) } + + await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) + await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) + + console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) + console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } async function parseManifest (manifestPath: string) { diff --git a/src/serve.ts b/src/serve.ts index f00735f..da9e49a 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -124,7 +124,7 @@ export async function serve (args: ArgumentsCamelCase) { } } catch (error) { console.error(colors.red('❌ Failed to start server:'), error) - process.exit(1) + throw error } finally { // Safe to close because the server has opened the DB, increasing the // reference count. From 6c8f2eb4064b2ef01d3274494cb6fb6f18909292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 20:45:30 +0000 Subject: [PATCH 62/71] lint --- src/eventsAfter.ts | 1 - src/serve.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/eventsAfter.ts b/src/eventsAfter.ts index af56043..60e5a4b 100644 --- a/src/eventsAfter.ts +++ b/src/eventsAfter.ts @@ -4,7 +4,6 @@ import * as base64 from 'jsr:@std/encoding/base64' import sbp from 'npm:@sbp/sbp' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { closeDB, initDB } from './serve/database.ts' -import { exit } from './utils.ts' type Params = { limit: number, url: string | undefined, contractID: string, height: number } diff --git a/src/serve.ts b/src/serve.ts index da9e49a..7e1ceeb 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -1,5 +1,4 @@ import * as colors from 'jsr:@std/fmt/colors' -import process from 'node:process' import sbp from 'npm:@sbp/sbp' import { debounce } from 'npm:turtledash' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' From af04bcc31432502d352416f919c2f09f3e82b757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 27 Apr 2026 21:00:23 +0000 Subject: [PATCH 63/71] fixes --- src/serve/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/serve/index.ts b/src/serve/index.ts index 328312f..a668e56 100644 --- a/src/serve/index.ts +++ b/src/serve/index.ts @@ -131,3 +131,4 @@ export async function startServer (options: StartServerOptions = {}): Promise<{ // Backwards compatibility: default export is startServer export default startServer +export { stopServer } From 64f18e6580cb0868faad01cf997ff8dbb8eb96e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Fri, 1 May 2026 22:37:47 +0000 Subject: [PATCH 64/71] Feedback --- src/deploy.ts | 7 +-- src/eventsAfter.ts | 41 +++++++++++++----- src/get.ts | 13 +++--- src/hash.ts | 20 +++++---- src/keygen.ts | 9 +++- src/manifest.ts | 80 +++++++++++++++++++++------------- src/migrate.ts | 98 ++++++++++++++++++++++-------------------- src/parseArgs.ts | 8 ++-- src/parseConfig.ts | 46 ++++++++++---------- src/pin.ts | 66 +++++++++++++++++++++------- src/serve.ts | 14 +++--- src/types/build.d.ts | 20 ++++----- src/upload.ts | 17 ++++---- src/utils.ts | 18 ++++---- src/verifySignature.ts | 53 ++++++++++++++++++----- 15 files changed, 317 insertions(+), 193 deletions(-) diff --git a/src/deploy.ts b/src/deploy.ts index 4488347..09d0583 100644 --- a/src/deploy.ts +++ b/src/deploy.ts @@ -12,10 +12,10 @@ const CONTRACT_MANIFEST_PREFIX = 'm|' const ContractBodySchema = z.object({ contract: z.object({ file: z.string() }), - contractSlim: z.object({ file: z.string() }).optional(), + contractSlim: z.object({ file: z.string() }).optional() }) -type Params = { manifests: string[], url?: string } +type Params = { manifests: string[]; url?: string } export async function deploy (args: ArgumentsCamelCase): Promise { const { manifests } = args @@ -64,7 +64,8 @@ export const module = { string: true }) .positional('manifests', { - describe: 'Manifest files to deploy (if a directory is passed in, all manifests in that directory, and sub-directories, will be added)', + describe: + 'Manifest files to deploy (if a directory is passed in, all manifests in that directory, and sub-directories, will be added)', demandOption: true, array: true, type: 'string' diff --git a/src/eventsAfter.ts b/src/eventsAfter.ts index 60e5a4b..f8c9868 100644 --- a/src/eventsAfter.ts +++ b/src/eventsAfter.ts @@ -5,9 +5,14 @@ import sbp from 'npm:@sbp/sbp' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { closeDB, initDB } from './serve/database.ts' -type Params = { limit: number, url: string | undefined, contractID: string, height: number } +type Params = { limit: number; url: string | undefined; contractID: string; height: number } -export async function eventsAfter ({ limit, url, contractID, height }: ArgumentsCamelCase): Promise { +export async function eventsAfter ({ + limit, + url, + contractID, + height +}: ArgumentsCamelCase): Promise { let dbOpen = false try { let messages @@ -27,7 +32,11 @@ export async function eventsAfter ({ limit, url, contractID, height }: Arguments } } -async function getMessagesSince (contractID: string, sinceHeight: number, limit: number): Promise { +async function getMessagesSince ( + contractID: string, + sinceHeight: number, + limit: number +): Promise { const readable = await sbp('backend/db/streamEntriesAfter', contractID, sinceHeight, limit) return new Promise((resolve, reject) => { @@ -50,18 +59,27 @@ async function getMessagesSince (contractID: string, sinceHeight: number, limit: }) } -async function getRemoteMessagesSince (src: string, contractID: string, sinceHeight: number, limit: number): Promise { +async function getRemoteMessagesSince ( + src: string, + contractID: string, + sinceHeight: number, + limit: number +): Promise { const response = await fetch(`${src}/eventsAfter/${contractID}/${sinceHeight}`) if (!response.ok) { // The response body may contain some useful error info. - const bodyText = await response.text().catch(() => '') || '' - throw new Error(`failed network request to ${src}: ${response.status} - ${response.statusText} - '${bodyText}'`) + const bodyText = (await response.text().catch(() => '')) || '' + throw new Error( + `failed network request to ${src}: ${response.status} - ${response.statusText} - '${bodyText}'` + ) } const b64messages: string[] = await response.json() if (b64messages.length > limit) { b64messages.length = limit } - return b64messages.map(b64str => JSON.parse(new TextDecoder().decode(base64.decodeBase64(b64str)))) + return b64messages.map((b64str) => + JSON.parse(new TextDecoder().decode(base64.decodeBase64(b64str))) + ) } export const module = { @@ -95,10 +113,11 @@ export const module = { }) }, command: 'eventsAfter ', - describe: 'Displays a JSON array of the first LIMIT events that happened in a given contract, since a given entry identified by its hash.\n\n' + - '- Older events are displayed first.\n' + - '- The output is parseable with tools such as \'jq\'.\n' + - '- If --url is given, then its /eventsAfter REST endpoint will be called.\n', + describe: + 'Displays a JSON array of the first LIMIT events that happened in a given contract, since a given entry identified by its hash.\n\n' + + '- Older events are displayed first.\n' + + '- The output is parseable with tools such as \'jq\'.\n' + + '- If --url is given, then its /eventsAfter REST endpoint will be called.\n', postHandler: (argv) => { return eventsAfter(argv) } diff --git a/src/get.ts b/src/get.ts index 071bd89..927bef5 100644 --- a/src/get.ts +++ b/src/get.ts @@ -13,7 +13,7 @@ import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { closeDB, initDB } from './serve/database.ts' import { exit, readRemoteData } from './utils.ts' -type Params = { url?: string, key: string } +type Params = { url?: string; key: string } export async function get ({ key, url }: ArgumentsCamelCase): Promise { let dbOpen = false @@ -23,9 +23,7 @@ export async function get ({ key, url }: ArgumentsCamelCase): Promise', - describe: 'Retrieves the entry associated with a given key, from a given database or server.\n\n' + - '- The output can be piped to a file, like this:' + - ' chel get https://url.com mygreatlongkey > file.png', + describe: + 'Retrieves the entry associated with a given key, from a given database or server.\n\n' + + '- The output can be piped to a file, like this:' + + ' chel get https://url.com mygreatlongkey > file.png', postHandler: (argv) => { return get(argv) } diff --git a/src/hash.ts b/src/hash.ts index 356154f..17a796c 100644 --- a/src/hash.ts +++ b/src/hash.ts @@ -9,7 +9,11 @@ import { createEntryFromFile } from './utils.ts' type Params = { filename: string } -export async function hash ({ filename }: ArgumentsCamelCase, multicode: number = multicodes.RAW, internal = false): Promise { +export async function hash ( + { filename }: ArgumentsCamelCase, + multicode: number = multicodes.RAW, + internal = false +): Promise { const [cid] = await createEntryFromFile(filename, multicode) if (!internal) { console.log(`CID(${filename}):`, cid) @@ -19,15 +23,15 @@ export async function hash ({ filename }: ArgumentsCamelCase, multicode: export const module = { builder: (yargs) => { - return yargs - .positional('filename', { - describe: 'File name', - demandOption: true, - type: 'string' - }) + return yargs.positional('filename', { + describe: 'File name', + demandOption: true, + type: 'string' + }) }, command: 'hash ', - describe: 'Computes and logs the content identifier (CID) for the given file.\n\' + \'File contents will be interpreted as raw binary data, unless the file extension is \'.json\'.', + describe: + 'Computes and logs the content identifier (CID) for the given file.\n\' + \'File contents will be interpreted as raw binary data, unless the file extension is \'.json\'.', postHandler: (argv) => { return void hash(argv) } diff --git a/src/keygen.ts b/src/keygen.ts index f4a780e..bfd2081 100644 --- a/src/keygen.ts +++ b/src/keygen.ts @@ -1,9 +1,14 @@ import * as colors from 'jsr:@std/fmt/colors' -import { EDWARDS25519SHA512BATCH, keygen as cryptoKeygen, keyId, serializeKey } from 'npm:@chelonia/crypto' +import { + EDWARDS25519SHA512BATCH, + keygen as cryptoKeygen, + keyId, + serializeKey +} from 'npm:@chelonia/crypto' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { revokeNet } from './utils.ts' -type Params = {out?: string, pubout?: string } +type Params = { out?: string; pubout?: string } export const keygen = async (args: ArgumentsCamelCase): Promise => { await revokeNet() diff --git a/src/manifest.ts b/src/manifest.ts index c4ff0f7..a72fc66 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -5,7 +5,13 @@ import * as colors from 'jsr:@std/fmt/colors' import * as path from 'jsr:@std/path/' -import { EDWARDS25519SHA512BATCH, deserializeKey, keyId, serializeKey, sign } from 'npm:@chelonia/crypto' +import { + EDWARDS25519SHA512BATCH, + deserializeKey, + keyId, + serializeKey, + sign +} from 'npm:@chelonia/crypto' import { multicodes } from 'npm:@chelonia/lib/functions' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { hash } from './hash.ts' @@ -14,20 +20,24 @@ import { exit, readJsonFile, revokeNet } from './utils.ts' // import { writeAllSync } from "https://deno.land/std@0.141.0/streams/mod.ts" type Params = { - key?: string[]; - out?: string; - slim?: string; - name?: string; - contractVersion?: string; - signingKey: string; - contractBundle: string; + key?: string[] + out?: string + slim?: string + name?: string + contractVersion?: string + signingKey: string + contractBundle: string } interface SigningKeyDescriptor { privkey: string } function isSigningKeyDescriptor (obj: unknown): obj is SigningKeyDescriptor { - return obj !== null && typeof obj === 'object' && typeof (obj as Record).privkey === 'string' + return ( + obj !== null && + typeof obj === 'object' && + typeof (obj as Record).privkey === 'string' + ) } export async function manifest (args: ArgumentsCamelCase): Promise { @@ -43,7 +53,8 @@ export async function manifest (args: ArgumentsCamelCase): Promise const name = args.name || contractFileName const version = args.contractVersion || 'x' const slim = args.slim - const outFile: string = args.out || path.join(contractDir, `${contractFileName}.${version}.manifest.json`) + const outFile: string = + args.out || path.join(contractDir, `${contractFileName}.${version}.manifest.json`) if (!keyFile) exit('Missing signing key file') const signingKeyDescriptorRaw = await readJsonFile(keyFile) @@ -54,23 +65,28 @@ export async function manifest (args: ArgumentsCamelCase): Promise const signingKey = deserializeKey(signingKeyDescriptor.privkey) // Add all additional public keys in addition to the signing key - const publicKeys = Array.from(new Set( - [serializeKey(signingKey, false)] - .concat(...await Promise.all(args.key?.map( - async (kf: unknown) => { - if (typeof kf !== 'string' && typeof kf !== 'number') { - exit(`Invalid key file reference: ${String(kf)}`) - } - const descriptor = await readJsonFile(String(kf)) - // @ts-expect-error: descriptor is unknown, ignoring type error - const key = deserializeKey(descriptor.pubkey) - if (key.type !== EDWARDS25519SHA512BATCH) { - exit(`Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.`) - } - return serializeKey(key, false) - } - ) || [])) - )) + const publicKeys = Array.from( + new Set( + [serializeKey(signingKey, false)].concat( + ...(await Promise.all( + args.key?.map(async (kf: unknown) => { + if (typeof kf !== 'string' && typeof kf !== 'number') { + exit(`Invalid key file reference: ${String(kf)}`) + } + const descriptor = await readJsonFile(String(kf)) + // @ts-expect-error: descriptor is unknown, ignoring type error + const key = deserializeKey(descriptor.pubkey) + if (key.type !== EDWARDS25519SHA512BATCH) { + exit( + `Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.` + ) + } + return serializeKey(key, false) + }) || [] + )) + ) + ) + ) const body: { [key: string]: unknown } = { name, @@ -110,10 +126,10 @@ export const module = { builder: (yargs) => { return yargs .option('key', { - coerce: (v: string | string[]) => Array.isArray(v) ? v : [v], + coerce: (v: string | string[]) => (Array.isArray(v) ? v : [v]), describe: 'Additional public key', requiresArg: true, - string: true, + string: true }) .alias('k', 'key') .option('out', { @@ -150,8 +166,10 @@ export const module = { type: 'string' }) }, - command: 'manifest [-k|--key ] [-k|--key ...] [--out ] [-s|--slim ] [-V|--contract-version ] ', - describe: 'Produce a signed manifest from a contract.\n' + 'If unspecified, is set to \'x\'.', + command: + 'manifest [-k|--key ] [-k|--key ...] [--out ] [-s|--slim ] [-V|--contract-version ] ', + describe: + 'Produce a signed manifest from a contract.\n' + 'If unspecified, is set to \'x\'.', postHandler: (argv) => { return manifest(argv) } diff --git a/src/migrate.ts b/src/migrate.ts index be93b80..0b77036 100644 --- a/src/migrate.ts +++ b/src/migrate.ts @@ -13,7 +13,7 @@ import { exit, isValidKey } from './utils.ts' import nconf from 'npm:nconf' import { parse, type TomlTable } from 'npm:smol-toml' -type Params = { from: string, fromConfig?: string, to: string, toConfig?: string } +type Params = { from: string; fromConfig?: string; to: string; toConfig?: string } export async function migrate (args: ArgumentsCamelCase): Promise { const { to } = args @@ -25,7 +25,8 @@ export async function migrate (args: ArgumentsCamelCase): Promise if (fromBackend !== backend) { console.warn(`--from-config has backend ${fromBackend} but --from is ${backend}`) } - const fromConfigOpts = ((fromConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[backend] || {} + const fromConfigOpts = + ((fromConfig?.database as TomlTable)?.backendOptions as TomlTable)?.[backend] || {} nconf.set(`database:backendOptions:${backend}`, fromConfigOpts) } @@ -68,8 +69,8 @@ export async function migrate (args: ArgumentsCamelCase): Promise const handleSignal = (signal: string, code: number) => { process.on(signal, () => { - // Exit codes follow the 128 + signal code convention. - // See + // Exit codes follow the 128 + signal code convention. + // See shouldExit = 128 + code if (++interruptCount < 3) { @@ -90,15 +91,17 @@ export async function migrate (args: ArgumentsCamelCase): Promise } } - // Codes from - ;([ - ['SIGHUP', 1], - ['SIGINT', 2], - ['SIGQUIT', 3], - ['SIGTERM', 15], - ['SIGUSR1', 10], - ['SIGUSR2', 11] - ] as [string, number][]).forEach(([signal, code]) => handleSignal(signal, code)) + // Codes from + ;( + [ + ['SIGHUP', 1], + ['SIGINT', 2], + ['SIGQUIT', 3], + ['SIGTERM', 15], + ['SIGUSR1', 10], + ['SIGUSR2', 11] + ] as [string, number][] + ).forEach(([signal, code]) => handleSignal(signal, code)) return checkAndExit })() @@ -150,41 +153,44 @@ export async function migrate (args: ArgumentsCamelCase): Promise export const module = { builder: (yargs) => { - return yargs - .option('from', { - describe: 'Source backend', - demandOption: true, - requiresArg: true, - string: true - }) - .alias('database:backend', 'from') - .option('from-config', { - describe: 'Source backend configuration', - requiresArg: true, - string: true - }) - .option('to', { - describe: 'Destination backend', - demandOption: true, - requiresArg: true, - string: true - }) - .option('to-config', { - describe: 'Destination backend configuration', - requiresArg: true, - string: true - }) - // strict(false) to support non-enumerated flags, which can be used for - // configuring backend settings. However, `from-config` should be preferred. - .strict(false) - .strictCommands(true) + return ( + yargs + .option('from', { + describe: 'Source backend', + demandOption: true, + requiresArg: true, + string: true + }) + .alias('database:backend', 'from') + .option('from-config', { + describe: 'Source backend configuration', + requiresArg: true, + string: true + }) + .option('to', { + describe: 'Destination backend', + demandOption: true, + requiresArg: true, + string: true + }) + .option('to-config', { + describe: 'Destination backend configuration', + requiresArg: true, + string: true + }) + // strict(false) to support non-enumerated flags, which can be used for + // configuring backend settings. However, `from-config` should be preferred. + .strict(false) + .strictCommands(true) + ) }, command: 'migrate', - describe: 'Reads all key-value pairs from a given database and creates or updates another database accordingly.\n\n' + - '- The output database will be created if necessary.\n' + - '- The source database won\'t be modified nor deleted.\n' + - '- Invalid key-value pairs entries will be skipped.\n' + - '- Requires read and write access to the source.\n', + describe: + 'Reads all key-value pairs from a given database and creates or updates another database accordingly.\n\n' + + '- The output database will be created if necessary.\n' + + '- The source database won\'t be modified nor deleted.\n' + + '- Invalid key-value pairs entries will be skipped.\n' + + '- Requires read and write access to the source.\n', postHandler: (argv) => { return migrate(argv) } diff --git a/src/parseArgs.ts b/src/parseArgs.ts index 81d1a70..ebd41fc 100644 --- a/src/parseArgs.ts +++ b/src/parseArgs.ts @@ -11,7 +11,9 @@ const handlerState: { postHandler: () => void | Promise } = { } const parseArgs = () => { - const handlerWrapper = (commandModule: commands.CommandModule): YCommandModule => { + const handlerWrapper = ( + commandModule: commands.CommandModule + ): YCommandModule => { return { ...commandModule, handler: (argv: ArgumentsCamelCase) => { @@ -24,8 +26,8 @@ const parseArgs = () => { } // Typecasting seems to be required - const commandModules = Object.values(commands).map( - (c) => handlerWrapper(c as commands.CommandModule) + const commandModules = Object.values(commands).map((c) => + handlerWrapper(c as commands.CommandModule) ) const yargsInstance = yargs(hideBin(process.argv)) diff --git a/src/parseConfig.ts b/src/parseConfig.ts index 1819bdd..fcc606e 100644 --- a/src/parseConfig.ts +++ b/src/parseConfig.ts @@ -12,33 +12,33 @@ const parseConfig = () => { .argv(parseArgs()) .file({ file: 'chel.toml', format: { parse, stringify } }) .defaults({ - 'server': { - 'appDir': '.', - 'host': '0.0.0.0', - 'port': 8000, - 'dashboardPort': 8888, - 'fileUploadMaxBytes': 31457280, - 'signup': { - 'disabled': false, - 'limit': { - 'disabled': false, - 'minute': 2, - 'hour': 10, - 'day': 50 + server: { + appDir: '.', + host: '0.0.0.0', + port: 8000, + dashboardPort: 8888, + fileUploadMaxBytes: 31457280, + signup: { + disabled: false, + limit: { + disabled: false, + minute: 2, + hour: 10, + day: 50 }, - 'vapid': { - 'email': undefined + vapid: { + email: undefined } }, - 'logLevel': 'debug', - 'messages': [], - 'maxEventsBatchSize': 500, - 'archiveMode': false + logLevel: 'debug', + messages: [], + maxEventsBatchSize: 500, + archiveMode: false }, - 'database': { - 'lruNumItems': 10000, - 'backend': 'mem', - 'backendOptions': {} + database: { + lruNumItems: 10000, + backend: 'mem', + backendOptions: {} } }) } diff --git a/src/pin.ts b/src/pin.ts index ab7687c..a57919b 100644 --- a/src/pin.ts +++ b/src/pin.ts @@ -12,10 +12,10 @@ const VALID_VERSION = /^[a-zA-Z0-9_+-][a-zA-Z0-9._+-]*[a-zA-Z0-9_+-]?$/ // deno-lint-ignore no-control-regex const RESERVED_FILE_CHARS_REPLACE = /[\x00/\\:*?"<>|]/g -type Params = { overwrite: boolean, 'dir'?: string, 'manifest-version'?: string, manifest: string } +type Params = { overwrite: boolean; dir?: string; 'manifest-version'?: string; manifest: string } let projectRoot: string -let cheloniaConfig: { contracts: Record } +let cheloniaConfig: { contracts: Record } function sanitizeContractName (contractName: string): string { return contractName.replace(RESERVED_FILE_CHARS_REPLACE, '_').replace(/\.\./g, '__') @@ -41,7 +41,8 @@ export async function pin (args: ArgumentsCamelCase): Promise { exit(`Manifest file not found: ${manifestPath}`) } - const { contractName, fullContractName, contractFiles, manifestVersion } = await parseManifest(fullManifestPath) + const { contractName, fullContractName, contractFiles, manifestVersion } = + await parseManifest(fullManifestPath) if (!manifestVersion || !VALID_VERSION.test(manifestVersion)) { exit(`Invalid manifest version: ${manifestVersion}`) @@ -52,8 +53,14 @@ export async function pin (args: ArgumentsCamelCase): Promise { if (version) { if (version !== manifestVersion) { - console.error(colors.red(`❌ Version mismatch: CLI version (${version}) does not match manifest version (${manifestVersion})`)) - console.error(colors.yellow(`💡 To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)) + console.error( + colors.red( + `❌ Version mismatch: CLI version (${version}) does not match manifest version (${manifestVersion})` + ) + ) + console.error( + colors.yellow(`💡 To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`) + ) exit('Version mismatch between CLI and manifest') } @@ -62,23 +69,39 @@ export async function pin (args: ArgumentsCamelCase): Promise { const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version if (currentPinnedVersion === manifestVersion) { - console.log(colors.yellow(`✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)) + console.log( + colors.yellow( + `✨ Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed` + ) + ) return } if (currentPinnedVersion) { - console.log(colors.cyan(`📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)) + console.log( + colors.cyan( + `📌 Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}` + ) + ) } else { - console.log(colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`)) + console.log( + colors.cyan(`📌 Pinning ${fullContractName} to version ${manifestVersion} (first time)`) + ) } const contractVersionDir = join(projectRoot, 'contracts', contractName, manifestVersion) if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`) + exit( + `Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.` + ) } - console.log(colors.yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)) + console.log( + colors.yellow( + `Version ${manifestVersion} already exists for ${fullContractName} - checking files...` + ) + ) } else { await createVersionDirectory(contractName, manifestVersion) } @@ -86,7 +109,9 @@ export async function pin (args: ArgumentsCamelCase): Promise { await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args) await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath) - console.log(colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`)) + console.log( + colors.green(`✅ Successfully pinned ${fullContractName} to version ${manifestVersion}`) + ) console.log(colors.gray(`Location: contracts/${contractName}/${manifestVersion}/`)) } @@ -125,7 +150,7 @@ async function createVersionDirectory (contractName: string, version: string) { } async function copyContractFiles ( - contractFiles: { main: string, slim?: string }, + contractFiles: { main: string; slim?: string }, manifestPath: string, contractName: string, version: string, @@ -134,7 +159,11 @@ async function copyContractFiles ( const sourceDir = dirname(join(projectRoot, manifestPath)) const targetDir = join(projectRoot, 'contracts', contractName, version) - console.log(colors.gray(`📋 Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ''}, manifest`)) + console.log( + colors.gray( + `📋 Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ''}, manifest` + ) + ) // First, copy the contract files to the target directory const mainSource = join(sourceDir, contractFiles.main) @@ -174,7 +203,9 @@ async function copyFileIfNeeded ( } if (targetExists && !args.overwrite) { - console.log(colors.yellow(`⏭️ Skipping: ${fileName} (already exists, use --overwrite to replace)`)) + console.log( + colors.yellow(`⏭️ Skipping: ${fileName} (already exists, use --overwrite to replace)`) + ) return } @@ -203,7 +234,12 @@ async function loadCheloniaConfig () { } } -async function updateCheloniaConfig (fullContractName: string, contractName: string, version: string, manifestPath: string) { +async function updateCheloniaConfig ( + fullContractName: string, + contractName: string, + version: string, + manifestPath: string +) { const manifestFileName = basename(manifestPath) const pinnedManifestPath = `contracts/${contractName}/${version}/${manifestFileName}` diff --git a/src/serve.ts b/src/serve.ts index 7e1ceeb..394398d 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -9,11 +9,11 @@ import { startDashboard } from './serve/dashboard-server.ts' import { closeDB, initDB } from '~/serve/database.ts' type Params = { - port: number, - 'dashboard-port': number, - directory: string, - dev: boolean, - 'manifests-dir': string, + port: number + 'dashboard-port': number + directory: string + dev: boolean + 'manifests-dir': string 'app-manifest': string } @@ -59,7 +59,9 @@ async function watch (args: ArgumentsCamelCase): Promise { continue } if (event.kind !== 'create' && event.kind !== 'modify') continue - const manifests = event.paths.filter((path) => path.toLowerCase().endsWith('.manifest.json')) + const manifests = event.paths.filter((path) => + path.toLowerCase().endsWith('.manifest.json') + ) for (const manifestPath of manifests) { try { await sbp('okTurtles.eventQueue/queueEvent', queueName, async () => { diff --git a/src/types/build.d.ts b/src/types/build.d.ts index d7ab461..46b2f4a 100644 --- a/src/types/build.d.ts +++ b/src/types/build.d.ts @@ -1,17 +1,17 @@ interface ImportMeta { - VERSION: string, - ownerSizeTotalWorker?: string, - creditsWorker?: string, + VERSION: string + ownerSizeTotalWorker?: string + creditsWorker?: string lockDbSelectors?: boolean } declare const logger: { - level: string; + level: string levels: { - values: Record; - }; - debug: (...args: unknown[]) => void; - info: (...args: unknown[]) => void; - warn: (...args: unknown[]) => void; - error: (...args: unknown[]) => void; + values: Record + } + debug: (...args: unknown[]) => void + info: (...args: unknown[]) => void + warn: (...args: unknown[]) => void + error: (...args: unknown[]) => void } diff --git a/src/upload.ts b/src/upload.ts index 5016e14..d9d5fbf 100644 --- a/src/upload.ts +++ b/src/upload.ts @@ -7,9 +7,12 @@ import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { closeDB, initDB } from './serve/database.ts' import { createEntryFromFile, type Entry } from './utils.ts' -type Params = { url?: string, files: string[] } +type Params = { url?: string; files: string[] } -export async function upload (args: ArgumentsCamelCase, internal = false): Promise<[string, string][]> { +export async function upload ( + args: ArgumentsCamelCase, + internal = false +): Promise<[string, string][]> { const { url, files } = args let dbOpen = false if (!url) { @@ -18,14 +21,12 @@ export async function upload (args: ArgumentsCamelCase, internal = false } try { const uploaded: Array<[string, string]> = [] - const uploaderFn = url - ? uploadEntryToURL - : uploadEntryToDB + const uploaderFn = url ? uploadEntryToURL : uploadEntryToDB for (const filepath_ of files) { let type = multicodes.RAW let filepath = filepath_ if (internal) { - // The `{type}|` prefix is used to determine which kind of CID is needed + // The `{type}|` prefix is used to determine which kind of CID is needed if (filepath_[1] !== '|') throw new Error('Invalid path format') switch (filepath_[0]) { case 'r': @@ -65,7 +66,7 @@ async function uploadEntryToURL ([cid, buffer]: Entry, url: string): Promise { + .then((r) => { if (r !== `/file/${cid}`) { throw new Error(`server returned bad URL: ${r}`) } @@ -79,7 +80,7 @@ function uploadEntryToDB ([cid, buffer]: Entry): Promise { type ResponseTypeFn = 'arrayBuffer' | 'blob' | 'clone' | 'formData' | 'json' | 'text' -export function handleFetchResult (type: ResponseTypeFn): ((r: Response) => unknown) { +export function handleFetchResult (type: ResponseTypeFn): (r: Response) => unknown { return async function (r: Response) { if (!r.ok) throw new Error(`${r.status}: ${r.statusText}`) return await r[type]() diff --git a/src/utils.ts b/src/utils.ts index 9d1b61d..e91dcb8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -70,8 +70,13 @@ export function isValidKey (key: string): boolean { } export async function readRemoteData (src: string, key: string): Promise { - const buffer = await fetch(`${src}/file/${key}`) - .then(async r => r.ok ? await r.arrayBuffer() : await Promise.reject(new Error(`failed network request to ${src}: ${r.status} - ${r.statusText}`))) + const buffer = await fetch(`${src}/file/${key}`).then(async (r) => + r.ok + ? await r.arrayBuffer() + : await Promise.reject( + new Error(`failed network request to ${src}: ${r.status} - ${r.statusText}`) + ) + ) return new Uint8Array(buffer) } @@ -91,10 +96,7 @@ export interface ShellOptions { cwd?: string } -export async function shell ( - command: string, - options: ShellOptions = {} -): Promise { +export async function shell (command: string, options: ShellOptions = {}): Promise { const { printOutput = false, shell = '/bin/sh', cwd } = options const cmd = new Deno.Command(shell, { args: ['-c', command], @@ -112,9 +114,7 @@ export async function shell ( } if (code !== 0) { - throw new Error( - `Command failed with exit code ${code}: ${decoder.decode(stderr)}` - ) + throw new Error(`Command failed with exit code ${code}: ${decoder.decode(stderr)}`) } return decoder.decode(stdout).trim() diff --git a/src/verifySignature.ts b/src/verifySignature.ts index 303dd32..5449724 100644 --- a/src/verifySignature.ts +++ b/src/verifySignature.ts @@ -1,12 +1,16 @@ import * as colors from 'jsr:@std/fmt/colors' import * as path from 'jsr:@std/path/' -import { verifySignature as cryptoVerifySignature, deserializeKey, keyId } from 'npm:@chelonia/crypto' +import { + verifySignature as cryptoVerifySignature, + deserializeKey, + keyId +} from 'npm:@chelonia/crypto' import { multicodes } from 'npm:@chelonia/lib/functions' import type { ArgumentsCamelCase, CommandModule } from './commands.ts' import { hash } from './hash.ts' import { exit, readJsonFile, revokeNet } from './utils.ts' -type Params = { key?: string, manifestFile: string } +type Params = { key?: string; manifestFile: string } interface ExternalKeyDescriptor { pubkey: string @@ -24,7 +28,11 @@ interface Manifest { } function isExternalKeyDescriptor (obj: unknown): obj is ExternalKeyDescriptor { - return obj !== null && typeof obj === 'object' && typeof (obj as Record).pubkey === 'string' + return ( + obj !== null && + typeof obj === 'object' && + typeof (obj as Record).pubkey === 'string' + ) } function isManifest (obj: unknown): obj is Manifest { @@ -39,7 +47,10 @@ function isManifest (obj: unknown): obj is Manifest { ) } -export const verifySignature = async (args: ArgumentsCamelCase, internal = false): Promise => { +export const verifySignature = async ( + args: ArgumentsCamelCase, + internal = false +): Promise => { await revokeNet() const { key: keyFile, manifestFile } = args const [externalKeyDescriptorRaw, manifestRaw] = await Promise.all([ @@ -83,7 +94,10 @@ export const verifySignature = async (args: ArgumentsCamelCase, internal if (externalKeyDescriptor) { const id = keyId(externalKeyDescriptor.pubkey) if (manifest.signature.keyId !== id) { - exit(`Invalid manifest signature: key ID doesn't match the provided key file. Expected ${id} but got ${manifest.signature.keyId}.`, internal) + exit( + `Invalid manifest signature: key ID doesn't match the provided key file. Expected ${id} but got ${manifest.signature.keyId}.`, + internal + ) } } @@ -91,7 +105,10 @@ export const verifySignature = async (args: ArgumentsCamelCase, internal // even if it is missing in body.signingKeys const serializedPubKey = signingKey || externalKeyDescriptor?.pubkey if (!serializedPubKey) { - exit('The manifest appears to be signed but verification can\'t proceed because the key used is unknown.', internal) + exit( + 'The manifest appears to be signed but verification can\'t proceed because the key used is unknown.', + internal + ) } const pubKey = deserializeKey(serializedPubKey) @@ -109,15 +126,29 @@ export const verifySignature = async (args: ArgumentsCamelCase, internal if (!body.contract?.file) { exit('Invalid manifest: no contract file', internal) } - const computedHash = await hash({ ...args, filename: path.join(parsedFilepath.dir, body.contract.file) }, multicodes.SHELTER_CONTRACT_TEXT, true) + const computedHash = await hash( + { ...args, filename: path.join(parsedFilepath.dir, body.contract.file) }, + multicodes.SHELTER_CONTRACT_TEXT, + true + ) if (computedHash !== body.contract.hash) { - exit(`Invalid contract file hash. Expected ${body.contract.hash} but got ${computedHash}`, internal) + exit( + `Invalid contract file hash. Expected ${body.contract.hash} but got ${computedHash}`, + internal + ) } if (body.contractSlim) { - const computedHash = await hash({ ...args, filename: path.join(parsedFilepath.dir, body.contractSlim.file) }, multicodes.SHELTER_CONTRACT_TEXT, true) + const computedHash = await hash( + { ...args, filename: path.join(parsedFilepath.dir, body.contractSlim.file) }, + multicodes.SHELTER_CONTRACT_TEXT, + true + ) if (computedHash !== body.contractSlim.hash) { - exit(`Invalid slim contract file hash. Expected ${body.contractSlim.hash} but got ${computedHash}`, internal) + exit( + `Invalid slim contract file hash. Expected ${body.contractSlim.hash} but got ${computedHash}`, + internal + ) } } @@ -130,7 +161,7 @@ export const module = { .option('key', { describe: 'Public key', requiresArg: true, - string: true, + string: true }) .alias('k', 'key') .positional('manifestFile', { From 53c62a680688ccb59f897a31e251ec20b0f14354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 2 May 2026 19:13:27 +0000 Subject: [PATCH 65/71] Indentation --- src/serve/routes.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/serve/routes.ts b/src/serve/routes.ts index a66c970..a96cee9 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -696,14 +696,14 @@ export function registerRoutes (app: Hono): void { // Now that the manifest format looks right, validate the chunks let ourSize = 0 const chunks: [string, Uint8Array][] = await Promise.all(manifest.chunks.map(async (chunk: [number, string], i: number) => { - // Validate the chunk information + // Validate the chunk information if ( !Array.isArray(chunk) || - chunk.length !== 2 || - typeof chunk[0] !== 'number' || - typeof chunk[1] !== 'string' || - !Number.isSafeInteger(chunk[0]) || - chunk[0] <= 0 + chunk.length !== 2 || + typeof chunk[0] !== 'number' || + typeof chunk[1] !== 'string' || + !Number.isSafeInteger(chunk[0]) || + chunk[0] <= 0 ) { throw new HTTPException(422, { message: 'bad chunk description' }) } From e2b0bd60efb087b27bff62469e3f902793b2108c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 2 May 2026 19:36:29 +0000 Subject: [PATCH 66/71] dist --- build/main.js | 189 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 130 insertions(+), 59 deletions(-) diff --git a/build/main.js b/build/main.js index 93f00bb..63d6f37 100644 --- a/build/main.js +++ b/build/main.js @@ -69013,7 +69013,11 @@ function isValidKey(key) { return !/[\x00-\x1f\x7f\t\\/]/.test(key); } async function readRemoteData(src2, key) { - const buffer = await fetch(`${src2}/file/${key}`).then(async (r) => r.ok ? await r.arrayBuffer() : await Promise.reject(new Error(`failed network request to ${src2}: ${r.status} - ${r.statusText}`))); + const buffer = await fetch(`${src2}/file/${key}`).then( + async (r) => r.ok ? await r.arrayBuffer() : await Promise.reject( + new Error(`failed network request to ${src2}: ${r.status} - ${r.statusText}`) + ) + ); return new Uint8Array(buffer); } async function revokeNet() { @@ -69193,7 +69197,12 @@ var module3 = { } }; init_esm(); -async function eventsAfter2({ limit, url: url2, contractID, height }) { +async function eventsAfter2({ + limit, + url: url2, + contractID, + height +}) { let dbOpen = false; try { let messages; @@ -69234,13 +69243,17 @@ async function getRemoteMessagesSince(src2, contractID, sinceHeight, limit) { const response = await fetch(`${src2}/eventsAfter/${contractID}/${sinceHeight}`); if (!response.ok) { const bodyText = await response.text().catch(() => "") || ""; - throw new Error(`failed network request to ${src2}: ${response.status} - ${response.statusText} - '${bodyText}'`); + throw new Error( + `failed network request to ${src2}: ${response.status} - ${response.statusText} - '${bodyText}'` + ); } const b64messages = await response.json(); if (b64messages.length > limit) { b64messages.length = limit; } - return b64messages.map((b64str) => JSON.parse(new TextDecoder().decode(decodeBase64(b64str)))); + return b64messages.map( + (b64str) => JSON.parse(new TextDecoder().decode(decodeBase64(b64str))) + ); } var module4 = { builder: (yargs) => { @@ -69400,21 +69413,27 @@ async function manifest(args) { } const signingKeyDescriptor = signingKeyDescriptorRaw; const signingKey = deserializeKey(signingKeyDescriptor.privkey); - const publicKeys = Array.from(new Set( - [serializeKey(signingKey, false)].concat(...await Promise.all(args.key?.map( - async (kf) => { - if (typeof kf !== "string" && typeof kf !== "number") { - exit(`Invalid key file reference: ${String(kf)}`); - } - const descriptor = await readJsonFile(String(kf)); - const key = deserializeKey(descriptor.pubkey); - if (key.type !== EDWARDS25519SHA512BATCH) { - exit(`Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.`); - } - return serializeKey(key, false); - } - ) || [])) - )); + const publicKeys = Array.from( + new Set( + [serializeKey(signingKey, false)].concat( + ...await Promise.all( + args.key?.map(async (kf) => { + if (typeof kf !== "string" && typeof kf !== "number") { + exit(`Invalid key file reference: ${String(kf)}`); + } + const descriptor = await readJsonFile(String(kf)); + const key = deserializeKey(descriptor.pubkey); + if (key.type !== EDWARDS25519SHA512BATCH) { + exit( + `Invalid key type ${key.type}; only ${EDWARDS25519SHA512BATCH} keys are supported.` + ); + } + return serializeKey(key, false); + }) || [] + ) + ) + ) + ); const body = { name, version: version3, @@ -69667,34 +69686,58 @@ async function pin(args) { console.log(blue(`Manifest version: ${manifestVersion}`)); if (version3) { if (version3 !== manifestVersion) { - console.error(red(`\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})`)); - console.error(yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`)); + console.error( + red( + `\u274C Version mismatch: CLI version (${version3}) does not match manifest version (${manifestVersion})` + ) + ); + console.error( + yellow(`\u{1F4A1} To pin this contract, use: chel pin ${manifestVersion} ${manifestPath}`) + ); exit("Version mismatch between CLI and manifest"); } console.log(green(`\u2705 Version validation passed: ${version3}`)); } const currentPinnedVersion = cheloniaConfig.contracts[fullContractName]?.version; if (currentPinnedVersion === manifestVersion) { - console.log(yellow(`\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed`)); + console.log( + yellow( + `\u2728 Contract ${fullContractName} is already pinned to version ${manifestVersion} - no action needed` + ) + ); return; } if (currentPinnedVersion) { - console.log(cyan(`\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}`)); + console.log( + cyan( + `\u{1F4CC} Updating ${fullContractName} from version ${currentPinnedVersion} to ${manifestVersion}` + ) + ); } else { - console.log(cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`)); + console.log( + cyan(`\u{1F4CC} Pinning ${fullContractName} to version ${manifestVersion} (first time)`) + ); } const contractVersionDir = join62(projectRoot, "contracts", contractName, manifestVersion); if (existsSync(contractVersionDir)) { if (!args.overwrite) { - exit(`Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.`); + exit( + `Version ${manifestVersion} already exists for contract ${fullContractName}. Use --overwrite to replace it.` + ); } - console.log(yellow(`Version ${manifestVersion} already exists for ${fullContractName} - checking files...`)); + console.log( + yellow( + `Version ${manifestVersion} already exists for ${fullContractName} - checking files...` + ) + ); } else { await createVersionDirectory(contractName, manifestVersion); } await copyContractFiles(contractFiles, manifestPath, contractName, manifestVersion, args); await updateCheloniaConfig(fullContractName, contractName, manifestVersion, manifestPath); - console.log(green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`)); + console.log( + green(`\u2705 Successfully pinned ${fullContractName} to version ${manifestVersion}`) + ); console.log(gray(`Location: contracts/${contractName}/${manifestVersion}/`)); } async function parseManifest(manifestPath) { @@ -69728,7 +69771,11 @@ async function createVersionDirectory(contractName, version3) { async function copyContractFiles(contractFiles, manifestPath, contractName, version3, args) { const sourceDir = dirname42(join62(projectRoot, manifestPath)); const targetDir = join62(projectRoot, "contracts", contractName, version3); - console.log(gray(`\u{1F4CB} Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ""}, manifest`)); + console.log( + gray( + `\u{1F4CB} Copying files from manifest: ${contractFiles.main}${contractFiles.slim ? `, ${contractFiles.slim}` : ""}, manifest` + ) + ); const mainSource = join62(sourceDir, contractFiles.main); const mainTarget = join62(targetDir, contractFiles.main); await copyFileIfNeeded(mainSource, mainTarget, contractFiles.main, args); @@ -69754,7 +69801,9 @@ async function copyFileIfNeeded(sourcePath, targetPath, fileName, args) { return; } if (targetExists && !args.overwrite) { - console.log(yellow(`\u23ED\uFE0F Skipping: ${fileName} (already exists, use --overwrite to replace)`)); + console.log( + yellow(`\u23ED\uFE0F Skipping: ${fileName} (already exists, use --overwrite to replace)`) + ); return; } console.log(blue(`\u{1F4C4} Copying: ${fileName} (overwriting)`)); @@ -76040,7 +76089,9 @@ async function watch(args) { continue; } if (event.kind !== "create" && event.kind !== "modify") continue; - const manifests = event.paths.filter((path8) => path8.toLowerCase().endsWith(".manifest.json")); + const manifests = event.paths.filter( + (path8) => path8.toLowerCase().endsWith(".manifest.json") + ); for (const manifestPath of manifests) { try { await esm_default("okTurtles.eventQueue/queueEvent", queueName, async () => { @@ -76182,12 +76233,18 @@ var verifySignature2 = async (args, internal = false) => { if (externalKeyDescriptor) { const id = keyId(externalKeyDescriptor.pubkey); if (manifest2.signature.keyId !== id) { - exit(`Invalid manifest signature: key ID doesn't match the provided key file. Expected ${id} but got ${manifest2.signature.keyId}.`, internal); + exit( + `Invalid manifest signature: key ID doesn't match the provided key file. Expected ${id} but got ${manifest2.signature.keyId}.`, + internal + ); } } const serializedPubKey = signingKey || externalKeyDescriptor?.pubkey; if (!serializedPubKey) { - exit("The manifest appears to be signed but verification can't proceed because the key used is unknown.", internal); + exit( + "The manifest appears to be signed but verification can't proceed because the key used is unknown.", + internal + ); } const pubKey = deserializeKey(serializedPubKey); try { @@ -76202,14 +76259,28 @@ var verifySignature2 = async (args, internal = false) => { if (!body.contract?.file) { exit("Invalid manifest: no contract file", internal); } - const computedHash = await hash22({ ...args, filename: join8(parsedFilepath.dir, body.contract.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); + const computedHash = await hash22( + { ...args, filename: join8(parsedFilepath.dir, body.contract.file) }, + multicodes.SHELTER_CONTRACT_TEXT, + true + ); if (computedHash !== body.contract.hash) { - exit(`Invalid contract file hash. Expected ${body.contract.hash} but got ${computedHash}`, internal); + exit( + `Invalid contract file hash. Expected ${body.contract.hash} but got ${computedHash}`, + internal + ); } if (body.contractSlim) { - const computedHash2 = await hash22({ ...args, filename: join8(parsedFilepath.dir, body.contractSlim.file) }, multicodes.SHELTER_CONTRACT_TEXT, true); + const computedHash2 = await hash22( + { ...args, filename: join8(parsedFilepath.dir, body.contractSlim.file) }, + multicodes.SHELTER_CONTRACT_TEXT, + true + ); if (computedHash2 !== body.contractSlim.hash) { - exit(`Invalid slim contract file hash. Expected ${body.contractSlim.hash} but got ${computedHash2}`, internal); + exit( + `Invalid slim contract file hash. Expected ${body.contractSlim.hash} but got ${computedHash2}`, + internal + ); } } if (!internal) console.log(green("ok"), "all checks passed"); @@ -80388,33 +80459,33 @@ var parseConfig = () => { separator: "__", parseValues: true }).argv(parseArgs_default()).file({ file: "chel.toml", format: { parse: parse8, stringify } }).defaults({ - "server": { - "appDir": ".", - "host": "0.0.0.0", - "port": 8e3, - "dashboardPort": 8888, - "fileUploadMaxBytes": 31457280, - "signup": { - "disabled": false, - "limit": { - "disabled": false, - "minute": 2, - "hour": 10, - "day": 50 + server: { + appDir: ".", + host: "0.0.0.0", + port: 8e3, + dashboardPort: 8888, + fileUploadMaxBytes: 31457280, + signup: { + disabled: false, + limit: { + disabled: false, + minute: 2, + hour: 10, + day: 50 }, - "vapid": { - "email": void 0 + vapid: { + email: void 0 } }, - "logLevel": "debug", - "messages": [], - "maxEventsBatchSize": 500, - "archiveMode": false + logLevel: "debug", + messages: [], + maxEventsBatchSize: 500, + archiveMode: false }, - "database": { - "lruNumItems": 1e4, - "backend": "mem", - "backendOptions": {} + database: { + lruNumItems: 1e4, + backend: "mem", + backendOptions: {} } }); }; From 040f7d059c7b373c184bf6fb91dad63abd893701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 2 May 2026 20:10:12 +0000 Subject: [PATCH 67/71] Fixes --- .github/workflows/pull-request-bin.yml | 2 -- build/main.js | 2 +- src/serve/routes.ts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pull-request-bin.yml b/.github/workflows/pull-request-bin.yml index 4911b93..5d0dd10 100644 --- a/.github/workflows/pull-request-bin.yml +++ b/.github/workflows/pull-request-bin.yml @@ -4,8 +4,6 @@ permissions: contents: read on: - push: - branches: [ "master" ] pull_request: branches: [ "master" ] diff --git a/build/main.js b/build/main.js index 63d6f37..6afe922 100644 --- a/build/main.js +++ b/build/main.js @@ -73824,7 +73824,7 @@ function notFoundNoCache(c) { function safePathWithin(base2, subpath) { const normalizedBase = path5.resolve(base2); const resolved = path5.resolve(normalizedBase, subpath); - if (!resolved.startsWith(base2 + path5.sep) && resolved !== normalizedBase) return null; + if (!resolved.startsWith(normalizedBase + path5.sep) && resolved !== normalizedBase) return null; return resolved; } function serveAsset(c, subpath, assetsDir) { diff --git a/src/serve/routes.ts b/src/serve/routes.ts index a96cee9..e9f80b5 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -253,7 +253,7 @@ function notFoundNoCache (c: Context): Response { function safePathWithin (base: string, subpath: string): string | null { const normalizedBase = path.resolve(base) const resolved = path.resolve(normalizedBase, subpath) - if (!resolved.startsWith(base + path.sep) && resolved !== normalizedBase) return null + if (!resolved.startsWith(normalizedBase + path.sep) && resolved !== normalizedBase) return null return resolved } From 9f97ba41fba85c6e02bccbf61db9d58613de52d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Sat, 2 May 2026 20:29:45 +0000 Subject: [PATCH 68/71] feedback --- build/main.js | 4 ++-- src/hash.ts | 3 ++- src/serve.ts | 2 +- src/serve/auth.ts | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/build/main.js b/build/main.js index 6afe922..a625aa4 100644 --- a/build/main.js +++ b/build/main.js @@ -69342,7 +69342,7 @@ var module6 = { }); }, command: "hash ", - describe: "Computes and logs the content identifier (CID) for the given file.\n' + 'File contents will be interpreted as raw binary data, unless the file extension is '.json'.", + describe: "Computes and logs the content identifier (CID) for the given file.\nFile contents will be interpreted as raw binary data, unless the file extension is '.json'.", postHandler: (argv) => { return void hash22(argv); } @@ -73647,7 +73647,7 @@ function authMiddleware(strategies, mode = "required") { return next(); } } - if (mode === "optional") { + if (mode === "optional" && !c.req.header("authorization")) { c.set("credentials", {}); c.set("authStrategy", ""); return next(); diff --git a/src/hash.ts b/src/hash.ts index 17a796c..da67443 100644 --- a/src/hash.ts +++ b/src/hash.ts @@ -31,7 +31,8 @@ export const module = { }, command: 'hash ', describe: - 'Computes and logs the content identifier (CID) for the given file.\n\' + \'File contents will be interpreted as raw binary data, unless the file extension is \'.json\'.', + 'Computes and logs the content identifier (CID) for the given file.\n' + + 'File contents will be interpreted as raw binary data, unless the file extension is \'.json\'.', postHandler: (argv) => { return void hash(argv) } diff --git a/src/serve.ts b/src/serve.ts index 394398d..a31230f 100644 --- a/src/serve.ts +++ b/src/serve.ts @@ -87,7 +87,7 @@ async function watch (args: ArgumentsCamelCase): Promise { export async function serve (args: ArgumentsCamelCase) { // `deployManifests` / `watch` will open the database and then close it. - // By callig `initDB` here, we ensure that the DB isn't closed. + // By calling `initDB` here, we ensure that the DB isn't closed. await initDB() try { // Start dashboard server on port 7000 first diff --git a/src/serve/auth.ts b/src/serve/auth.ts index d8609c8..9fafeb7 100644 --- a/src/serve/auth.ts +++ b/src/serve/auth.ts @@ -59,7 +59,7 @@ export function authMiddleware ( return next() } } - if (mode === 'optional') { + if (mode === 'optional' && !c.req.header('authorization')) { c.set('credentials', {} as AuthCredentials) c.set('authStrategy', '') return next() From af3566dbd8cb05c323f81c347f2cf59df190d02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 4 May 2026 19:27:16 +0000 Subject: [PATCH 69/71] Feedback --- build/main.js | 9 ++++++++- src/serve/routes.ts | 4 +++- src/serve/server.ts | 8 ++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build/main.js b/build/main.js index a625aa4..54ba607 100644 --- a/build/main.js +++ b/build/main.js @@ -74455,7 +74455,9 @@ function registerRoutes(app) { return serveAsset(c, subpath, staticServeConfig.distAssets); }); } - app.get(isCheloniaDashboard ? "/dashboard/*" : "/app/*", etag(), async function(c) { + const spaPrefix = isCheloniaDashboard ? "/dashboard" : "/app"; + app.get(spaPrefix, (c) => c.redirect(`${spaPrefix}/`)); + app.get(`${spaPrefix}/*`, etag(), async function(c) { try { const file = await Deno.readFile(staticServeConfig.distIndexHtml); return c.body(file, 200, { "Content-Type": "text/html" }); @@ -75457,6 +75459,11 @@ async function startServer() { await next(); c.header("X-Frame-Options", "DENY"); }); + currentApp.onError((err, c) => { + const response = err instanceof HTTPException ? err.getResponse() : c.text("Internal Server Error", 500); + response.headers.set("X-Frame-Options", "DENY"); + return response; + }); if (process9.env.NODE_ENV === "development" && !process9.env.CI) { currentApp.use("*", async (c, next) => { await next(); diff --git a/src/serve/routes.ts b/src/serve/routes.ts index e9f80b5..404e744 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -1051,7 +1051,9 @@ export function registerRoutes (app: Hono): void { } // SPA catch-all route - app.get(isCheloniaDashboard ? '/dashboard/*' : '/app/*', etag(), async function (c) { + const spaPrefix = isCheloniaDashboard ? '/dashboard' : '/app' + app.get(spaPrefix, (c) => c.redirect(`${spaPrefix}/`)) + app.get(`${spaPrefix}/*`, etag(), async function (c) { try { const file = await Deno.readFile(staticServeConfig.distIndexHtml) return c.body(file, 200, { 'Content-Type': 'text/html' }) diff --git a/src/serve/server.ts b/src/serve/server.ts index 6c9db45..624436a 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -33,6 +33,7 @@ import { } from './pubsub.ts' import { addChannelToSubscription, deleteChannelFromSubscription, postEvent, pushServerActionhandlers, subscriptionInfoWrapper } from './push.ts' import { pathToFileURL } from 'node:url' +import { HTTPException } from 'npm:hono/http-exception' // @deno-types="npm:@types/nconf" import nconf from 'npm:nconf' @@ -423,6 +424,13 @@ export async function startServer (): Promise<{ uri: string }> { await next() c.header('X-Frame-Options', 'DENY') }) + currentApp.onError((err, c) => { + const response = err instanceof HTTPException + ? err.getResponse() + : c.text('Internal Server Error', 500) + response.headers.set('X-Frame-Options', 'DENY') + return response + }) // Dev logging middleware if (process.env.NODE_ENV === 'development' && !process.env.CI) { From 348983e59d970416775bdf242a6a52eac0fba11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 4 May 2026 20:22:50 +0000 Subject: [PATCH 70/71] Feedback --- build/main.js | 35 +++++++++++++++-------------------- src/serve/routes.ts | 32 ++++++++++++-------------------- src/serve/server.ts | 4 ++++ 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/build/main.js b/build/main.js index 54ba607..93f2a4a 100644 --- a/build/main.js +++ b/build/main.js @@ -74018,7 +74018,7 @@ function registerRoutes(app) { c.req.raw.signal.addEventListener("abort", () => stream.destroy()); const streamHeaders = stream.headers || {}; const webStream = Readable3.toWeb(stream); - return new Response(webStream, { + return c.body(webStream, { headers: { "content-type": "application/json", ...streamHeaders } }); } catch (err) { @@ -74373,12 +74373,9 @@ function registerRoutes(app) { if (expectedEtag === "*") { } else { if (!expectedEtag.split(",").map((v2) => v2.trim()).includes(`"${cid}"`)) { - return new Response(existing || "", { - status: 412, - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"` - } + return c.body(existing || "", 412, { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` }); } } @@ -74386,12 +74383,9 @@ function registerRoutes(app) { const serializedData = JSON.parse(payloadBuffer.toString()); const { contracts } = esm_default("chelonia/rootState"); if (contracts[contractID].height !== Number(serializedData.height)) { - return new Response(existing || "", { - status: 409, - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"` - } + return c.body(existing || "", 409, { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"` }); } esm_default("chelonia/parseEncryptedOrUnencryptedDetachedMessage", { @@ -74400,7 +74394,7 @@ function registerRoutes(app) { meta: key }); } catch (parseErr) { - if (parseErr instanceof Response) throw parseErr; + console.error(parseErr, "/kv/:contractID/:key", contractID, key); throw new HTTPException(422); } const existingSize = existing ? Buffer14.from(existing).byteLength : 0; @@ -74431,12 +74425,10 @@ function registerRoutes(app) { return notFoundNoCache(c); } const cid = createCID(result, multicodes.RAW); - return new Response(result, { - headers: { - "ETag": `"${cid}"`, - "x-cid": `"${cid}"`, - "Cache-Control": "no-store" - } + return c.body(result, 200, { + "ETag": `"${cid}"`, + "x-cid": `"${cid}"`, + "Cache-Control": "no-store" }); } ); @@ -75460,6 +75452,9 @@ async function startServer() { c.header("X-Frame-Options", "DENY"); }); currentApp.onError((err, c) => { + if (!(err instanceof HTTPException)) { + console.error(err, "Unhandled error in route handler"); + } const response = err instanceof HTTPException ? err.getResponse() : c.text("Internal Server Error", 500); response.headers.set("X-Frame-Options", "DENY"); return response; diff --git a/src/serve/routes.ts b/src/serve/routes.ts index 404e744..7fe6d02 100644 --- a/src/serve/routes.ts +++ b/src/serve/routes.ts @@ -491,7 +491,7 @@ export function registerRoutes (app: Hono): void { // Convert the Node Readable stream to a web ReadableStream for the Response const streamHeaders = (stream as { headers?: Record }).headers || {} const webStream = Readable.toWeb(stream) as ReadableStream - return new Response(webStream, { + return c.body(webStream, { headers: { 'content-type': 'application/json', ...streamHeaders } }) } catch (err) { @@ -953,12 +953,9 @@ export function registerRoutes (app: Hono): void { // pass through } else { if (!expectedEtag.split(',').map((v: string) => v.trim()).includes(`"${cid}"`)) { - return new Response(existing || '', { - status: 412, - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"` - } + return c.body(existing || '', 412, { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` }) } } @@ -968,12 +965,9 @@ export function registerRoutes (app: Hono): void { const { contracts } = sbp('chelonia/rootState') // Check that the height is the latest value if (contracts[contractID].height !== Number(serializedData.height)) { - return new Response(existing || '', { - status: 409, - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"` - } + return c.body(existing || '', 409, { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"` }) } // Check that the signature is valid @@ -983,7 +977,7 @@ export function registerRoutes (app: Hono): void { meta: key }) } catch (parseErr) { - if (parseErr instanceof Response) throw parseErr + console.error(parseErr, '/kv/:contractID/:key', contractID, key) throw new HTTPException(422) } @@ -1020,12 +1014,10 @@ export function registerRoutes (app: Hono): void { } const cid = createCID(result, multicodes.RAW) - return new Response(result, { - headers: { - 'ETag': `"${cid}"`, - 'x-cid': `"${cid}"`, - 'Cache-Control': 'no-store' - } + return c.body(result, 200, { + 'ETag': `"${cid}"`, + 'x-cid': `"${cid}"`, + 'Cache-Control': 'no-store' }) }) diff --git a/src/serve/server.ts b/src/serve/server.ts index 624436a..ea19fc6 100644 --- a/src/serve/server.ts +++ b/src/serve/server.ts @@ -425,6 +425,10 @@ export async function startServer (): Promise<{ uri: string }> { c.header('X-Frame-Options', 'DENY') }) currentApp.onError((err, c) => { + if (!(err instanceof HTTPException)) { + console.error(err, 'Unhandled error in route handler') + } + const response = err instanceof HTTPException ? err.getResponse() : c.text('Internal Server Error', 500) From bbe963fb021c4849975dcbdcfa4edb8fb337ef33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Iv=C3=A1n=20Vieitez=20Parra?= <3857362+corrideat@users.noreply.github.com> Date: Mon, 4 May 2026 20:25:18 +0000 Subject: [PATCH 71/71] db refs --- build/main.js | 14 ++++++++++---- src/serve/database.ts | 19 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/build/main.js b/build/main.js index 93f2a4a..443577b 100644 --- a/build/main.js +++ b/build/main.js @@ -68879,9 +68879,11 @@ var getCurrentInitPromise = () => initPromise ?? Promise.resolve(); var getCurrentClosePromise = () => closePromise ?? Promise.resolve(); var initDB = async ({ skipDbPreloading } = {}) => { await getCurrentClosePromise(); + const isFirstRef = dbRefs === 0; + dbRefs++; const thisInitPromise = initPromise ?? (async () => { installBaseSelectorsOnce(); - if (!dbRefs) { + if (isFirstRef) { const backend = import_npm_nconf2.default.get("database:backend"); const persistence = backend || (production ? "fs" : void 0); const options2 = import_npm_nconf2.default.get("database:backendOptions"); @@ -68954,15 +68956,19 @@ var initDB = async ({ skipDbPreloading } = {}) => { } } } - dbRefs++; if (skipDbPreloading || preloaded) return; await Promise.all([initVapid(), initZkpp()]); preloaded = true; })(); initPromise = thisInitPromise; - await thisInitPromise.finally(() => { + try { + await thisInitPromise; + } catch (e2) { + dbRefs--; + throw e2; + } finally { initPromise = null; - }); + } }; async function closeDB() { await getCurrentInitPromise(); diff --git a/src/serve/database.ts b/src/serve/database.ts index 56c8d5b..39d669e 100644 --- a/src/serve/database.ts +++ b/src/serve/database.ts @@ -203,11 +203,16 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean // Await any ongoing close operation first await getCurrentClosePromise() + // Increment per-caller refcount immediately so concurrent callers each + // contribute a reference, independent of the shared init promise below. + const isFirstRef = dbRefs === 0 + dbRefs++ + // Queue this init operation const thisInitPromise = initPromise ?? (async () => { installBaseSelectorsOnce() - if (!dbRefs) { + if (isFirstRef) { // First-time initialization const backend = nconf.get('database:backend') const persistence = backend || (production ? 'fs' : undefined) @@ -285,8 +290,6 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean } } - dbRefs++ - if (skipDbPreloading || preloaded) return await Promise.all([initVapid(), initZkpp()]) @@ -294,9 +297,15 @@ export const initDB = async ({ skipDbPreloading }: { skipDbPreloading?: boolean })() initPromise = thisInitPromise - await thisInitPromise.finally(() => { + try { + await thisInitPromise + } catch (e) { + // Roll back our reference if shared initialization failed + dbRefs-- + throw e + } finally { initPromise = null - }) + } } export async function closeDB (): Promise {