From 92d78d351f27ca83a0a08e6e88fa31f1acf394e0 Mon Sep 17 00:00:00 2001 From: wraymo <37269683+wraymo@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:56:44 -0400 Subject: [PATCH] log-viewer-webui: Add server implementation for submitting IR extraction jobs and serving IR files; Don't copy unnecessary files when building component. (#458) --- Taskfile.yml | 35 +- .../clp_package_utils/general.py | 10 +- .../clp_package_utils/scripts/start_clp.py | 79 +- .../clp-py-utils/clp_py_utils/clp_config.py | 1 - components/log-viewer-webui/server/.env | 5 + components/log-viewer-webui/server/.gitignore | 3 + .../log-viewer-webui/server/package-lock.json | 1318 +++++++++++++++-- .../log-viewer-webui/server/package.json | 19 +- .../log-viewer-webui/server/settings.json | 13 + .../log-viewer-webui/server/src/DbManager.js | 241 +++ components/log-viewer-webui/server/src/app.js | 57 +- .../log-viewer-webui/server/src/app.test.js | 9 +- .../log-viewer-webui/server/src/main.js | 22 +- .../src/routes/{examples.js => example.js} | 4 +- .../server/src/routes/query.js | 40 + .../log-viewer-webui/server/src/utils.js | 13 + .../package-template/src/etc/clp-config.yml | 2 +- lint-tasks.yml | 6 +- 18 files changed, 1653 insertions(+), 224 deletions(-) create mode 100644 components/log-viewer-webui/server/settings.json create mode 100644 components/log-viewer-webui/server/src/DbManager.js rename components/log-viewer-webui/server/src/routes/{examples.js => example.js} (75%) create mode 100644 components/log-viewer-webui/server/src/routes/query.js create mode 100644 components/log-viewer-webui/server/src/utils.js diff --git a/Taskfile.yml b/Taskfile.yml index e01bda896..e547dd68b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -10,6 +10,7 @@ vars: G_BUILD_DIR: "{{.ROOT_DIR}}/build" G_CORE_COMPONENT_BUILD_DIR: "{{.G_BUILD_DIR}}/core" G_LOG_VIEWER_WEBUI_BUILD_DIR: "{{.G_BUILD_DIR}}/log-viewer-webui" + G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" G_METEOR_BUILD_DIR: "{{.G_BUILD_DIR}}/meteor" G_NODEJS_14_BUILD_DIR: "{{.G_BUILD_DIR}}/nodejs-14" G_NODEJS_14_BIN_DIR: "{{.G_NODEJS_14_BUILD_DIR}}/bin" @@ -73,6 +74,7 @@ tasks: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_PACKAGE_BUILD_DIR}}" sources: + - "{{.G_BUILD_DIR}}/log-viewer-webui-client.md5" - "{{.G_BUILD_DIR}}/package-venv.md5" - "{{.G_BUILD_DIR}}/webui.md5" - "{{.G_BUILD_DIR}}/webui-nodejs.md5" @@ -81,6 +83,10 @@ tasks: - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/clp-s" - "{{.G_CORE_COMPONENT_BUILD_DIR}}/reducer-server" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package-lock.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/settings.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/*.js" - "{{.TASKFILE}}" - "/etc/os-release" - "components/clp-package-utils/dist/*.whl" @@ -94,7 +100,7 @@ tasks: - "clp-py-utils" - "init" - "job-orchestration" - - "log-viewer-webui" + - "log-viewer-webui-client" - "nodejs-14" - "package-venv" - task: "utils:validate-checksum" @@ -143,10 +149,15 @@ tasks: PATH="{{.G_NODEJS_14_BIN_DIR}}":$PATH npm install - >- rsync -a - "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/" - "{{.OUTPUT_DIR}}/var/www/log_viewer/" + "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}/client" + "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/" - |- - cd "{{.OUTPUT_DIR}}/var/www/log_viewer/server" + cd components/log-viewer-webui/server/ + rsync -a \ + package.json package-lock.json settings.json src \ + "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/server/" + - |- + cd "{{.OUTPUT_DIR}}/var/www/log_viewer_webui/server" PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm clean-install # This command must be last - task: "utils:compute-checksum" @@ -195,19 +206,17 @@ tasks: vars: COMPONENT: "{{.TASK}}" - log-viewer-webui: + log-viewer-webui-client: vars: CHECKSUM_FILE: "{{.G_BUILD_DIR}}/{{.TASK}}.md5" OUTPUT_DIR: "{{.G_LOG_VIEWER_WEBUI_BUILD_DIR}}" sources: - "{{.G_BUILD_DIR}}/log-viewer-modules.md5" - "{{.TASKFILE}}" + - "client/package.json" - "client/src/**/*.css" - "client/src/**/*.jsx" - - "client/src/package.json" - "client/src/webpack.config.js" - - "server/src/**/*.js" - - "server/src/**/package.json" dir: "components/log-viewer-webui" generates: ["{{.CHECKSUM_FILE}}"] deps: @@ -219,14 +228,10 @@ tasks: DATA_DIR: "{{.OUTPUT_DIR}}" cmds: - "rm -rf '{{.OUTPUT_DIR}}'" - - "rsync -a client {{.OUTPUT_DIR}}/" - - |- - cd "{{.OUTPUT_DIR}}/client" - PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build - - "mkdir {{.OUTPUT_DIR}}/server" - |- - cd server - rsync -a src package-lock.json package.json {{.OUTPUT_DIR}}/server/ + cd client + PATH="{{.G_NODEJS_22_BIN_DIR}}":$PATH npm run build -- \ + --output-path "{{.OUTPUT_DIR}}/client" - task: "utils:compute-checksum" vars: DATA_DIR: "{{.OUTPUT_DIR}}" diff --git a/components/clp-package-utils/clp_package_utils/general.py b/components/clp-package-utils/clp_package_utils/general.py index d1edf7d5b..4dca481b0 100644 --- a/components/clp-package-utils/clp_package_utils/general.py +++ b/components/clp-package-utils/clp_package_utils/general.py @@ -501,11 +501,11 @@ def validate_webui_config( validate_port(f"{WEBUI_COMPONENT_NAME}.port", clp_config.webui.host, clp_config.webui.port) -def validate_log_viewer_config(clp_config: CLPConfig, logs_dir: pathlib.Path): - try: - validate_path_could_be_dir(logs_dir) - except ValueError as ex: - raise ValueError(f"{LOG_VIEWER_WEBUI_COMPONENT_NAME} logs directory is invalid: {ex}") +def validate_log_viewer_webui_config(clp_config: CLPConfig, settings_json_path: pathlib.Path): + if not settings_json_path.exists(): + raise ValueError( + f"{WEBUI_COMPONENT_NAME} {settings_json_path} is not a valid path to settings.json" + ) validate_port( f"{LOG_VIEWER_WEBUI_COMPONENT_NAME}.port", diff --git a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py index 4c072752e..655c1dae1 100755 --- a/components/clp-package-utils/clp_package_utils/scripts/start_clp.py +++ b/components/clp-package-utils/clp_package_utils/scripts/start_clp.py @@ -50,7 +50,7 @@ validate_and_load_queue_credentials_file, validate_and_load_redis_credentials_file, validate_db_config, - validate_log_viewer_config, + validate_log_viewer_webui_config, validate_queue_config, validate_redis_config, validate_reducer_config, @@ -668,13 +668,13 @@ def generic_start_worker( logger.info(f"Started {component_name}.") -def update_meteor_settings( +def update_settings_object( parent_key_prefix: str, settings: Dict[str, Any], updates: Dict[str, Any], ): """ - Recursively updates the given Meteor settings object with the values from `updates`. + Recursively updates the given settings object with the values from `updates`. :param parent_key_prefix: The prefix for keys at this level in the settings dictionary. :param settings: The settings to update. @@ -686,11 +686,25 @@ def update_meteor_settings( error_msg = f"{parent_key_prefix}{key} is not a valid configuration key for the webui." raise ValueError(error_msg) if isinstance(value, dict): - update_meteor_settings(f"{parent_key_prefix}{key}.", settings[key], value) + update_settings_object(f"{parent_key_prefix}{key}.", settings[key], value) else: settings[key] = updates[key] +def read_and_update_settings_json(settings_file_path: pathlib.Path, updates: Dict[str, Any]): + """ + Reads and updates a settings JSON file. + + :param settings_file_path: + :param updates: + """ + with open(settings_file_path, "r") as settings_json_file: + settings_object = json.loads(settings_json_file.read()) + update_settings_object("", settings_object, updates) + + return settings_object + + def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts): component_name = WEBUI_COMPONENT_NAME logger.info(f"Starting {component_name}...") @@ -710,8 +724,8 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts webui_logs_dir.mkdir(exist_ok=True, parents=True) container_webui_logs_dir = pathlib.Path("/") / "var" / "log" / component_name - with open(settings_json_path, "r") as settings_json_file: - meteor_settings = json.loads(settings_json_file.read()) + + # Read and update settings.json meteor_settings_updates = { "private": { "SqlDbHost": clp_config.database.host, @@ -726,7 +740,7 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts "ClpStorageEngine": clp_config.package.storage_engine, }, } - update_meteor_settings("", meteor_settings, meteor_settings_updates) + meteor_settings = read_and_update_settings_json(settings_json_path, meteor_settings_updates) # Start container # fmt: off @@ -769,7 +783,12 @@ def start_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts logger.info(f"Started {component_name}.") -def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPDockerMounts): +def start_log_viewer_webui( + instance_id: str, + clp_config: CLPConfig, + container_clp_config: CLPConfig, + mounts: CLPDockerMounts, +): component_name = LOG_VIEWER_WEBUI_COMPONENT_NAME logger.info(f"Starting {component_name}...") @@ -777,16 +796,30 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD if container_exists(container_name): return - log_viewer_webui_logs_dir = clp_config.logs_directory / component_name - container_log_viewer_dir = CONTAINER_CLP_HOME / "var" / "www" / "log_viewer" - node_path = str(container_log_viewer_dir / "server" / "node_modules") - - validate_log_viewer_config(clp_config, log_viewer_webui_logs_dir) - - # Create directories - log_viewer_webui_logs_dir.mkdir(exist_ok=True, parents=True) + container_log_viewer_webui_dir = CONTAINER_CLP_HOME / "var" / "www" / "log_viewer_webui" + node_path = str(container_log_viewer_webui_dir / "server" / "node_modules") + settings_json_path = ( + get_clp_home() / "var" / "www" / "log_viewer_webui" / "server" / "settings.json" + ) - container_log_viewer_webui_logs_dir = pathlib.Path("/") / "var" / "log" / component_name + validate_log_viewer_webui_config(clp_config, settings_json_path) + + # Read, update, and write back settings.json + settings_json_updates = { + "SqlDbHost": clp_config.database.host, + "SqlDbPort": clp_config.database.port, + "SqlDbName": clp_config.database.name, + "SqlDbQueryJobsTableName": QUERY_JOBS_TABLE_NAME, + "MongoDbHost": clp_config.results_cache.host, + "MongoDbPort": clp_config.results_cache.port, + "MongoDbName": clp_config.results_cache.db_name, + "MongoDbIrFilesCollectionName": clp_config.results_cache.ir_collection_name, + "ClientDir": str(container_log_viewer_webui_dir / "client"), + "IrFilesDir": str(container_clp_config.ir_output.directory), + } + settings_json = read_and_update_settings_json(settings_json_path, settings_json_updates) + with open(settings_json_path, "w") as settings_json_file: + settings_json_file.write(json.dumps(settings_json)) # Start container # fmt: off @@ -797,9 +830,10 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD "--name", container_name, "--log-driver", "local", "-e", f"NODE_PATH={node_path}", - "-e", f"CLIENT_DIR={container_log_viewer_dir}/client/dist", - "-e", f"PORT={clp_config.log_viewer_webui.port}", "-e", f"HOST={clp_config.log_viewer_webui.host}", + "-e", f"PORT={clp_config.log_viewer_webui.port}", + "-e", f"CLP_DB_USER={clp_config.database.username}", + "-e", f"CLP_DB_PASS={clp_config.database.password}", "-e", f"NODE_ENV=production", "-u", f"{os.getuid()}:{os.getgid()}", ] @@ -807,9 +841,6 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD necessary_mounts = [ mounts.clp_home, mounts.ir_output_dir, - DockerMount( - DockerMountType.BIND, log_viewer_webui_logs_dir, container_log_viewer_webui_logs_dir - ), ] for mount in necessary_mounts: if mount: @@ -819,7 +850,7 @@ def start_log_viewer_webui(instance_id: str, clp_config: CLPConfig, mounts: CLPD node_cmd = [ str(CONTAINER_CLP_HOME / "bin" / "node-22"), - str(container_log_viewer_dir / "server" / "src" / "main.js"), + str(container_log_viewer_webui_dir / "server" / "src" / "main.js"), ] cmd = container_cmd + node_cmd subprocess.run(cmd, stdout=subprocess.DEVNULL, check=True) @@ -1046,7 +1077,7 @@ def main(argv): if target in (ALL_TARGET_NAME, WEBUI_COMPONENT_NAME): start_webui(instance_id, clp_config, mounts) if target in (ALL_TARGET_NAME, LOG_VIEWER_WEBUI_COMPONENT_NAME): - start_log_viewer_webui(instance_id, clp_config, mounts) + start_log_viewer_webui(instance_id, clp_config, container_clp_config, mounts) except Exception as ex: if type(ex) == ValueError: diff --git a/components/clp-py-utils/clp_py_utils/clp_config.py b/components/clp-py-utils/clp_py_utils/clp_config.py index 9485b43c2..f5a813057 100644 --- a/components/clp-py-utils/clp_py_utils/clp_config.py +++ b/components/clp-py-utils/clp_py_utils/clp_config.py @@ -393,7 +393,6 @@ def validate_logging_level(cls, field): class LogViewerWebUi(BaseModel): host: str = "localhost" port: int = 3000 - logging_level: str = "INFO" @validator("host") def validate_host(cls, field): diff --git a/components/log-viewer-webui/server/.env b/components/log-viewer-webui/server/.env index 699f2cb90..b66dc997b 100644 --- a/components/log-viewer-webui/server/.env +++ b/components/log-viewer-webui/server/.env @@ -1,3 +1,8 @@ CLIENT_DIR=../client/dist +IR_DATA_DIR=../../../build/clp-package/var/data/ir +LOG_VIEWER_DIR=../yscope-log-viewer/dist + HOST=localhost PORT=3000 +CLP_DB_USER=clp-user +CLP_DB_PASS= diff --git a/components/log-viewer-webui/server/.gitignore b/components/log-viewer-webui/server/.gitignore index d0e829eda..e19dcc6a4 100644 --- a/components/log-viewer-webui/server/.gitignore +++ b/components/log-viewer-webui/server/.gitignore @@ -1,2 +1,5 @@ + # Local development +.env.local + # Testing /.tap diff --git a/components/log-viewer-webui/server/package-lock.json b/components/log-viewer-webui/server/package-lock.json index 1066e05ef..b5ad7d428 100644 --- a/components/log-viewer-webui/server/package-lock.json +++ b/components/log-viewer-webui/server/package-lock.json @@ -9,13 +9,19 @@ "version": "0.1.0", "license": "Apache-2.0", "dependencies": { + "@fastify/mongodb": "^8.0.0", + "@fastify/mysql": "^4.3.0", "@fastify/static": "^7.0.4", + "@msgpack/msgpack": "^3.0.0-beta2", "dotenv": "^16.4.5", "fastify": "^4.28.0", + "fastify-plugin": "^4.5.1", "http-status-codes": "^2.3.0", "pino-pretty": "^11.2.1" }, "devDependencies": { + "@babel/eslint-parser": "^7.24.8", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "eslint-config-yscope": "latest", "nodemon": "^3.1.3", "tap": "^19.2.5" @@ -58,6 +64,554 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", + "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", + "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", + "dev": true, + "peer": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.9", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-module-transforms": "^7.24.9", + "@babel/helpers": "^7.24.8", + "@babel/parser": "^7.24.8", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.8.tgz", + "integrity": "sha512-nYAikI4XTGokU2QX7Jx+v4rxZKhKivaQaREZjuW3mrJrbdWJ5yUfohnoUULge+zEEaKjPYNxhoRgUKktjXtbwA==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@babel/eslint-parser/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", + "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", + "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/compat-data": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "peer": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "peer": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "peer": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", + "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz", + "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "peer": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", + "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "dev": true, + "peer": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", + "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", + "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.8", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.8", + "@babel/types": "^7.24.8", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", + "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@base2/pretty-print-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz", @@ -83,37 +637,20 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.1.tgz", - "integrity": "sha512-I238eDtOolvCuvtxrnqtlBaw0BwdQuYqK7eA6XIonicMdOOOb75mqdIzkGDUbS04+1Di007rgm9snFRNeVrOog==", + "version": "0.46.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", + "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", "dev": true, "peer": true, "dependencies": { - "@types/eslint": "^8.56.5", - "@types/estree": "^1.0.5", - "@typescript-eslint/types": "^7.2.0", "comment-parser": "1.4.1", - "esquery": "^1.5.0", + "esquery": "^1.6.0", "jsdoc-type-pratt-parser": "~4.0.0" }, "engines": { "node": ">=16" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.15.0.tgz", - "integrity": "sha512-aV1+B1+ySXbQH0pLK0rx66I3IkiZNidYobyfn0WFsdGhSXw+P3YOqeTq5GED458SfB24tg+ux3S+9g118hjlTw==", - "dev": true, - "peer": true, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -217,20 +754,25 @@ } }, "node_modules/@fastify/ajv-compiler/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@fastify/ajv-compiler/node_modules/ajv/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -257,6 +799,24 @@ "fast-deep-equal": "^3.1.3" } }, + "node_modules/@fastify/mongodb": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@fastify/mongodb/-/mongodb-8.0.0.tgz", + "integrity": "sha512-IDw/wWpdc53+Y5sPpMg+ek71HOIVuz8NoD2GlfIOcvGE/lYdrZvnFQxqJcaZtlwPZ7YflDDkIu5aNkCPWdZQ0Q==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mongodb": "^6.0.0" + } + }, + "node_modules/@fastify/mysql": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@fastify/mysql/-/mysql-4.3.0.tgz", + "integrity": "sha512-eVx5/PyMmoBWp3hTaqdvXiZdo8YnKsAx3k/8AEXgI/MjUbgcn8YrSdy8eHSpCL3YZtBhD/2vLpOXFFciyqlWjQ==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "mysql2": "^3.9.7" + } + }, "node_modules/@fastify/send": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@fastify/send/-/send-2.1.0.tgz", @@ -443,6 +1003,32 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -452,10 +1038,20 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { @@ -476,6 +1072,53 @@ "node": ">=8" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", + "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "3.0.0-beta2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.0.0-beta2.tgz", + "integrity": "sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -530,6 +1173,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/@npmcli/fs": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", @@ -543,12 +1192,13 @@ } }, "node_modules/@npmcli/git": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.7.tgz", - "integrity": "sha512-WaOVvto604d5IpdCRV2KjQu8PzkfE96d50CQGKgywXh2GxXmDeUO5EWcBC4V57uFyrNqx83+MewuJh3WTR3xPA==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.8.tgz", + "integrity": "sha512-liASfw5cqhjNW9UFd+ruwwdEf/lbOAQjLL2XY2dFW/bkJheXDYZgOyul/4gVvEV4BWkTXjYGmDqMw9uegdbJNQ==", "dev": true, "dependencies": { "@npmcli/promise-spawn": "^7.0.0", + "ini": "^4.1.3", "lru-cache": "^10.0.1", "npm-pick-manifest": "^9.0.0", "proc-log": "^4.0.0", @@ -570,6 +1220,12 @@ "node": ">=16" } }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/@npmcli/git/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -1065,9 +1721,9 @@ } }, "node_modules/@tapjs/fixture/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1076,7 +1732,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1270,9 +1926,9 @@ } }, "node_modules/@tapjs/run/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1281,7 +1937,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1404,9 +2060,9 @@ } }, "node_modules/@tapjs/test/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -1415,7 +2071,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1577,6 +2233,19 @@ "dev": true, "peer": true }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "dependencies": { + "@types/webidl-conversions": "*" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", @@ -1816,20 +2485,25 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/ajv-formats/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2152,6 +2826,14 @@ "fastq": "^1.17.1" } }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", + "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2208,6 +2890,47 @@ "node": ">=8" } }, + "node_modules/browserslist": { + "version": "4.23.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", + "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "caniuse-lite": "^1.0.30001640", + "electron-to-chromium": "^1.4.820", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bson": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz", + "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==", + "engines": { + "node": ">=16.20.1" + } + }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -2257,9 +2980,9 @@ } }, "node_modules/cacache": { - "version": "18.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", - "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", + "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", @@ -2279,6 +3002,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -2309,6 +3038,27 @@ "node": ">=6" } }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2747,6 +3497,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2806,6 +3564,13 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/electron-to-chromium": { + "version": "1.4.828", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.828.tgz", + "integrity": "sha512-QOIJiWpQJDHAVO4P58pwb133Cwee0nbvy/MV1CwzZVGpkH1RX33N3vsaWRCpR6bF63AAq366neZrRTu7Qlsbbw==", + "dev": true, + "peer": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -3275,19 +4040,19 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "48.5.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.5.2.tgz", - "integrity": "sha512-VXBJFviQz30rynlOEQ+dNWLmeopjoAgutUVrWOZwm6Ki4EVDm4XkyIqAV/Zhf7FcDr0AG0aGmRn5FxxCtAF0tA==", + "version": "48.7.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.7.0.tgz", + "integrity": "sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==", "dev": true, "peer": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.43.1", + "@es-joy/jsdoccomment": "~0.46.0", "are-docs-informative": "^0.0.2", "comment-parser": "1.4.1", "debug": "^4.3.5", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "parse-imports": "^2.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", "semver": "^7.6.2", "spdx-expression-parse": "^4.0.0", "synckit": "^0.9.0" @@ -3317,9 +4082,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.34.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.3.tgz", - "integrity": "sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==", + "version": "7.34.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", + "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", "dev": true, "peer": true, "dependencies": { @@ -3331,16 +4096,17 @@ "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.8", "object.fromentries": "^2.0.8", - "object.hasown": "^1.1.4", "object.values": "^1.2.0", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.11" + "string.prototype.matchall": "^4.0.11", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" @@ -3520,9 +4286,9 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "peer": true, "dependencies": { @@ -3537,7 +4303,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "peer": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3550,7 +4315,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "peer": true, "engines": { "node": ">=4.0" } @@ -3668,14 +4432,14 @@ } }, "node_modules/fast-json-stringify/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dependencies": { "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3698,6 +4462,11 @@ } } }, + "node_modules/fast-json-stringify/node_modules/ajv/node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -3988,6 +4757,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4036,9 +4823,9 @@ } }, "node_modules/glob": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.3.tgz", - "integrity": "sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -4050,9 +4837,6 @@ "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -4268,6 +5052,12 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4330,8 +5120,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -4440,6 +5228,15 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/ink": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/ink/-/ink-4.4.1.tgz", @@ -4538,7 +5335,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, + "devOptional": true, "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -4852,6 +5649,11 @@ "node": ">=0.10.0" } }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5061,15 +5863,12 @@ } }, "node_modules/jackspeak": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.1.tgz", - "integrity": "sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -5108,7 +5907,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true + "devOptional": true }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.0.0", @@ -5120,6 +5919,19 @@ "node": ">=12.0.0" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "peer": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5258,6 +6070,11 @@ "dev": true, "peer": true }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5271,11 +6088,11 @@ } }, "node_modules/lru-cache": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.3.1.tgz", - "integrity": "sha512-9/8QXrtbGeMB6LxwQd4x1tIMnsmUxMvIH/qWGsccz6bt9Uln3S+sgAaqfQNhbGA8ufzs2fHuP/yqapGgP9Hh2g==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", "engines": { - "node": ">=18" + "node": ">=16.14" } }, "node_modules/make-dir": { @@ -5322,6 +6139,11 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5573,12 +6395,104 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mongodb": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz", + "integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==", + "dependencies": { + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" + }, + "engines": { + "node": ">=16.20.1" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + }, + "socks": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "dependencies": { + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mysql2": { + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.3.tgz", + "integrity": "sha512-k43gmH9i79rZD4hGPdj7pDuT0UBiFjs4UzXEy1cJrV0QqcSABomoLwvejqdbcXN+Vd7gi999CVM6o9vCPKq29g==", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5596,9 +6510,9 @@ } }, "node_modules/node-gyp": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", - "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.2.0.tgz", + "integrity": "sha512-sp3FonBAaFe4aYTcFdZUn2NYkbP7xroPGYvQmP4Nl5PxamznItBnNCgjrVTKrEfQynInMsJvZrdmqUnysCJ8rw==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -5607,9 +6521,9 @@ "graceful-fs": "^4.2.6", "make-fetch-happen": "^13.0.0", "nopt": "^7.0.0", - "proc-log": "^3.0.0", + "proc-log": "^4.1.0", "semver": "^7.3.5", - "tar": "^6.1.2", + "tar": "^6.2.1", "which": "^4.0.0" }, "bin": { @@ -5628,15 +6542,6 @@ "node": ">=16" } }, - "node_modules/node-gyp/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", @@ -5652,6 +6557,13 @@ "node": "^16.13.0 || >=18.0.0" } }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "peer": true + }, "node_modules/nodemon": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", @@ -5822,9 +6734,9 @@ } }, "node_modules/npm-pick-manifest": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.1.tgz", - "integrity": "sha512-Udm1f0l2nXb3wxDpKjfohwgdFUSV50UVwzEIpDXVsbDMXVIEF81a/i0UhuQbhrPMMmdiq3+YMFLFIRVLs3hxQw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.1.0.tgz", + "integrity": "sha512-nkc+3pIIhqHVQr085X9d2JzPzLyjzQS96zbruppqC9aZRm/x8xx6xhI98gHtsfELP2bE+loHq8ZaHFHhe+NauA==", "dev": true, "dependencies": { "npm-install-checks": "^6.0.0", @@ -5956,24 +6868,6 @@ "node": ">= 0.4" } }, - "node_modules/object.hasown": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", - "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", - "dev": true, - "peer": true, - "dependencies": { - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object.values": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", @@ -6216,6 +7110,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -6226,6 +7125,13 @@ "node": ">=8" } }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "peer": true + }, "node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", @@ -6240,9 +7146,9 @@ } }, "node_modules/pino": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", - "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.3.1.tgz", + "integrity": "sha512-afSfrq/hUiW/MFmQcLEwV9Zh8Ry6MrMTOyBU53o/fc0gEl+1OZ/Fks/xQCM2nOC0C/OfDtQMnT2d8c3kpcfSzA==", "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", @@ -6736,9 +7642,9 @@ } }, "node_modules/resolve-import": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.5.tgz", - "integrity": "sha512-HXb4YqODuuXT7Icq1Z++0g2JmhgbUHSs3VT2xR83gqvAPUikYT2Xk+562KHQgiaNkbBOlPddYrDLsC44qQggzw==", + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/resolve-import/-/resolve-import-1.4.6.tgz", + "integrity": "sha512-CIw9e64QcKcCFUj9+KxUCJPy8hYofv6eVfo3U9wdhCm2E4IjvFnZ6G4/yIC4yP3f11+h6uU5b3LdS7O64LgqrA==", "dev": true, "dependencies": { "glob": "^10.3.3", @@ -6966,9 +7872,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "optional": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/scheduler": { "version": "0.23.2", @@ -6995,6 +7899,11 @@ "node": ">=10" } }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, "node_modules/set-cookie-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", @@ -7178,7 +8087,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -7188,7 +8097,7 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "dev": true, + "devOptional": true, "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -7220,6 +8129,14 @@ "atomic-sleep": "^1.0.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -7275,7 +8192,15 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true + "devOptional": true + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } }, "node_modules/ssri": { "version": "10.0.6", @@ -7455,6 +8380,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "peer": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", @@ -7598,9 +8534,9 @@ } }, "node_modules/sync-content/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -7609,16 +8545,16 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/synckit": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.0.tgz", - "integrity": "sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", "dev": true, "peer": true, "dependencies": { @@ -7845,6 +8781,16 @@ "real-require": "^0.2.0" } }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7882,6 +8828,17 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/trivial-deferred": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-2.0.0.tgz", @@ -7918,9 +8875,9 @@ } }, "node_modules/tshy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.17.0.tgz", - "integrity": "sha512-95BrHQTZCrJ3LnoGQoDCv7PtyNKyIIY9A9FPgY04IpsmV0URmlI8OWjMkQWRONUAJqJeJCij9p8REXLuv+7MXg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tshy/-/tshy-1.18.0.tgz", + "integrity": "sha512-FQudIujBazHRu7CVPHKQE9/Xq1Wc7lezxD/FCnTXx2PTcnoSN32DVpb/ZXvzV2NJBTDB3XKjqX8Cdm+2UK1DlQ==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -7982,9 +8939,9 @@ } }, "node_modules/tshy/node_modules/rimraf": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.8.tgz", - "integrity": "sha512-XSh0V2/yNhDEi8HwdIefD8MLgs4LQXPag/nEJWs3YUc3Upn+UHa1GyIkEg9xSSNt7HnkO5FjTvmcRzgf+8UZuw==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", + "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -7993,7 +8950,7 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=18" + "node": "14 >=14.20 || 16 >=16.20 || >=18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -8188,10 +9145,43 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "peer": true, + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -8270,6 +9260,26 @@ "integrity": "sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA==", "dev": true }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/components/log-viewer-webui/server/package.json b/components/log-viewer-webui/server/package.json index e7e52d521..f952b6c86 100644 --- a/components/log-viewer-webui/server/package.json +++ b/components/log-viewer-webui/server/package.json @@ -8,19 +8,25 @@ "lint:fix": "npx eslint --fix --no-eslintrc --config package.json src", "prod": "NODE_ENV=production node src/main.js", "start": "NODE_ENV=development nodemon src/main.js", - "test": "tap" + "test": "NODE_ENV=test tap" }, "author": "YScope Inc. ", "license": "Apache-2.0", "type": "module", "dependencies": { + "@fastify/mongodb": "^8.0.0", + "@fastify/mysql": "^4.3.0", "@fastify/static": "^7.0.4", + "fastify-plugin": "^4.5.1", + "@msgpack/msgpack": "^3.0.0-beta2", "dotenv": "^16.4.5", "fastify": "^4.28.0", "http-status-codes": "^2.3.0", "pino-pretty": "^11.2.1" }, "devDependencies": { + "@babel/eslint-parser": "^7.24.8", + "@babel/plugin-syntax-import-attributes": "^7.24.7", "eslint-config-yscope": "latest", "nodemon": "^3.1.3", "tap": "^19.2.5" @@ -28,6 +34,15 @@ "eslintConfig": { "extends": [ "yscope/common" - ] + ], + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "babelOptions": { + "plugins": [ + "@babel/plugin-syntax-import-attributes" + ] + } + } } } diff --git a/components/log-viewer-webui/server/settings.json b/components/log-viewer-webui/server/settings.json new file mode 100644 index 000000000..76183a879 --- /dev/null +++ b/components/log-viewer-webui/server/settings.json @@ -0,0 +1,13 @@ +{ + "SqlDbHost": "localhost", + "SqlDbPort": 3306, + "SqlDbName": "clp-db", + "SqlDbQueryJobsTableName": "query_jobs", + "MongoDbHost": "localhost", + "MongoDbPort": 27017, + "MongoDbName": "clp-query-results", + "MongoDbIrFilesCollectionName": "ir-files", + + "ClientDir": "../client/dist", + "IrFilesDir": "../../../build/clp-package/var/data/ir" +} diff --git a/components/log-viewer-webui/server/src/DbManager.js b/components/log-viewer-webui/server/src/DbManager.js new file mode 100644 index 000000000..ad71518a5 --- /dev/null +++ b/components/log-viewer-webui/server/src/DbManager.js @@ -0,0 +1,241 @@ +import fastifyPlugin from "fastify-plugin"; + +import fastifyMongo from "@fastify/mongodb"; +import fastifyMysql from "@fastify/mysql"; +import msgpack from "@msgpack/msgpack"; + +import {sleep} from "./utils.js"; + + +/** + * Interval in milliseconds for polling the completion status of a job. + */ +const JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS = 0.5; + +/** + * Enum of the `query_jobs` table's column names. + * + * @enum {string} + */ +const QUERY_JOBS_TABLE_COLUMN_NAMES = Object.freeze({ + ID: "id", + STATUS: "status", + TYPE: "type", + JOB_CONFIG: "job_config", +}); + +/* eslint-disable sort-keys */ +let enumQueryJobStatus; +/** + * Enum of job statuses, matching the `QueryJobStatus` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_STATUS = Object.freeze({ + PENDING: (enumQueryJobStatus = 0), + RUNNING: ++enumQueryJobStatus, + SUCCEEDED: ++enumQueryJobStatus, + FAILED: ++enumQueryJobStatus, + CANCELLING: ++enumQueryJobStatus, + CANCELLED: ++enumQueryJobStatus, +}); +/* eslint-enable sort-keys */ + +/** + * List of states that indicate the job is either pending or in progress. + */ +const QUERY_JOB_STATUS_WAITING_STATES = Object.freeze([ + QUERY_JOB_STATUS.PENDING, + QUERY_JOB_STATUS.RUNNING, + QUERY_JOB_STATUS.CANCELLING, +]); + +/* eslint-disable sort-keys */ +let enumQueryType; +/** + * Enum of job types, matching the `QueryJobType` class in + * `job_orchestration.query_scheduler.constants`. + * + * @enum {number} + */ +const QUERY_JOB_TYPE = Object.freeze({ + SEARCH_OR_AGGREGATION: (enumQueryType = 0), + EXTRACT_IR: ++enumQueryType, +}); +/* eslint-enable sort-keys */ + +/** + * Class to manage connections to the jobs database (MySQL) and results cache (MongoDB). + */ +class DbManager { + /** + * @type {import("fastify").FastifyInstance | + * {mysql: import("@fastify/mysql").MySQLPromisePool} | + * {mongo: import("@fastify/mongodb").FastifyMongoObject}} + */ + #fastify; + + /** + * @type {import("@fastify/mysql").PromisePool} + */ + #mysqlConnectionPool; + + /** + * @type {import("mongodb").Collection} + */ + #irFilesCollection; + + #queryJobsTableName; + + /** + * @param {import("fastify").FastifyInstance} app + * @param {object} dbConfig + * @param {object} dbConfig.mysqlConfig + * @param {object} dbConfig.mongoConfig + */ + constructor (app, dbConfig) { + this.#fastify = app; + this.#initMySql(dbConfig.mysqlConfig); + this.#initMongo(dbConfig.mongoConfig); + } + + /** + * Submits an IR extraction job to the scheduler and waits for it to finish. + * + * @param {object} jobConfig + * @return {Promise} The ID of the job or null if an error occurred. + */ + async submitAndWaitForExtractIrJob (jobConfig) { + let jobId; + try { + const [result] = await this.#mysqlConnectionPool.query( + `INSERT INTO ${this.#queryJobsTableName} (job_config, type) + VALUES (?, ?)`, + [ + Buffer.from(msgpack.encode(jobConfig)), + QUERY_JOB_TYPE.EXTRACT_IR, + ] + ); + + ({insertId: jobId} = result); + await this.#awaitJobCompletion(jobId); + } catch (e) { + this.#fastify.log.error(e); + + return null; + } + + return jobId; + } + + /** + * Gets the metadata for an IR file extracted from part of an original file, where the original + * file has the given ID and the extracted part contains the given message index. + * + * @param {string} origFileId + * @param {number} msgIdx + * @return {Promise} A promise that resolves to the extracted IR file's metadata. + */ + async getExtractedIrFileMetadata (origFileId, msgIdx) { + return await this.#irFilesCollection.findOne({ + orig_file_id: origFileId, + begin_msg_ix: {$lte: msgIdx}, + end_msg_ix: {$gt: msgIdx}, + }); + } + + /** + * Initializes the MySQL plugin. + * + * @param {object} config + * @param {string} config.user + * @param {string} config.password + * @param {string} config.host + * @param {number} config.port + * @param {string} config.database + * @param {string} config.queryJobsTableName + */ + #initMySql (config) { + this.#fastify.register(fastifyMysql, { + promise: true, + connectionString: `mysql://${config.user}:${config.password}@${config.host}:` + + `${config.port}/${config.database}`, + }).after(async (err) => { + if (err) { + throw err; + } + this.#mysqlConnectionPool = this.#fastify.mysql.pool; + this.#queryJobsTableName = config.queryJobsTableName; + }); + } + + /** + * Initializes the MongoDB plugin. + * + * @param {object} config + * @param {string} config.host + * @param {number} config.port + * @param {string} config.database + * @param {string} config.irFilesCollectionName + */ + #initMongo (config) { + this.#fastify.register(fastifyMongo, { + forceClose: true, + url: `mongodb://${config.host}:${config.port}/${config.database}`, + }).after((err) => { + if (err) { + throw err; + } + this.#irFilesCollection = + this.#fastify.mongo.db.collection(config.irFilesCollectionName); + }); + } + + /** + * Waits for the job with the given ID to finish. + * + * @param {number} jobId + * @throws {Error} If there's an error querying the job's status, the job is not found in the + * database, the job was cancelled, or it exited with an unexpected status. + */ + async #awaitJobCompletion (jobId) { + while (true) { + let rows; + try { + const [queryRows] = await this.#mysqlConnectionPool.query( + ` + SELECT ${QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS} + FROM ${this.#queryJobsTableName} + WHERE ${QUERY_JOBS_TABLE_COLUMN_NAMES.ID} = ? + `, + jobId, + ); + + rows = queryRows; + } catch (e) { + throw new Error(`Failed to query status for job ${jobId} - ${e}`); + } + if (0 === rows.length) { + throw new Error(`Job ${jobId} not found in database.`); + } + const status = rows[0][QUERY_JOBS_TABLE_COLUMN_NAMES.STATUS]; + + if (false === QUERY_JOB_STATUS_WAITING_STATES.includes(status)) { + if (QUERY_JOB_STATUS.CANCELLED === status) { + throw new Error(`Job ${jobId} was cancelled.`); + } else if (QUERY_JOB_STATUS.SUCCEEDED !== status) { + throw new Error(`Job ${jobId} exited with unexpected status=${status}: ` + + `${Object.keys(QUERY_JOB_STATUS)[status]}.`); + } + break; + } + + await sleep(JOB_COMPLETION_STATUS_POLL_INTERVAL_MILLIS); + } + } +} + +export default fastifyPlugin(async (app, options) => { + await app.decorate("dbManager", new DbManager(app, options)); +}); diff --git a/components/log-viewer-webui/server/src/app.js b/components/log-viewer-webui/server/src/app.js index d67b7136a..28c7fdfe5 100644 --- a/components/log-viewer-webui/server/src/app.js +++ b/components/log-viewer-webui/server/src/app.js @@ -1,36 +1,79 @@ import fastify from "fastify"; import * as path from "node:path"; import process from "node:process"; +import {fileURLToPath} from "node:url"; import {fastifyStatic} from "@fastify/static"; -import exampleRoutes from "./routes/examples.js"; +import settings from "../settings.json" with {type: "json"}; +import DbManager from "./DbManager.js"; +import exampleRoutes from "./routes/example.js"; +import queryRoutes from "./routes/query.js"; /** * Creates the Fastify app with the given options. * - * @param {string} clientDir Absolute path to the client directory to serve when in running in a - * production environment. - * @param {import("fastify").FastifyServerOptions} fastifyOptions + * @param {object} props + * @param {import("fastify").FastifyServerOptions} props.fastifyOptions + * @param {string} props.sqlDbUser + * @param {string} props.sqlDbPass * @return {Promise} */ -const app = async (clientDir, fastifyOptions = {}) => { +const app = async ({ + fastifyOptions, + sqlDbUser, + sqlDbPass, +}) => { const server = fastify(fastifyOptions); + const filename = fileURLToPath(import.meta.url); + const dirname = path.dirname(filename); + const parentDirname = path.resolve(dirname, ".."); + + if ("test" !== process.env.NODE_ENV) { + let irFilesDir = settings.IrFilesDir; + if (false === path.isAbsolute(irFilesDir)) { + irFilesDir = path.resolve(parentDirname, irFilesDir); + } + await server.register(fastifyStatic, { + prefix: "/ir", + root: irFilesDir, + }); + + await server.register(DbManager, { + mysqlConfig: { + database: settings.SqlDbName, + host: settings.SqlDbHost, + password: sqlDbPass, + port: settings.SqlDbPort, + queryJobsTableName: settings.SqlDbQueryJobsTableName, + user: sqlDbUser, + }, + mongoConfig: { + database: settings.MongoDbName, + host: settings.MongoDbHost, + irFilesCollectionName: settings.MongoDbIrFilesCollectionName, + port: settings.MongoDbPort, + }, + }); + } if ("production" === process.env.NODE_ENV) { // In the development environment, we expect the client to use a separate webserver that // supports live reloading. - if (false === path.isAbsolute(clientDir)) { + if (false === path.isAbsolute(settings.ClientDir)) { throw new Error("`clientDir` must be an absolute path."); } await server.register(fastifyStatic, { prefix: "/", - root: clientDir, + root: settings.ClientDir, + decorateReply: false, }); } + await server.register(exampleRoutes); + await server.register(queryRoutes); return server; }; diff --git a/components/log-viewer-webui/server/src/app.test.js b/components/log-viewer-webui/server/src/app.test.js index 1215c795f..3a19208f7 100644 --- a/components/log-viewer-webui/server/src/app.test.js +++ b/components/log-viewer-webui/server/src/app.test.js @@ -5,12 +5,12 @@ import app from "./app.js"; test("Tests the example routes", async (t) => { - const server = await app(); + const server = await app({}); t.teardown(() => server.close()); let resp = await server.inject({ method: "GET", - url: "/examples/get/Alice", + url: "/example/get/Alice", }); t.equal(resp.statusCode, httpStatusCodes.OK); @@ -18,9 +18,12 @@ test("Tests the example routes", async (t) => { resp = await server.inject({ method: "POST", - url: "/examples/post", + url: "/example/post", payload: {name: "Bob"}, }); t.equal(resp.statusCode, httpStatusCodes.OK); t.match(JSON.parse(resp.body), {msg: String}); }); + +// eslint-disable-next-line no-warning-comments +// TODO: Add tests for `query` routes. diff --git a/components/log-viewer-webui/server/src/main.js b/components/log-viewer-webui/server/src/main.js index f1507d3ef..c3b7ef5cf 100644 --- a/components/log-viewer-webui/server/src/main.js +++ b/components/log-viewer-webui/server/src/main.js @@ -1,5 +1,4 @@ import dotenv from "dotenv"; -import * as path from "node:path"; import process from "node:process"; import app from "./app.js"; @@ -8,20 +7,25 @@ import app from "./app.js"; /** * Parses environment variables into config values for the application. * - * @return {{CLIENT_DIR: string, HOST: string, PORT: string}} + * @return {{CLP_DB_USER: string, CLP_DB_PASS: string, HOST: string, PORT: string}} * @throws {Error} if any required environment variable is undefined. */ const parseEnvVars = () => { dotenv.config({ - path: ".env", + path: [ + ".env.local", + ".env", + ], }); + /* eslint-disable sort-keys */ const { - CLIENT_DIR, HOST, PORT, + CLP_DB_USER, CLP_DB_PASS, HOST, PORT, } = process.env; const envVars = { - CLIENT_DIR, HOST, PORT, + CLP_DB_USER, CLP_DB_PASS, HOST, PORT, }; + /* eslint-enable sort-keys */ // Check for mandatory environment variables for (const [key, value] of Object.entries(envVars)) { @@ -48,8 +52,12 @@ const main = async () => { }; const envVars = parseEnvVars(); - const server = await app(path.resolve(envVars.CLIENT_DIR), { - logger: envToLogger[process.env.NODE_ENV] ?? true, + const server = await app({ + fastifyOptions: { + logger: envToLogger[process.env.NODE_ENV] ?? true, + }, + sqlDbPass: envVars.CLP_DB_PASS, + sqlDbUser: envVars.CLP_DB_USER, }); try { diff --git a/components/log-viewer-webui/server/src/routes/examples.js b/components/log-viewer-webui/server/src/routes/example.js similarity index 75% rename from components/log-viewer-webui/server/src/routes/examples.js rename to components/log-viewer-webui/server/src/routes/example.js index 8074f4a29..fb4aa31c7 100644 --- a/components/log-viewer-webui/server/src/routes/examples.js +++ b/components/log-viewer-webui/server/src/routes/example.js @@ -6,11 +6,11 @@ * @return {Promise} */ const routes = async (fastify, options) => { - fastify.get("/examples/get/:name", async (req, resp) => { + fastify.get("/example/get/:name", async (req, resp) => { return {msg: `Hello, ${req.params.name}!`}; }); - fastify.post("/examples/post", async (req, resp) => { + fastify.post("/example/post", async (req, resp) => { return {msg: `Goodbye, ${req.body.name}!`}; }); }; diff --git a/components/log-viewer-webui/server/src/routes/query.js b/components/log-viewer-webui/server/src/routes/query.js new file mode 100644 index 000000000..2f790ebc3 --- /dev/null +++ b/components/log-viewer-webui/server/src/routes/query.js @@ -0,0 +1,40 @@ +/** + * Creates query routes. + * + * @param {import("fastify").FastifyInstance | {dbManager: DbManager}} fastify + * @param {import("fastify").FastifyPluginOptions} options + * @return {Promise} + */ +const routes = async (fastify, options) => { + fastify.post("/query/extract-ir", async (req, resp) => { + const {orig_file_id: origFileId, msg_ix: msgIdx} = req.body; + const sanitizedMsgIdx = Number(msgIdx); + + let irMetadata = + await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + + if (null === irMetadata) { + const extractResult = await fastify.dbManager.submitAndWaitForExtractIrJob({ + file_split_id: null, + msg_ix: sanitizedMsgIdx, + orig_file_id: origFileId, + // eslint-disable-next-line no-magic-numbers + target_uncompressed_size: 128 * 1024 * 1024, + }); + + if (null === extractResult) { + const err = new Error("Unable to extract IR for file with " + + `orig_file_id=${origFileId} at msg_ix=${sanitizedMsgIdx}`); + + err.statusCode = 400; + throw err; + } + irMetadata = + await fastify.dbManager.getExtractedIrFileMetadata(origFileId, sanitizedMsgIdx); + } + + return irMetadata; + }); +}; + +export default routes; diff --git a/components/log-viewer-webui/server/src/utils.js b/components/log-viewer-webui/server/src/utils.js new file mode 100644 index 000000000..580ea76f8 --- /dev/null +++ b/components/log-viewer-webui/server/src/utils.js @@ -0,0 +1,13 @@ +const MILLIS_PER_SECOND = 1000; + +/** + * Creates a promise that resolves after a specified number of seconds. + * + * @param {number} seconds Number of seconds to wait before resolving the promise. + * @return {Promise} A promise that resolves after the specified delay. + */ +const sleep = (seconds) => new Promise((resolve) => { + setTimeout(resolve, seconds * MILLIS_PER_SECOND); +}); + +export {sleep}; diff --git a/components/package-template/src/etc/clp-config.yml b/components/package-template/src/etc/clp-config.yml index ce626afa3..cb66f40cd 100644 --- a/components/package-template/src/etc/clp-config.yml +++ b/components/package-template/src/etc/clp-config.yml @@ -60,7 +60,7 @@ # port: 4000 # logging_level: "INFO" # -#log_viewer_webui +#log_viewer_webui: # host: "localhost" # port: 3000 # diff --git a/lint-tasks.yml b/lint-tasks.yml index a7de6e49e..9f21cd8ed 100644 --- a/lint-tasks.yml +++ b/lint-tasks.yml @@ -2,7 +2,6 @@ version: "3" vars: G_LINT_VENV_DIR: "{{.G_BUILD_DIR}}/lint-venv" - G_LOG_VIEWER_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/log-viewer-webui" G_WEBUI_SRC_DIR: "{{.ROOT_DIR}}/components/webui" tasks: @@ -51,12 +50,13 @@ tasks: - "{{.G_BUILD_DIR}}/lint#linter-node-modules.md5" - "{{.G_BUILD_DIR}}/log-viewer-webui-node-modules.md5" - "{{.G_BUILD_DIR}}/webui-node-modules.md5" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/package.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.css" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/**/*.jsx" - - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/package.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/client/src/webpack.config.js" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/package.json" + - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/settings.json" - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/*.js" - - "{{.G_LOG_VIEWER_WEBUI_SRC_DIR}}/server/src/**/package.json" - "{{.G_WEBUI_SRC_DIR}}/client/**/*.js" - "{{.G_WEBUI_SRC_DIR}}/client/**/*.jsx" - "{{.G_WEBUI_SRC_DIR}}/imports/**/*.js"