From 16e7beb51b294837e2d8a26cfd0d381374d74c0a Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 30 Oct 2025 16:17:54 -0500 Subject: [PATCH 01/40] Python remote file source plugin (#DH-19715) --- .gitignore | 1 + package-lock.json | 1274 ++++++++++++++--- plugins/python-remote-file-source/.gitignore | 10 + plugins/python-remote-file-source/LICENSE | 202 +++ plugins/python-remote-file-source/README.md | 12 + .../README_TEMPLATE.md | 213 +++ .../_assets/plugin_map.png | Bin 0 -> 52557 bytes .../_assets/plugin_settings.png | Bin 0 -> 34460 bytes .../python-remote-file-source/docs/DESIGN.md | 57 + .../plugin_builder.py | 411 ++++++ .../python-remote-file-source/pyproject.toml | 3 + .../requirements.txt | 5 + plugins/python-remote-file-source/setup.cfg | 27 + plugins/python-remote-file-source/setup.py | 12 + .../python_remote_file_source/.gitignore | 2 + .../python_remote_file_source/__init__.py | 5 + .../python_remote_file_source/json_rpc.py | 52 + .../python_remote_file_source/logger.py | 15 + .../message_stream.py | 183 +++ .../module_loader.py | 91 ++ .../plugin_object.py | 70 + .../python_remote_file_source/plugin_type.py | 60 + .../python_remote_file_source/register.py | 23 + .../python_remote_file_source/types.py | 63 + .../src/js/.eslintrc.js | 13 + .../src/js/.gitignore | 5 + .../python-remote-file-source/src/js/.nvmrc | 1 + .../src/js/package.json | 45 + .../js/src/PythonRemoteFileSourcePlugin.ts | 20 + .../src/PythonRemoteFileSourcePluginView.tsx | 108 ++ .../src/js/src/index.ts | 3 + .../src/js/src/vite-env.d.ts | 1 + .../src/js/tsconfig.json | 13 + .../src/js/vite.config.js | 33 + 34 files changed, 2824 insertions(+), 209 deletions(-) create mode 100644 plugins/python-remote-file-source/.gitignore create mode 100644 plugins/python-remote-file-source/LICENSE create mode 100644 plugins/python-remote-file-source/README.md create mode 100644 plugins/python-remote-file-source/README_TEMPLATE.md create mode 100644 plugins/python-remote-file-source/_assets/plugin_map.png create mode 100644 plugins/python-remote-file-source/_assets/plugin_settings.png create mode 100644 plugins/python-remote-file-source/docs/DESIGN.md create mode 100644 plugins/python-remote-file-source/plugin_builder.py create mode 100644 plugins/python-remote-file-source/pyproject.toml create mode 100644 plugins/python-remote-file-source/requirements.txt create mode 100644 plugins/python-remote-file-source/setup.cfg create mode 100644 plugins/python-remote-file-source/setup.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/.gitignore create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/__init__.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/register.py create mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py create mode 100644 plugins/python-remote-file-source/src/js/.eslintrc.js create mode 100644 plugins/python-remote-file-source/src/js/.gitignore create mode 100644 plugins/python-remote-file-source/src/js/.nvmrc create mode 100644 plugins/python-remote-file-source/src/js/package.json create mode 100644 plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts create mode 100644 plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx create mode 100644 plugins/python-remote-file-source/src/js/src/index.ts create mode 100644 plugins/python-remote-file-source/src/js/src/vite-env.d.ts create mode 100644 plugins/python-remote-file-source/src/js/tsconfig.json create mode 100644 plugins/python-remote-file-source/src/js/vite.config.js diff --git a/.gitignore b/.gitignore index 39de105b0..474e837b6 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # because they are built by the plugin builder. node_modules +.DS_Store .vscode/* !.vscode/settings.json !.vscode/tasks.json diff --git a/package-lock.json b/package-lock.json index 74bad86a4..ba72eb24b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2107,13 +2107,6 @@ "redux": "^4.2.0" } }, - "node_modules/@deephaven/auth-plugins/node_modules/redux-thunk": { - "version": "2.4.1", - "license": "MIT", - "peerDependencies": { - "redux": "^4" - } - }, "node_modules/@deephaven/babel-preset": { "version": "0.72.0", "dev": true, @@ -3401,13 +3394,6 @@ "redux": "^4.2.0" } }, - "node_modules/@deephaven/dashboard/node_modules/redux-thunk": { - "version": "2.4.1", - "license": "MIT", - "peerDependencies": { - "redux": "^4" - } - }, "node_modules/@deephaven/eslint-config": { "version": "0.72.0", "dev": true, @@ -15424,6 +15410,10 @@ "dev": true, "license": "MIT" }, + "node_modules/deephaven-python-remote-file-source-plugin": { + "resolved": "plugins/python-remote-file-source/src/js", + "link": true + }, "node_modules/deepmerge": { "version": "4.3.1", "dev": true, @@ -31303,13 +31293,17 @@ "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.3.9.tgz", "integrity": "sha512-drcRiJVencliC8LnRwk4MmeQDNNBg5GzmOoLFihO3/k0CUK0VF/N+2nc7iFozwaNG0btSB9vAhYuJLjqHMtRrQ==" }, - "plugins/ag-grid/src/js/node_modules/redux-thunk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "license": "MIT", - "peerDependencies": { - "redux": "^4" + "plugins/ag-grid/src/js/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" } }, "plugins/auth-keycloak/src/js": { @@ -31999,11 +31993,16 @@ "node": ">=16" } }, - "plugins/matplotlib/src/js/node_modules/redux-thunk": { - "version": "2.4.1", - "license": "MIT", - "peerDependencies": { - "redux": "^4" + "plugins/matplotlib/src/js/node_modules/typescript": { + "version": "4.9.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" } }, "plugins/pivot/src/js": { @@ -34326,14 +34325,6 @@ "node": ">=18.0.0" } }, - "plugins/plotly-express/src/js/node_modules/redux-thunk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "peerDependencies": { - "redux": "^4" - } - }, "plugins/plotly-express/src/js/node_modules/rehype-mathjax": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/rehype-mathjax/-/rehype-mathjax-4.0.3.tgz", @@ -34375,31 +34366,27 @@ "url": "https://github.com/sponsors/wooorm" } }, - "plugins/simple-pivot/src/js": { - "name": "@deephaven/js-plugin-simple-pivot", - "version": "0.0.3-dev.2", + "plugins/python-remote-file-source/src/js": { + "name": "deephaven-python-remote-file-source-plugin", + "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@deephaven/components": "^0.85.27", - "@deephaven/dashboard": "^0.85.28", - "@deephaven/grid": "^0.85.28", + "@deephaven/components": "^0.85.0", + "@deephaven/dashboard": "^0.85.0", "@deephaven/icons": "^0.85.0", - "@deephaven/iris-grid": "^0.85.28", - "@deephaven/jsapi-bootstrap": "^0.85.27", - "@deephaven/jsapi-utils": "^0.85.20", - "@deephaven/log": "^0.85.19", - "@deephaven/plugin": "^0.85.28", - "@deephaven/utils": "^0.85.20", - "memoize-one": "^5.1.1", - "nanoid": "^5.1.5" + "@deephaven/jsapi-bootstrap": "^0.85.0", + "@deephaven/jsapi-types": "1.0.0-dev0.35.2", + "@deephaven/log": "^0.85.0", + "@deephaven/plugin": "^0.85.0", + "@fortawesome/react-fontawesome": "^0.2.0" }, "devDependencies": { - "@deephaven/jsapi-types": "^1.0.0-dev0.35.2", "@deephaven/tsconfig": "^0.72.0", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@vitejs/plugin-react-swc": "^3.0.0", "react": "^17.0.2", + "typescript": "^4.5.4", "vite": "~4.1.4" }, "peerDependencies": { @@ -34407,16 +34394,16 @@ "react-dom": "^17.0.2" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/components": { - "version": "0.85.27", - "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-0.85.27.tgz", - "integrity": "sha512-ndzIUbL8mgHSi8LOjT7gNXC+kfXh+PTj9XWV4qK30FwteW5Ff/0C6Bo49lnJpTiqttBvn1tipyGc6nZ6VOmdDQ==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/components": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-0.85.35.tgz", + "integrity": "sha512-KDPy/yU3r/45xLzM4E7PG5bSA7ufPoP29sDDWfajDj/v9LLNJpFSVoeMT9PqgI+9KEWdkZTAY4VfL2FDkCfaTg==", "dependencies": { "@adobe/react-spectrum": "3.38.0", "@deephaven/icons": "^0.85.0", "@deephaven/log": "^0.85.19", - "@deephaven/react-hooks": "^0.85.23", - "@deephaven/utils": "^0.85.20", + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/utils": "^0.85.35", "@fortawesome/fontawesome-svg-core": "^6.2.1", "@fortawesome/react-fontawesome": "^0.2.0", "@internationalized/date": "^3.5.5", @@ -34450,7 +34437,7 @@ "react-dom": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/components/node_modules/@adobe/react-spectrum": { + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/components/node_modules/@adobe/react-spectrum": { "version": "3.38.0", "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", @@ -34522,14 +34509,14 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/components/node_modules/@deephaven/react-hooks": { - "version": "0.85.23", - "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", - "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/components/node_modules/@deephaven/react-hooks": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.35.tgz", + "integrity": "sha512-eOip5/TJMw1Yc8dKc54RlA6fesvgUZfwrwE0BWOerQTeRRVHFX4f1oRbAARpOEEsasWeVwpQlO20/wdShj71eg==", "dependencies": { "@adobe/react-spectrum": "3.38.0", "@deephaven/log": "^0.85.19", - "@deephaven/utils": "^0.85.20", + "@deephaven/utils": "^0.85.35", "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1", "nanoid": "^5.0.7" @@ -34541,17 +34528,17 @@ "react": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard": { - "version": "0.85.28", - "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-0.85.28.tgz", - "integrity": "sha512-NQ0DKmWJa4M4T/dQygVjKxQ8ixD2tHkU5mWhBbW1LZPGmov1OGK+QPMqa1IPW2no69DA2jIqyAEpZBp9uU7dig==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/dashboard": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-0.85.35.tgz", + "integrity": "sha512-yN4LVp8z/Lv/Di5Ui8NV/rSqGOdNplJ1i8nCPi2auO9mPkD5K7mdhdjYddc61cAoc/1xXiZ61jpjggylzLAmSQ==", "dependencies": { - "@deephaven/components": "^0.85.27", - "@deephaven/golden-layout": "^0.85.27", + "@deephaven/components": "^0.85.35", + "@deephaven/golden-layout": "^0.85.35", "@deephaven/log": "^0.85.19", - "@deephaven/react-hooks": "^0.85.23", - "@deephaven/redux": "^0.85.28", - "@deephaven/utils": "^0.85.20", + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/redux": "^0.85.35", + "@deephaven/utils": "^0.85.35", "fast-deep-equal": "^3.1.3", "lodash.ismatch": "^4.1.1", "lodash.throttle": "^4.1.1", @@ -34568,12 +34555,12 @@ "react-redux": "^7.2.4" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/golden-layout": { - "version": "0.85.27", - "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-0.85.27.tgz", - "integrity": "sha512-b4T9m3G1XLtu6Iy1/sINLzR6EUZM1hmdh/nAOZlKrR731IU2pp2xiilpc6YQ2WU2Ur8JcOFKufAk/6S3wZGU7A==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/golden-layout": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-0.85.35.tgz", + "integrity": "sha512-oIF3gqfK2SVV5U/6R1Pcb/NK5XWQ5WjdFXiq+As2RGHVWO/YveaEZhY9P5/JYu0cjHETRh+mcoa8J2Sd6YpaMg==", "dependencies": { - "@deephaven/components": "^0.85.27", + "@deephaven/components": "^0.85.35", "jquery": "^3.6.0", "nanoid": "^5.0.7" }, @@ -34582,14 +34569,14 @@ "react-dom": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks": { - "version": "0.85.23", - "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", - "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.35.tgz", + "integrity": "sha512-eOip5/TJMw1Yc8dKc54RlA6fesvgUZfwrwE0BWOerQTeRRVHFX4f1oRbAARpOEEsasWeVwpQlO20/wdShj71eg==", "dependencies": { "@adobe/react-spectrum": "3.38.0", "@deephaven/log": "^0.85.19", - "@deephaven/utils": "^0.85.20", + "@deephaven/utils": "^0.85.35", "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1", "nanoid": "^5.0.7" @@ -34601,7 +34588,7 @@ "react": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { "version": "3.38.0", "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", @@ -34673,29 +34660,7 @@ "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/grid": { - "version": "0.85.28", - "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-0.85.28.tgz", - "integrity": "sha512-laOvYZh+mMx3sJoA6e0SwFYCYBHuJiH09/1Wk202kfvSISFsQE0jauV7JTUhgOqSMFH8lrvQKK3wbZ0T21TChA==", - "dependencies": { - "@deephaven/utils": "^0.85.20", - "classnames": "^2.3.1", - "color-convert": "^2.0.1", - "event-target-shim": "^6.0.2", - "linkifyjs": "^4.1.0", - "lodash.clamp": "^4.0.3", - "memoize-one": "^5.1.1", - "memoizee": "^0.4.15", - "prop-types": "^15.7.2" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/icons": { + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/icons": { "version": "0.85.0", "resolved": "https://registry.npmjs.org/@deephaven/icons/-/icons-0.85.0.tgz", "integrity": "sha512-8G77T/RPLs+SRdxWJJmOAFV0cS14U63L7hwJ8aqhMQmQkNqTqeDKrPXugXpOGN4iw3rkN05UPgV6ypS9XtbEgA==", @@ -34707,101 +34672,16 @@ "@fortawesome/react-fontawesome": "^0.2.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid": { - "version": "0.85.28", - "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-0.85.28.tgz", - "integrity": "sha512-hURNxPEVIl+NnYBQ03UqNDVeCRIlrBYJJPvUoFqlZAGjNpIwcPLAxCNocs6ZxQYuYNNgU9FaeTWeE2Wwg7ARdQ==", - "dependencies": { - "@deephaven/components": "^0.85.27", - "@deephaven/console": "^0.85.27", - "@deephaven/filters": "^0.85.0", - "@deephaven/grid": "^0.85.28", - "@deephaven/icons": "^0.85.0", - "@deephaven/jsapi-components": "^0.85.27", - "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", - "@deephaven/jsapi-utils": "^0.85.20", - "@deephaven/log": "^0.85.19", - "@deephaven/react-hooks": "^0.85.23", - "@deephaven/storage": "^0.85.19", - "@deephaven/utils": "^0.85.20", - "@dnd-kit/core": "^6.1.0", - "@dnd-kit/sortable": "^7.0.2", - "@dnd-kit/utilities": "^3.2.2", - "@fortawesome/react-fontawesome": "^0.2.0", - "classnames": "^2.3.1", - "fast-deep-equal": "^3.1.3", - "lodash.clamp": "^4.0.3", - "lodash.debounce": "^4.0.8", - "lodash.throttle": "^4.1.1", - "memoize-one": "^5.1.1", - "memoizee": "^0.4.15", - "monaco-editor": "^0.41.0", - "nanoid": "^5.0.7", - "prop-types": "^15.7.2", - "react-beautiful-dnd": "^13.1.0", - "react-transition-group": "^4.4.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console": { - "version": "0.85.27", - "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-0.85.27.tgz", - "integrity": "sha512-UhIW7j8z5X6sY/AfUovovY/YJjHDQi/uxsb1TOCmoJSm/pQL93Mxj6XqwwaDFBMf3JGeFmWtjC20w56Y2NJ4YA==", - "dependencies": { - "@deephaven/chart": "^0.85.27", - "@deephaven/components": "^0.85.27", - "@deephaven/icons": "^0.85.0", - "@deephaven/jsapi-bootstrap": "^0.85.27", - "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", - "@deephaven/log": "^0.85.19", - "@deephaven/react-hooks": "^0.85.23", - "@deephaven/storage": "^0.85.19", - "@deephaven/utils": "^0.85.20", - "@fortawesome/react-fontawesome": "^0.2.0", - "classnames": "^2.3.1", - "linkifyjs": "^4.1.0", - "lodash.debounce": "^4.0.8", - "lodash.throttle": "^4.1.1", - "memoize-one": "^5.1.1", - "memoizee": "^0.4.15", - "monaco-editor": "^0.41.0", - "nanoid": "^5.0.7", - "papaparse": "5.3.2", - "popper.js": "^1.16.1", - "prop-types": "^15.7.2", - "shell-quote": "^1.7.2" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/jsapi-components": { - "version": "0.85.27", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-0.85.27.tgz", - "integrity": "sha512-ZABrMxL0bVYMTLs14lwD/KcJL5ZEAsV8oVkdLwhg+eAA1hM3z1l2IWYa+CkCFkiAas1iqFnhk+o0Xry48n8JfQ==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-bootstrap/-/jsapi-bootstrap-0.85.35.tgz", + "integrity": "sha512-hVXMVuWNecore/AJHZdlZQrubtq60NFZ+CdWQQaUVMu5Pf1nCxFAPJ7YVzhTYyg6Pwl2KbfPYZCX4RkoN8CaYQ==", "dependencies": { - "@deephaven/components": "^0.85.27", - "@deephaven/jsapi-bootstrap": "^0.85.27", - "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", - "@deephaven/jsapi-utils": "^0.85.20", + "@deephaven/components": "^0.85.35", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", "@deephaven/log": "^0.85.19", - "@deephaven/react-hooks": "^0.85.23", - "@deephaven/utils": "^0.85.20", - "@types/js-cookie": "^3.0.3", - "classnames": "^2.3.2", - "js-cookie": "^3.0.5", - "lodash.debounce": "^4.0.8", - "prop-types": "^15.8.1" + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/utils": "^0.85.35" }, "engines": { "node": ">=16" @@ -34810,14 +34690,19 @@ "react": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/react-hooks": { - "version": "0.85.23", - "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", - "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", + "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/react-hooks": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.35.tgz", + "integrity": "sha512-eOip5/TJMw1Yc8dKc54RlA6fesvgUZfwrwE0BWOerQTeRRVHFX4f1oRbAARpOEEsasWeVwpQlO20/wdShj71eg==", "dependencies": { "@adobe/react-spectrum": "3.38.0", "@deephaven/log": "^0.85.19", - "@deephaven/utils": "^0.85.20", + "@deephaven/utils": "^0.85.35", "lodash.debounce": "^4.0.8", "lodash.throttle": "^4.1.1", "nanoid": "^5.0.7" @@ -34829,7 +34714,974 @@ "react": ">=16.8.0" } }, - "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", + "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", + "dependencies": { + "@internationalized/string": "^3.2.5", + "@react-aria/i18n": "^3.12.4", + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.26.0", + "@react-aria/visually-hidden": "^3.8.18", + "@react-spectrum/accordion": "^3.0.0", + "@react-spectrum/actionbar": "^3.6.2", + "@react-spectrum/actiongroup": "^3.10.10", + "@react-spectrum/avatar": "^3.0.17", + "@react-spectrum/badge": "^3.1.18", + "@react-spectrum/breadcrumbs": "^3.9.12", + "@react-spectrum/button": "^3.16.9", + "@react-spectrum/buttongroup": "^3.6.17", + "@react-spectrum/calendar": "^3.5.0", + "@react-spectrum/checkbox": "^3.9.11", + "@react-spectrum/color": "^3.0.2", + "@react-spectrum/combobox": "^3.14.0", + "@react-spectrum/contextualhelp": "^3.6.16", + "@react-spectrum/datepicker": "^3.11.0", + "@react-spectrum/dialog": "^3.8.16", + "@react-spectrum/divider": "^3.5.18", + "@react-spectrum/dnd": "^3.5.0", + "@react-spectrum/dropzone": "^3.0.6", + "@react-spectrum/filetrigger": "^3.0.6", + "@react-spectrum/form": "^3.7.10", + "@react-spectrum/icon": "^3.8.0", + "@react-spectrum/illustratedmessage": "^3.5.5", + "@react-spectrum/image": "^3.5.6", + "@react-spectrum/inlinealert": "^3.2.10", + "@react-spectrum/labeledvalue": "^3.1.18", + "@react-spectrum/layout": "^3.6.10", + "@react-spectrum/link": "^3.6.12", + "@react-spectrum/list": "^3.9.0", + "@react-spectrum/listbox": "^3.14.0", + "@react-spectrum/menu": "^3.21.0", + "@react-spectrum/meter": "^3.5.5", + "@react-spectrum/numberfield": "^3.9.8", + "@react-spectrum/overlays": "^5.7.0", + "@react-spectrum/picker": "^3.15.4", + "@react-spectrum/progress": "^3.7.11", + "@react-spectrum/provider": "^3.10.0", + "@react-spectrum/radio": "^3.7.11", + "@react-spectrum/searchfield": "^3.8.11", + "@react-spectrum/slider": "^3.7.0", + "@react-spectrum/statuslight": "^3.5.17", + "@react-spectrum/switch": "^3.5.10", + "@react-spectrum/table": "^3.15.0", + "@react-spectrum/tabs": "^3.8.15", + "@react-spectrum/tag": "^3.2.11", + "@react-spectrum/text": "^3.5.10", + "@react-spectrum/textfield": "^3.12.7", + "@react-spectrum/theme-dark": "^3.5.14", + "@react-spectrum/theme-default": "^3.5.14", + "@react-spectrum/theme-light": "^3.4.14", + "@react-spectrum/tooltip": "^3.7.0", + "@react-spectrum/view": "^3.6.14", + "@react-spectrum/well": "^3.4.18", + "@react-stately/collections": "^3.12.0", + "@react-stately/data": "^3.12.0", + "@react-types/shared": "^3.26.0", + "client-only": "^0.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.35.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.35.2.tgz", + "integrity": "sha512-VM1WAps/+KEXdxIiaEGutcjgaf5p1LNf6AA+Hv7sTIaENYYJpndZqD6bGFcuuiUVTYDlnFF0hohN4l6lOsjcQw==" + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-utils": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-utils/-/jsapi-utils-0.85.35.tgz", + "integrity": "sha512-yTWk7Dp8qL43oDSuNwDldl7e22IZsSBD/o+T6sRfjnYeWx2uhWTAQLShzOdLBIbf32MnvJT8gb7V24TV/4sOeA==", + "dependencies": { + "@deephaven/filters": "^0.85.0", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/log": "^0.85.19", + "@deephaven/utils": "^0.85.35", + "lodash.clamp": "^4.0.3", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-utils/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", + "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/log": { + "version": "0.85.19", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-0.85.19.tgz", + "integrity": "sha512-z1maZojpcKxIWGkvq9ZSD1P+92LY1qZMGDjyeb84/mn+krVVFN1LTsmVCNOfA0S73s6+1UdzTch0AE4vo3EEGA==", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1" + }, + "engines": { + "node": ">=16" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/plugin/-/plugin-0.85.35.tgz", + "integrity": "sha512-h2N6xompKhrxAJGwRieH35oJokyUo920wRBx2GMELMLcSfYVZ5iIEnbqUuXTs3UbSWUgd4tC4NS2xYBu4WAbLg==", + "dependencies": { + "@deephaven/components": "^0.85.35", + "@deephaven/golden-layout": "^0.85.35", + "@deephaven/icons": "^0.85.0", + "@deephaven/iris-grid": "^0.85.35", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.35", + "@fortawesome/fontawesome-common-types": "^6.1.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/golden-layout": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-0.85.35.tgz", + "integrity": "sha512-oIF3gqfK2SVV5U/6R1Pcb/NK5XWQ5WjdFXiq+As2RGHVWO/YveaEZhY9P5/JYu0cjHETRh+mcoa8J2Sd6YpaMg==", + "dependencies": { + "@deephaven/components": "^0.85.35", + "jquery": "^3.6.0", + "nanoid": "^5.0.7" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-0.85.35.tgz", + "integrity": "sha512-du2nFvGWEMrAsJV0e4nQyD1+sRAZYB1UdE33j8+gi0CgHnYIoOsuGMKAz4i1u6OHKK0tpTK0GLFB/tyHbwnVFQ==", + "dependencies": { + "@deephaven/components": "^0.85.35", + "@deephaven/console": "^0.85.35", + "@deephaven/filters": "^0.85.0", + "@deephaven/grid": "^0.85.35", + "@deephaven/icons": "^0.85.0", + "@deephaven/jsapi-components": "^0.85.35", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/jsapi-utils": "^0.85.35", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/storage": "^0.85.19", + "@deephaven/utils": "^0.85.35", + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/sortable": "^7.0.2", + "@dnd-kit/utilities": "^3.2.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "classnames": "^2.3.1", + "fast-deep-equal": "^3.1.3", + "lodash.clamp": "^4.0.3", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.41.0", + "nanoid": "^5.0.7", + "prop-types": "^15.7.2", + "react-beautiful-dnd": "^13.1.0", + "react-transition-group": "^4.4.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-0.85.35.tgz", + "integrity": "sha512-sqPSxYbcg2EjJ+CyGrgeI7pfYmOjbGSifQaW0CD16z1isrD+o5EaIR0y4dwg5JSdimGZppXlWs5GiQikpGifdQ==", + "dependencies": { + "@deephaven/chart": "^0.85.35", + "@deephaven/components": "^0.85.35", + "@deephaven/icons": "^0.85.0", + "@deephaven/jsapi-bootstrap": "^0.85.35", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/jsapi-utils": "^0.85.35", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/storage": "^0.85.19", + "@deephaven/utils": "^0.85.35", + "@fortawesome/react-fontawesome": "^0.2.0", + "classnames": "^2.3.1", + "linkifyjs": "^4.1.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.41.0", + "nanoid": "^5.0.7", + "papaparse": "5.3.2", + "popper.js": "^1.16.1", + "prop-types": "^15.7.2", + "shell-quote": "^1.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/grid": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-0.85.35.tgz", + "integrity": "sha512-dRcxrAAlWqhB4PWQTfxaJCrtiAOX21v1Po12p0j7VDQXkwdBMkkkL3JLr3wT1ETlmWFkh8R9PyHUXAG4P8pZCA==", + "dependencies": { + "@deephaven/utils": "^0.85.35", + "classnames": "^2.3.1", + "color-convert": "^2.0.1", + "event-target-shim": "^6.0.2", + "linkifyjs": "^4.1.0", + "lodash.clamp": "^4.0.3", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/jsapi-components": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-0.85.35.tgz", + "integrity": "sha512-PebAvfV8YHrUowcl8ZnSwWsDzgI8/bc4T36sCeeyNaSQ089+BwcPwFPm9PgTpe8TDmg9tYJRdyYHZexAbb7aSA==", + "dependencies": { + "@deephaven/components": "^0.85.35", + "@deephaven/jsapi-bootstrap": "^0.85.35", + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/jsapi-utils": "^0.85.35", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.35", + "@deephaven/utils": "^0.85.35", + "@types/js-cookie": "^3.0.3", + "classnames": "^2.3.2", + "js-cookie": "^3.0.5", + "lodash.debounce": "^4.0.8", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/iris-grid/node_modules/@deephaven/storage": { + "version": "0.85.19", + "resolved": "https://registry.npmjs.org/@deephaven/storage/-/storage-0.85.19.tgz", + "integrity": "sha512-rDLcoqYv3WD8KO8/xE0Hy+zv/wJ0lhlmiJInCxsSXkcPOnD5IC5YWAK/Ov+/57+JH/r9kHmZt/JmuRKAmpv0Ow==", + "dependencies": { + "@deephaven/filters": "^0.85.0", + "@deephaven/log": "^0.85.19", + "lodash.throttle": "^4.1.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", + "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/react-hooks": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.35.tgz", + "integrity": "sha512-eOip5/TJMw1Yc8dKc54RlA6fesvgUZfwrwE0BWOerQTeRRVHFX4f1oRbAARpOEEsasWeVwpQlO20/wdShj71eg==", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^0.85.19", + "@deephaven/utils": "^0.85.35", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", + "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", + "dependencies": { + "@internationalized/string": "^3.2.5", + "@react-aria/i18n": "^3.12.4", + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.26.0", + "@react-aria/visually-hidden": "^3.8.18", + "@react-spectrum/accordion": "^3.0.0", + "@react-spectrum/actionbar": "^3.6.2", + "@react-spectrum/actiongroup": "^3.10.10", + "@react-spectrum/avatar": "^3.0.17", + "@react-spectrum/badge": "^3.1.18", + "@react-spectrum/breadcrumbs": "^3.9.12", + "@react-spectrum/button": "^3.16.9", + "@react-spectrum/buttongroup": "^3.6.17", + "@react-spectrum/calendar": "^3.5.0", + "@react-spectrum/checkbox": "^3.9.11", + "@react-spectrum/color": "^3.0.2", + "@react-spectrum/combobox": "^3.14.0", + "@react-spectrum/contextualhelp": "^3.6.16", + "@react-spectrum/datepicker": "^3.11.0", + "@react-spectrum/dialog": "^3.8.16", + "@react-spectrum/divider": "^3.5.18", + "@react-spectrum/dnd": "^3.5.0", + "@react-spectrum/dropzone": "^3.0.6", + "@react-spectrum/filetrigger": "^3.0.6", + "@react-spectrum/form": "^3.7.10", + "@react-spectrum/icon": "^3.8.0", + "@react-spectrum/illustratedmessage": "^3.5.5", + "@react-spectrum/image": "^3.5.6", + "@react-spectrum/inlinealert": "^3.2.10", + "@react-spectrum/labeledvalue": "^3.1.18", + "@react-spectrum/layout": "^3.6.10", + "@react-spectrum/link": "^3.6.12", + "@react-spectrum/list": "^3.9.0", + "@react-spectrum/listbox": "^3.14.0", + "@react-spectrum/menu": "^3.21.0", + "@react-spectrum/meter": "^3.5.5", + "@react-spectrum/numberfield": "^3.9.8", + "@react-spectrum/overlays": "^5.7.0", + "@react-spectrum/picker": "^3.15.4", + "@react-spectrum/progress": "^3.7.11", + "@react-spectrum/provider": "^3.10.0", + "@react-spectrum/radio": "^3.7.11", + "@react-spectrum/searchfield": "^3.8.11", + "@react-spectrum/slider": "^3.7.0", + "@react-spectrum/statuslight": "^3.5.17", + "@react-spectrum/switch": "^3.5.10", + "@react-spectrum/table": "^3.15.0", + "@react-spectrum/tabs": "^3.8.15", + "@react-spectrum/tag": "^3.2.11", + "@react-spectrum/text": "^3.5.10", + "@react-spectrum/textfield": "^3.12.7", + "@react-spectrum/theme-dark": "^3.5.14", + "@react-spectrum/theme-default": "^3.5.14", + "@react-spectrum/theme-light": "^3.4.14", + "@react-spectrum/tooltip": "^3.7.0", + "@react-spectrum/view": "^3.6.14", + "@react-spectrum/well": "^3.4.18", + "@react-stately/collections": "^3.12.0", + "@react-stately/data": "^3.12.0", + "@react-types/shared": "^3.26.0", + "client-only": "^0.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/@deephaven/utils": { + "version": "0.85.35", + "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-0.85.35.tgz", + "integrity": "sha512-C/0Wb3dS5PZOAMHv+B0QDxn7LSyH9gzGiztM6cuCx9ZLm7kVXMkGoqHlUhKpSv6cl7qLVOCFaPPa4eyp3WdGjg==", + "engines": { + "node": ">=16" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/monaco-editor": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz", + "integrity": "sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==" + }, + "plugins/python-remote-file-source/src/js/node_modules/rollup": { + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "plugins/python-remote-file-source/src/js/node_modules/vite": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.5.tgz", + "integrity": "sha512-zJ0RiVkf61kpd7O+VtU6r766xgnTaIknP/lR6sJTZq3HtVJ3HGnTo5DaJhTUtYoTyS/CQwZ6yEVdc/lrmQT7dQ==", + "dev": true, + "dependencies": { + "esbuild": "^0.16.14", + "postcss": "^8.4.21", + "resolve": "^1.22.1", + "rollup": "^3.10.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "plugins/simple-pivot/src/js": { + "name": "@deephaven/js-plugin-simple-pivot", + "version": "0.0.3-dev.2", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/components": "^0.85.27", + "@deephaven/dashboard": "^0.85.28", + "@deephaven/grid": "^0.85.28", + "@deephaven/icons": "^0.85.0", + "@deephaven/iris-grid": "^0.85.28", + "@deephaven/jsapi-bootstrap": "^0.85.27", + "@deephaven/jsapi-utils": "^0.85.20", + "@deephaven/log": "^0.85.19", + "@deephaven/plugin": "^0.85.28", + "@deephaven/utils": "^0.85.20", + "memoize-one": "^5.1.1", + "nanoid": "^5.1.5" + }, + "devDependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.35.2", + "@deephaven/tsconfig": "^0.72.0", + "@types/react": "^17.0.2", + "@types/react-dom": "^17.0.2", + "@vitejs/plugin-react-swc": "^3.0.0", + "react": "^17.0.2", + "vite": "~4.1.4" + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/components": { + "version": "0.85.27", + "resolved": "https://registry.npmjs.org/@deephaven/components/-/components-0.85.27.tgz", + "integrity": "sha512-ndzIUbL8mgHSi8LOjT7gNXC+kfXh+PTj9XWV4qK30FwteW5Ff/0C6Bo49lnJpTiqttBvn1tipyGc6nZ6VOmdDQ==", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/icons": "^0.85.0", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.23", + "@deephaven/utils": "^0.85.20", + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/react-fontawesome": "^0.2.0", + "@internationalized/date": "^3.5.5", + "@react-spectrum/theme-default": "^3.5.1", + "@react-spectrum/toast": "^3.0.0-beta.16", + "@react-spectrum/utils": "^3.11.5", + "@react-types/radio": "^3.8.1", + "@react-types/shared": "^3.22.1", + "@react-types/textfield": "^3.9.1", + "bootstrap": "4.6.2", + "classnames": "^2.3.1", + "event-target-shim": "^6.0.2", + "lodash.clamp": "^4.0.3", + "lodash.debounce": "^4.0.8", + "lodash.flatten": "^4.4.0", + "memoizee": "^0.4.15", + "nanoid": "^5.0.7", + "popper.js": "^1.16.1", + "prop-types": "^15.7.2", + "react-beautiful-dnd": "^13.1.0", + "react-reverse-portal": "^2.3.0", + "react-transition-group": "^4.4.2", + "react-virtualized-auto-sizer": "1.0.6", + "react-window": "^1.8.6" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/components/node_modules/@adobe/react-spectrum": { + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", + "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", + "dependencies": { + "@internationalized/string": "^3.2.5", + "@react-aria/i18n": "^3.12.4", + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.26.0", + "@react-aria/visually-hidden": "^3.8.18", + "@react-spectrum/accordion": "^3.0.0", + "@react-spectrum/actionbar": "^3.6.2", + "@react-spectrum/actiongroup": "^3.10.10", + "@react-spectrum/avatar": "^3.0.17", + "@react-spectrum/badge": "^3.1.18", + "@react-spectrum/breadcrumbs": "^3.9.12", + "@react-spectrum/button": "^3.16.9", + "@react-spectrum/buttongroup": "^3.6.17", + "@react-spectrum/calendar": "^3.5.0", + "@react-spectrum/checkbox": "^3.9.11", + "@react-spectrum/color": "^3.0.2", + "@react-spectrum/combobox": "^3.14.0", + "@react-spectrum/contextualhelp": "^3.6.16", + "@react-spectrum/datepicker": "^3.11.0", + "@react-spectrum/dialog": "^3.8.16", + "@react-spectrum/divider": "^3.5.18", + "@react-spectrum/dnd": "^3.5.0", + "@react-spectrum/dropzone": "^3.0.6", + "@react-spectrum/filetrigger": "^3.0.6", + "@react-spectrum/form": "^3.7.10", + "@react-spectrum/icon": "^3.8.0", + "@react-spectrum/illustratedmessage": "^3.5.5", + "@react-spectrum/image": "^3.5.6", + "@react-spectrum/inlinealert": "^3.2.10", + "@react-spectrum/labeledvalue": "^3.1.18", + "@react-spectrum/layout": "^3.6.10", + "@react-spectrum/link": "^3.6.12", + "@react-spectrum/list": "^3.9.0", + "@react-spectrum/listbox": "^3.14.0", + "@react-spectrum/menu": "^3.21.0", + "@react-spectrum/meter": "^3.5.5", + "@react-spectrum/numberfield": "^3.9.8", + "@react-spectrum/overlays": "^5.7.0", + "@react-spectrum/picker": "^3.15.4", + "@react-spectrum/progress": "^3.7.11", + "@react-spectrum/provider": "^3.10.0", + "@react-spectrum/radio": "^3.7.11", + "@react-spectrum/searchfield": "^3.8.11", + "@react-spectrum/slider": "^3.7.0", + "@react-spectrum/statuslight": "^3.5.17", + "@react-spectrum/switch": "^3.5.10", + "@react-spectrum/table": "^3.15.0", + "@react-spectrum/tabs": "^3.8.15", + "@react-spectrum/tag": "^3.2.11", + "@react-spectrum/text": "^3.5.10", + "@react-spectrum/textfield": "^3.12.7", + "@react-spectrum/theme-dark": "^3.5.14", + "@react-spectrum/theme-default": "^3.5.14", + "@react-spectrum/theme-light": "^3.4.14", + "@react-spectrum/tooltip": "^3.7.0", + "@react-spectrum/view": "^3.6.14", + "@react-spectrum/well": "^3.4.18", + "@react-stately/collections": "^3.12.0", + "@react-stately/data": "^3.12.0", + "@react-types/shared": "^3.26.0", + "client-only": "^0.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/components/node_modules/@deephaven/react-hooks": { + "version": "0.85.23", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", + "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^0.85.19", + "@deephaven/utils": "^0.85.20", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard": { + "version": "0.85.28", + "resolved": "https://registry.npmjs.org/@deephaven/dashboard/-/dashboard-0.85.28.tgz", + "integrity": "sha512-NQ0DKmWJa4M4T/dQygVjKxQ8ixD2tHkU5mWhBbW1LZPGmov1OGK+QPMqa1IPW2no69DA2jIqyAEpZBp9uU7dig==", + "dependencies": { + "@deephaven/components": "^0.85.27", + "@deephaven/golden-layout": "^0.85.27", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.23", + "@deephaven/redux": "^0.85.28", + "@deephaven/utils": "^0.85.20", + "fast-deep-equal": "^3.1.3", + "lodash.ismatch": "^4.1.1", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0", + "react-is": ">=16.8.0", + "react-redux": "^7.2.4" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/golden-layout": { + "version": "0.85.27", + "resolved": "https://registry.npmjs.org/@deephaven/golden-layout/-/golden-layout-0.85.27.tgz", + "integrity": "sha512-b4T9m3G1XLtu6Iy1/sINLzR6EUZM1hmdh/nAOZlKrR731IU2pp2xiilpc6YQ2WU2Ur8JcOFKufAk/6S3wZGU7A==", + "dependencies": { + "@deephaven/components": "^0.85.27", + "jquery": "^3.6.0", + "nanoid": "^5.0.7" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks": { + "version": "0.85.23", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", + "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^0.85.19", + "@deephaven/utils": "^0.85.20", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/dashboard/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { + "version": "3.38.0", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", + "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", + "dependencies": { + "@internationalized/string": "^3.2.5", + "@react-aria/i18n": "^3.12.4", + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.26.0", + "@react-aria/visually-hidden": "^3.8.18", + "@react-spectrum/accordion": "^3.0.0", + "@react-spectrum/actionbar": "^3.6.2", + "@react-spectrum/actiongroup": "^3.10.10", + "@react-spectrum/avatar": "^3.0.17", + "@react-spectrum/badge": "^3.1.18", + "@react-spectrum/breadcrumbs": "^3.9.12", + "@react-spectrum/button": "^3.16.9", + "@react-spectrum/buttongroup": "^3.6.17", + "@react-spectrum/calendar": "^3.5.0", + "@react-spectrum/checkbox": "^3.9.11", + "@react-spectrum/color": "^3.0.2", + "@react-spectrum/combobox": "^3.14.0", + "@react-spectrum/contextualhelp": "^3.6.16", + "@react-spectrum/datepicker": "^3.11.0", + "@react-spectrum/dialog": "^3.8.16", + "@react-spectrum/divider": "^3.5.18", + "@react-spectrum/dnd": "^3.5.0", + "@react-spectrum/dropzone": "^3.0.6", + "@react-spectrum/filetrigger": "^3.0.6", + "@react-spectrum/form": "^3.7.10", + "@react-spectrum/icon": "^3.8.0", + "@react-spectrum/illustratedmessage": "^3.5.5", + "@react-spectrum/image": "^3.5.6", + "@react-spectrum/inlinealert": "^3.2.10", + "@react-spectrum/labeledvalue": "^3.1.18", + "@react-spectrum/layout": "^3.6.10", + "@react-spectrum/link": "^3.6.12", + "@react-spectrum/list": "^3.9.0", + "@react-spectrum/listbox": "^3.14.0", + "@react-spectrum/menu": "^3.21.0", + "@react-spectrum/meter": "^3.5.5", + "@react-spectrum/numberfield": "^3.9.8", + "@react-spectrum/overlays": "^5.7.0", + "@react-spectrum/picker": "^3.15.4", + "@react-spectrum/progress": "^3.7.11", + "@react-spectrum/provider": "^3.10.0", + "@react-spectrum/radio": "^3.7.11", + "@react-spectrum/searchfield": "^3.8.11", + "@react-spectrum/slider": "^3.7.0", + "@react-spectrum/statuslight": "^3.5.17", + "@react-spectrum/switch": "^3.5.10", + "@react-spectrum/table": "^3.15.0", + "@react-spectrum/tabs": "^3.8.15", + "@react-spectrum/tag": "^3.2.11", + "@react-spectrum/text": "^3.5.10", + "@react-spectrum/textfield": "^3.12.7", + "@react-spectrum/theme-dark": "^3.5.14", + "@react-spectrum/theme-default": "^3.5.14", + "@react-spectrum/theme-light": "^3.4.14", + "@react-spectrum/tooltip": "^3.7.0", + "@react-spectrum/view": "^3.6.14", + "@react-spectrum/well": "^3.4.18", + "@react-stately/collections": "^3.12.0", + "@react-stately/data": "^3.12.0", + "@react-types/shared": "^3.26.0", + "client-only": "^0.0.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/grid": { + "version": "0.85.28", + "resolved": "https://registry.npmjs.org/@deephaven/grid/-/grid-0.85.28.tgz", + "integrity": "sha512-laOvYZh+mMx3sJoA6e0SwFYCYBHuJiH09/1Wk202kfvSISFsQE0jauV7JTUhgOqSMFH8lrvQKK3wbZ0T21TChA==", + "dependencies": { + "@deephaven/utils": "^0.85.20", + "classnames": "^2.3.1", + "color-convert": "^2.0.1", + "event-target-shim": "^6.0.2", + "linkifyjs": "^4.1.0", + "lodash.clamp": "^4.0.3", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/icons": { + "version": "0.85.0", + "resolved": "https://registry.npmjs.org/@deephaven/icons/-/icons-0.85.0.tgz", + "integrity": "sha512-8G77T/RPLs+SRdxWJJmOAFV0cS14U63L7hwJ8aqhMQmQkNqTqeDKrPXugXpOGN4iw3rkN05UPgV6ypS9XtbEgA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "^6.1.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "^6.2.1", + "@fortawesome/react-fontawesome": "^0.2.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid": { + "version": "0.85.28", + "resolved": "https://registry.npmjs.org/@deephaven/iris-grid/-/iris-grid-0.85.28.tgz", + "integrity": "sha512-hURNxPEVIl+NnYBQ03UqNDVeCRIlrBYJJPvUoFqlZAGjNpIwcPLAxCNocs6ZxQYuYNNgU9FaeTWeE2Wwg7ARdQ==", + "dependencies": { + "@deephaven/components": "^0.85.27", + "@deephaven/console": "^0.85.27", + "@deephaven/filters": "^0.85.0", + "@deephaven/grid": "^0.85.28", + "@deephaven/icons": "^0.85.0", + "@deephaven/jsapi-components": "^0.85.27", + "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", + "@deephaven/jsapi-utils": "^0.85.20", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.23", + "@deephaven/storage": "^0.85.19", + "@deephaven/utils": "^0.85.20", + "@dnd-kit/core": "^6.1.0", + "@dnd-kit/sortable": "^7.0.2", + "@dnd-kit/utilities": "^3.2.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "classnames": "^2.3.1", + "fast-deep-equal": "^3.1.3", + "lodash.clamp": "^4.0.3", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.41.0", + "nanoid": "^5.0.7", + "prop-types": "^15.7.2", + "react-beautiful-dnd": "^13.1.0", + "react-transition-group": "^4.4.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/console": { + "version": "0.85.27", + "resolved": "https://registry.npmjs.org/@deephaven/console/-/console-0.85.27.tgz", + "integrity": "sha512-UhIW7j8z5X6sY/AfUovovY/YJjHDQi/uxsb1TOCmoJSm/pQL93Mxj6XqwwaDFBMf3JGeFmWtjC20w56Y2NJ4YA==", + "dependencies": { + "@deephaven/chart": "^0.85.27", + "@deephaven/components": "^0.85.27", + "@deephaven/icons": "^0.85.0", + "@deephaven/jsapi-bootstrap": "^0.85.27", + "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.23", + "@deephaven/storage": "^0.85.19", + "@deephaven/utils": "^0.85.20", + "@fortawesome/react-fontawesome": "^0.2.0", + "classnames": "^2.3.1", + "linkifyjs": "^4.1.0", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "memoize-one": "^5.1.1", + "memoizee": "^0.4.15", + "monaco-editor": "^0.41.0", + "nanoid": "^5.0.7", + "papaparse": "5.3.2", + "popper.js": "^1.16.1", + "prop-types": "^15.7.2", + "shell-quote": "^1.7.2" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/jsapi-components": { + "version": "0.85.27", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-components/-/jsapi-components-0.85.27.tgz", + "integrity": "sha512-ZABrMxL0bVYMTLs14lwD/KcJL5ZEAsV8oVkdLwhg+eAA1hM3z1l2IWYa+CkCFkiAas1iqFnhk+o0Xry48n8JfQ==", + "dependencies": { + "@deephaven/components": "^0.85.27", + "@deephaven/jsapi-bootstrap": "^0.85.27", + "@deephaven/jsapi-types": "^1.0.0-dev0.34.0", + "@deephaven/jsapi-utils": "^0.85.20", + "@deephaven/log": "^0.85.19", + "@deephaven/react-hooks": "^0.85.23", + "@deephaven/utils": "^0.85.20", + "@types/js-cookie": "^3.0.3", + "classnames": "^2.3.2", + "js-cookie": "^3.0.5", + "lodash.debounce": "^4.0.8", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/react-hooks": { + "version": "0.85.23", + "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.85.23.tgz", + "integrity": "sha512-RU18os6b2J1eSwjY2uvVrKDk/Dto/KzLz6aSJK1J/kDC9UsJA2UPjtItlz5nEbl8g7z2G3RN2IEGQXriWrMP7g==", + "dependencies": { + "@adobe/react-spectrum": "3.38.0", + "@deephaven/log": "^0.85.19", + "@deephaven/utils": "^0.85.20", + "lodash.debounce": "^4.0.8", + "lodash.throttle": "^4.1.1", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "plugins/simple-pivot/src/js/node_modules/@deephaven/iris-grid/node_modules/@deephaven/react-hooks/node_modules/@adobe/react-spectrum": { "version": "3.38.0", "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.38.0.tgz", "integrity": "sha512-0/zFmTz/sKf8rvB8EHMuWIE5miY1gSAvTr5q4fPIiQJQwMAlQyXfH3oy++/MsiC30HyT3Mp93scxX2F1ErKL4g==", @@ -36750,12 +37602,16 @@ "node": ">=18.0.0" } }, - "plugins/ui/src/js/node_modules/redux-thunk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", - "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", - "peerDependencies": { - "redux": "^4" + "plugins/ui/src/js/node_modules/typescript": { + "version": "4.9.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" } }, "plugins/ui/src/js/node_modules/unist-util-find-after": { diff --git a/plugins/python-remote-file-source/.gitignore b/plugins/python-remote-file-source/.gitignore new file mode 100644 index 000000000..af03e23eb --- /dev/null +++ b/plugins/python-remote-file-source/.gitignore @@ -0,0 +1,10 @@ +build/ +dist/ +.venv/ +/venv +*.egg-info/ +.idea +.DS_store +__pycache__/ +node_modules +docs/*.html \ No newline at end of file diff --git a/plugins/python-remote-file-source/LICENSE b/plugins/python-remote-file-source/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/plugins/python-remote-file-source/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md new file mode 100644 index 000000000..2d1174ca7 --- /dev/null +++ b/plugins/python-remote-file-source/README.md @@ -0,0 +1,12 @@ +# Deephaven Local Python Execution Plugin + +A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. + +## Additional Docs + +- [docs/DESIGN.md](docs/DESIGN.md) - Notes on architecture / design. +- [README_TEMPLATE.md](README_TEMPLATE.md) - Template scafolded by original cookiecutter template. Will eventually delete once `README` is completed. + +## Dev + +A DH server can be started via `./scripts/dev.sh` (Note that this requires venv to be active and initial build to have been run at least once per the template docs) diff --git a/plugins/python-remote-file-source/README_TEMPLATE.md b/plugins/python-remote-file-source/README_TEMPLATE.md new file mode 100644 index 000000000..a4dae1253 --- /dev/null +++ b/plugins/python-remote-file-source/README_TEMPLATE.md @@ -0,0 +1,213 @@ +# deephaven_python_remote_file_source + +This is a Python plugin for Deephaven generated from a [deephaven-plugin](https://github.com/deephaven/deephaven-plugins) template. + +Specifically, this plugin is a bidirectional widget plugin, which can send and receive messages on both the client and server. +The plugin works out of the box, demonstrates basic plugin structure, and can be used as a starting point for building more complex plugins. + +## Plugin Structure + +The `src` directory contains the Python and JavaScript code for the plugin. +Within the `src` directory, the `deephaven/python_remote_file_source` directory contains the Python code, and the `js` directory contains the JavaScript code. + +The Python files have the following structure: +`plugin_object.py` defines a simple Python class that can send messages to the client. This object can be modified to have other plugin functionality or replaced with a different object entirely, depending on the plugin's needs. +`plugin_type.py` defines the Python type for the plugin (which is used for registration) and a simple message stream. These can be modified to handle different objects or messages. An initial message is sent from the Python side to the client, then additional messages can be sent back and forth. +`register.py` registers the plugin with Deephaven. This file will not need to be modified for most plugins at the initial stages, but will need to be if the package is renamed or JavaScript files are moved. + +The JavaScript files have the following structure: +`PythonRemoteFileSourcePlugin.ts` registers the plugin with Deephaven. This contains the client equivalent of the type in `plugin_type.py` and these should be kept in sync. +`PythonRemoteFileSourcePluginView.tsx` defines the plugin panel and message handling. This is where messages are received when sent from the Python side of the plugin. This file is a good starting point for adding more complex plugin functionality. + +Additionally, the `test` directory contains Python tests for the plugin. This demonstrates how the embedded Deephaven server can be used in tests. +It's recommended to use `tox` to run the tests, and the `tox.ini` file is included in the project. + +## Using plugin_builder.py +The `plugin_builder.py` script is the recommended way to build the plugin. +See [Building the Plugin](#building-the-plugin) for more information if you want to build the plugin manually instead. + +To use `plugin_builder.py`, first set up your Python environment and install the required packages. +To build the plugin, you will need `npm` and `python` installed, as well as the `build` package for Python. +`nvm` is also strongly recommended, and an `.nvmrc` file is included in the project. +The script uses `watchdog` and `deephaven-server` for `--watch` mode and `--server` mode, respectively. +```sh +cd plugins/python-remote-file-source +python -m venv .venv +source .venv/bin/activate +pip install --upgrade -r requirements.txt +pip install deephaven-server watchdog + +cd src/js +nvm install +npm install +cd ../.. +``` + +First, run an initial install of the plugin: +This builds and installs the full plugin, including the JavaScript code. +```sh +python plugin_builder.py --install --js +``` + +After this, more advanced options can be used. +For example, if only iterating on the plugins with no version bumps, use the `--reinstall` flag for faster builds. +This adds `--force-reinstall --no-deps` to the `pip install` command. +```sh +python plugin_builder.py --reinstall --js +``` + +If only the Python code has changed, the `--js` flag can be omitted. +```sh +python plugin_builder.py --reinstall +``` + +Additional especially useful flags are `--watch` and `--server`. +`--watch` will watch the Python and JavaScript files for changes and rebuild the plugin when they are modified. +`--server` will start the Deephaven server with the plugin installed. +Taken in combination with `--reinstall` and `--js`, this command will rebuild and restart the server when changes are made to the plugin. +```sh +python plugin_builder.py --reinstall --js --watch --server +``` + +If interested in passing args to the server, the `--server-arg` flag can be used as well +Check `deephaven server --help` for more information on the available arguments. +```sh +python plugin_builder.py --reinstall --js --watch --server --server-arg --port=9999 +``` + +See [Using the Plugin](#using-the-plugin) for more information on how to use the plugin. + +## Manually Building the Plugin + +To build the plugin, you will need `npm` and `python` installed, as well as the `build` package for Python. +`nvm` is also strongly recommended, and an `.nvmrc` file is included in the project. +The python venv can be created and the recommended packages installed with the following commands: +```sh +cd plugins/python-remote-file-source +python -m venv .venv +source .venv/bin/activate +pip install --upgrade -r requirements.txt +``` + +Build the JavaScript plugin from the `src/js` directory: + +```sh +cd src/js +nvm install +npm install +npm run build +``` + +Then, build the Python plugin from the top-level directory: + +```sh +cd ../.. +python -m build --wheel +``` + +The built wheel file will be located in the `dist` directory. + +If you modify the JavaScript code, remove the `build` and `dist` directories before rebuilding the wheel: +```sh +rm -rf build dist +``` + +## Installing the Plugin + +The plugin can be installed into a Deephaven instance with `pip install `. +The wheel file is stored in the `dist` directory after building the plugin. +Exactly how this is done will depend on how you are running Deephaven. +If using the venv created above, the plugin and server can be created with the following commands: +```sh +pip install deephaven-server +pip install dist/deephaven_python_remote_file_source-0.0.1.dev0-py3-none-any.whl +deephaven server +``` +See the [plug-in documentation](https://deephaven.io/core/docs/how-to-guides/install-use-plugins/) for more information. + +## Using the Plugin + +Once the Deephaven server is running, the plugin should be available to use. + +```python +from deephaven.python_remote_file_source_plugin import ( + PluginObject as DeephavenRemoteFileSourcePlugin, +) + +obj = DeephavenRemoteFileSourcePlugin() +``` + +A panel should appear. You can now use the object to send messages to the client. + +```python +obj.send_message("Hello, world!") +``` + +The panel can also send messages back to the Python client by using the input field. + +## Debugging the Plugin +It's recommended to run through all the steps in [Using plugin_builder.py](#Using-plugin_builder.py) and [Using the Plugin](#Using-the-plugin) to ensure the plugin is working correctly. +Then, make changes to the plugin and rebuild it to see the changes in action. +Checkout the [Deephaven plugins repo](https://github.com/deephaven/deephaven-plugins), which is where this template was generated from, for more examples and information. +The `plugins` folder contains current plugins that are developed and maintained by Deephaven. +Below are some common issues and how to resolve them as you develop your plugin. +If there is an issue with the process while following the Installation and Usage steps on the originally generated plugin, please open an issue. + +### The Panel is Not Appearing +#### Checking if the Plugin is Registered +If the panel is not appearing or an error is thrown that the import is not found, the plugin may not be registered correctly. +To verify the plugin is registered, check either the console logs or the versions in the settings panel. +- In the console logs, there should be a messaging saying `Plugins loaded:` with a map that includes this plugin. +![plugin map](./_assets/plugin_map.png "Plugin Map") + +- To get to the settings panel, click on the gear icon in the top right corner of the Deephaven window. Towards the bottom this plugin should be listed. +![plugin settings](./_assets/plugin_settings.png "Plugin Settings") +- If the plugin is not listed, attempt to rebuild and reinstall the plugin and check for errors during that process. + +#### Checking if the Python Package is Installed +- Running `pip list` in the `.venv` environment should show the Python package installed, but this is not a guarantee that the plugin is registered properly. +- The version can also be checked directly from the Python console with: +```{python} +from importlib.metadata import version +print(version("deephaven_python_remote_file_source")) +``` + +### The Panel is Appearing but with Errors or Not Functioning Correctly +Check both the Python and JavaScript logs for errors as either side could be causing the issue. + +## Distributing the Plugin +To distribute the plugin, you can upload the wheel file to a package repository, such as [PyPI](https://pypi.org/). +The version of the plugin can be updated in the `setup.cfg` file. + +There is a separate instance of PyPI for testing purposes. +Start by creating an account at [TestPyPI](https://test.pypi.org/account/register/). +Then, get an API token from [account management](https://test.pypi.org/manage/account/#api-tokens), setting the “Scope” to “Entire account”. + +To upload to the test instance, use the following commands: +```sh +python -m pip install --upgrade twine +python -m twine upload --repository testpypi dist/* +``` + +Now, you can install the plugin from the test instance. The extra index is needed to find dependencies: +```sh +pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ deephaven_python_remote_file_source +``` + +For a production release, create an account at [PyPI](https://pypi.org/account/register/). +Then, get an API token from [account management](https://pypi.org/manage/account/#api-tokens), setting the “Scope” to “Entire account”. + +To upload to the production instance, use the following commands. +Note that `--repository` is the production instance by default, so it can be omitted: +```sh +python -m pip install --upgrade twine +python -m twine upload dist/* +``` + +Now, you can install the plugin from the production instance: +```sh +pip install deephaven_python_remote_file_source +``` + +See the [Python packaging documentation](https://packaging.python.org/en/latest/tutorials/packaging-projects/#uploading-the-distribution-archives) for more information. + diff --git a/plugins/python-remote-file-source/_assets/plugin_map.png b/plugins/python-remote-file-source/_assets/plugin_map.png new file mode 100644 index 0000000000000000000000000000000000000000..e7a9b1379872fb6c6f06911b58fa95a71cefa13d GIT binary patch literal 52557 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 CM^G66 literal 0 HcmV?d00001 diff --git a/plugins/python-remote-file-source/_assets/plugin_settings.png b/plugins/python-remote-file-source/_assets/plugin_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..4a067730017e25dc7b2785df9c2626b0bbd5ab52 GIT binary patch literal 34460 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 literal 0 HcmV?d00001 diff --git a/plugins/python-remote-file-source/docs/DESIGN.md b/plugins/python-remote-file-source/docs/DESIGN.md new file mode 100644 index 000000000..0c639abd3 --- /dev/null +++ b/plugins/python-remote-file-source/docs/DESIGN.md @@ -0,0 +1,57 @@ +# Deephaven Python Remote File Source Plugin + +A Deephaven bi-directional plugin to allow sourcing Python imports from the local filesystem. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. As part of initialization, a custom Python `sys.meta_path` finder and loader will be registered that will send messages to the client to request content for loading modules under a special module root. + +## Implementation + +### Python + +**DeephavenLocalExecPluginObject** + +- Deephaven Bi-directional plugin. +- Handles plugin registration + exposes message passing utils +- VS Code extension will use the JS API to run a snippet of Python code to initialize the plugin and assign it to a special variable. e.g. + + ```py + from deephaven.python_remote_file_source_plugin import PluginObject as DeephavenRemoteFileSourcePlugin + + __deephaven_vscode = DeephavenRemoteFileSourcePlugin() + ``` + +- VS Code can then fetch the object and subscribe to messages from the server + +**LocalMetaPathFinder class** + +- Instantiated with a "root" module name (e.g. `vscode`) defining the scope of module paths it will handle. e.g. A root of `vscode` would handle `vscode.module_a`, `vscode.module_b`, etc. +- Implements `find_spec`. Returns a `ModuleSpec` if it can handle the import. If so, this will also include an instance of `LocalModuleLoader`. +- Sends messages to clients running in user's local environment to request module source content. + - If available, clients will send source content back to the path finder. The path finder will then construct a `ModuleSpec` with a loader capable of serving the source. + - If not, will return `None` telling the import system to move on to next finder / loader + +> Note: `find_spec` is a synchronous api, but message passing between the local client and server plugin is asynchronous. We'll need to handle this somehow. Possibly with `asyncio` or some other blocking mechanism. + +**LocalModuleLoader class** + +- Responsible for executing the module source content and updating `module.__dict__` with the resulting variables. + +### VS Code Extension + +- After establishing a session, send a Python snippet to instantiate the plugin and assign to `__deephaven_vscode `if it isn't already assigned. Fetch the `__deephaven_vscode` object, and add an event listener for messages. +- Still need to figure out what happens if multiple clients are subscribed. This "might" only be possible in Community +- We probably will need to provide a way to specify the root folder to use for local module sourcing. The "root" used by the plugin will need to have the same name as the folder in VS Code in order for pylance to resolve imports locally for intellisense. There's also some pylance VS Code settings that can be tweaked to allow the workspace folder name to be found. e.g. "python.analysis.extraPaths": [".."]. Would be nice if DH extension can hhandle this automatically if the workspace root is the intended folder. For simpler config, we could just always require a subfolder and a way to specify that as the root, but this could be annoying if users don't want that assuming we can reasonably configure automatically for them. + +### Testing + +- Single root workspaces +- Multi root workspaces +- **init**.py modules +- Include / exclude folders +- Error handling. Timeouts + other + +### Questions + +- Can another user get access to filesystem. Seems yes without some sort of user check + yea +- Make sure VS Code will not serve modules that haven't been exposed / allowed +- Embed widget seems to not close connection when panel is closed +- Potential rename to "Remote module source" plugin diff --git a/plugins/python-remote-file-source/plugin_builder.py b/plugins/python-remote-file-source/plugin_builder.py new file mode 100644 index 000000000..71cd7d20e --- /dev/null +++ b/plugins/python-remote-file-source/plugin_builder.py @@ -0,0 +1,411 @@ +from __future__ import annotations + +import click +import os +import sys +from typing import Generator, Callable +import time +import subprocess +from watchdog.events import FileSystemEvent, RegexMatchingEventHandler +from watchdog.observers import Observer +import threading + +# get the directory of the current file +# this is used to watch for changes in this directory +current_dir = os.path.dirname(os.path.abspath(__file__)) + +# these are the patterns to watch for changes in this directory +# if in editable mode, the builder will rerun when these files change +REBUILD_REGEXES = [ + r".*\.py$", + r".*\.js$", + r".*\.ts$", + r".*\.tsx$", + r".*\.scss$", +] + +# ignore these patterns in particular +# prevents infinite loops when the builder is rerun +IGNORE_REGEXES = [ + r".*/dist/.*", + r".*/build/.*", + r".*/node_modules/.*", + r".*/_js/.*", + r".*/src/node/.*", + r".*/test_ws/.*$", + # ignore hidden files and directories + r".*/\..*/.*", +] + +# the path where the python files are located relative to this script +# modify this if the python files are moved +PYTHON_DIR = "." +# the path where the JS files are located relative to this script +# modify this if the JS files are moved +JS_DIR = "./src/js" + + +class PluginsChangedHandler(RegexMatchingEventHandler): + """ + A handler that watches for changes and reruns the function when changes are detected + + Args: + func: The function to run when changes are detected + stop_event: The event to signal the function to stop + + Attributes: + func: The function to run when changes are detected + stop_event: The event to signal the function to stop + rerun_lock: A lock to prevent multiple reruns from occurring at the same time + """ + + def __init__(self, func: Callable, stop_event: threading.Event) -> None: + super().__init__(regexes=REBUILD_REGEXES, ignore_regexes=IGNORE_REGEXES) + + self.func = func + + # A flag to indicate whether the function should continue running + # Also prevents unnecessary reruns + self.stop_event = stop_event + + # A lock to prevent multiple reruns from occurring at the same time + self.rerun_lock = threading.Lock() + + # always have an initial run + threading.Thread(target=self.attempt_rerun).start() + + def attempt_rerun(self) -> None: + """ + Attempt to rerun the function. + If the stop event is set, do not rerun because a rerun has already been scheduled. + """ + self.stop_event.set() + with self.rerun_lock: + self.stop_event.clear() + self.func() + + def event_handler(self, event: FileSystemEvent) -> None: + """ + Handle any file system event + + Args: + event: The event that occurred + """ + if self.stop_event.is_set(): + # a rerun has already been scheduled on another thread + print( + f"File {event.src_path} {event.event_type}, rerun has already been scheduled" + ) + return + print(f"File {event.src_path} {event.event_type}, new rerun scheduled") + threading.Thread(target=self.attempt_rerun).start() + + def on_created(self, event: FileSystemEvent) -> None: + """ + Handle a file creation event + + Args: + event: The event that occurred + """ + self.event_handler(event) + + def on_deleted(self, event: FileSystemEvent) -> None: + """ + Handle a file deletion event + + Args: + event: The event that occurred + """ + self.event_handler(event) + + def on_modified(self, event: FileSystemEvent) -> None: + """ + Handle a file modification event + + Args: + event: The event that occurred + """ + self.event_handler(event) + + def on_moved(self, event: FileSystemEvent) -> None: + """ + Handle a file move event + + Args: + event: The event that occurred + + Returns: + + """ + self.event_handler(event) + + +def clean_build_dist() -> None: + """ + Remove the build and dist directories. + """ + # these folders may not exist, so ignore the errors + if os.path.exists(f"{PYTHON_DIR}/build"): + os.system(f"rm -rf {PYTHON_DIR}/build") + if os.path.exists(f"{PYTHON_DIR}/dist"): + os.system(f"rm -rf {PYTHON_DIR}/dist") + + +def run_command(command: str) -> None: + """ + Run a command and exit if it fails. + This should only be used in a non-main thread. + + Args: + command: The command to run. + + Returns: + None + """ + code = os.system(command) + if code != 0: + os._exit(1) + + +def run_build() -> None: + """ + Build the plugin + """ + + clean_build_dist() + + click.echo(f"Building plugin") + run_command(f"python -m build --wheel {PYTHON_DIR}") + + +def run_install( + reinstall: bool, +) -> None: + """ + Install plugins that have been built + + Args: + reinstall: Whether to reinstall the plugins. + If True, the --force-reinstall and --no-deps flags are added to pip install. + + Returns: + None + """ + install = "pip install" + if reinstall: + install += " --force-reinstall --no-deps" + + click.echo("Installing plugin") + run_command(f"{install} {PYTHON_DIR}/dist/*.whl") + + +def run_build_js() -> None: + """ + Build the JS files for the plugin + """ + click.echo(f"Building the JS plugin") + run_command(f"npm run build --prefix {JS_DIR}") + + +def build_server_args(server_arg: tuple[str]) -> list[str]: + """ + Build the server arguments to pass to the deephaven server + By default, the --no-browser flag is added to the server arguments unless the --browser flag is present + + Args: + server_arg: The arguments to pass to the server + """ + server_args = ["--no-browser"] + if server_arg: + if "--no-browser" in server_arg or "--browser" in server_arg: + server_args = list(server_arg) + else: + server_args = server_args + list(server_arg) + return server_args + + +def handle_args( + build: bool, + install: bool, + reinstall: bool, + server: bool, + server_arg: tuple[str], + js: bool, + stop_event: threading.Event, +) -> None: + """ + Handle all arguments for the builder command + + Args: + build: True to build the plugins + install: True to install the plugins + reinstall: True to reinstall the plugins + server: True to run the deephaven server after building and installing the plugins + server_arg: The arguments to pass to the server + js: True to build the JS files for the plugins + stop_event: The event to signal the function to stop + """ + # it is possible that the stop event is set before this function is called + if stop_event.is_set(): + return + + # default is to install, but don't if just configuring + if not any([build, install, reinstall, js]): + js = True + install = True + + # if this thread is signaled to stop, return after the current command + # instead of in the middle of a command, which could leave the environment in a bad state + if stop_event.is_set(): + return + + if js: + run_build_js() + + if stop_event.is_set(): + return + + if build or install or reinstall: + run_build() + + if stop_event.is_set(): + return + + if install or reinstall: + run_install(reinstall) + + if stop_event.is_set(): + return + + if server or server_arg: + server_args = build_server_args(server_arg) + + click.echo(f"Running deephaven server with args: {server_args}") + process = subprocess.Popen(["deephaven", "server"] + server_args) + + # waiting on either the process to finish or the stop event to be set + while not stop_event.wait(1): + poll = process.poll() + if poll is not None: + # process threw an error or was killed, so exit + os._exit(process.returncode) + + # stop event is set, so kill the process + process.terminate() + try: + process.wait(timeout=1) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + + +@click.command( + short_help="Build and install plugin.", + help="Build and install plugins. " + "By default, all plugins with the necessary file are used unless specified via the plugins arg.", +) +@click.option("--build", "-b", is_flag=True, help="Build the plugin.") +@click.option( + "--install", + "-i", + is_flag=True, + help="Install the plugin. This is the default behavior if no flags are provided.", +) +@click.option( + "--reinstall", + "-r", + is_flag=True, + help="Reinstall the plugin. " + "This adds the --force-reinstall and --no-deps flags to pip install. " + "Useful if the plugin has already been installed and does not have a new version number.", +) +@click.option( + "--server", + "-s", + is_flag=True, + help="Run the deephaven server after building and installing the plugin.", +) +@click.option( + "--server-arg", + "-sa", + default=tuple(), + multiple=True, + help="Run the deephaven server after building and installing the plugin with the provided argument.", +) +@click.option( + "--js", + "-j", + is_flag=True, + help="Build the JS files for the plugin.", +) +@click.option( + "--watch", + "-w", + is_flag=True, + help="Run the other provided commands in an editable-like mode, watching for changes " + "This will rerun all other commands (except configure) when files are changed. " + "The top level directory of this project is watched.", +) +def builder( + build: bool, + install: bool, + reinstall: bool, + server: bool, + server_arg: tuple[str], + js: bool, + watch: bool, +) -> None: + """ + Build and install plugins. + + Args: + build: True to build the plugin + install: True to install the plugin + reinstall: True to reinstall the plugin + server: True to run the deephaven server after building and installing the plugin + server_arg: The arguments to pass to the server + js: True to build the JS files for the plugin + watch: True to rerun the other commands when files are changed + """ + stop_event = threading.Event() + + def run_handle_args() -> None: + """ + Run the handle_args function with the provided arguments + """ + handle_args( + build, + install, + reinstall, + server, + server_arg, + js, + stop_event, + ) + + if not watch: + # since editable is not specified, only run the handler once + # call it from a thread to allow the usage of os._exit to exit the process + # rather than sys.exit because sys.exit will not exit the process when called from a thread + # and os._exit should be called from a thread + thread = threading.Thread(target=run_handle_args) + thread.start() + thread.join() + return + + # editable is specified, so run the handler in a loop that watches for changes and + # reruns the handler when changes are detected + event_handler = PluginsChangedHandler(run_handle_args, stop_event) + observer = Observer() + observer.schedule(event_handler, current_dir, recursive=True) + observer.start() + try: + while True: + input() + finally: + observer.stop() + observer.join() + + +if __name__ == "__main__": + builder() diff --git a/plugins/python-remote-file-source/pyproject.toml b/plugins/python-remote-file-source/pyproject.toml new file mode 100644 index 000000000..54e217464 --- /dev/null +++ b/plugins/python-remote-file-source/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=43.0.0", "wheel", "deephaven-plugin-packaging"] +build-backend = "setuptools.build_meta" diff --git a/plugins/python-remote-file-source/requirements.txt b/plugins/python-remote-file-source/requirements.txt new file mode 100644 index 000000000..c901c3334 --- /dev/null +++ b/plugins/python-remote-file-source/requirements.txt @@ -0,0 +1,5 @@ +build +pip +pre-commit +setuptools +tox \ No newline at end of file diff --git a/plugins/python-remote-file-source/setup.cfg b/plugins/python-remote-file-source/setup.cfg new file mode 100644 index 000000000..37a94a1c7 --- /dev/null +++ b/plugins/python-remote-file-source/setup.cfg @@ -0,0 +1,27 @@ +[metadata] +name = deephaven-plugin-python-remote-file-source +description = Deephaven plugin for sourcing Python files from a remote location +long_description = file: README.md +long_description_content_type = text/markdown +version = 0.0.1.dev0 +keywords = deephaven, plugin, graph +author = deephaven +author_email = Anonymous +platforms = any + +[options] +package_dir= + =src +packages=find_namespace: +install_requires = + deephaven-core>=0.35.1 + deephaven-plugin>=0.6.0 + deephaven-plugin-utilities +include_package_data = True + +[options.packages.find] +where=src + +[options.entry_points] +deephaven.plugin = + registration_cls = deephaven.python_remote_file_source.register:PluginRegistration diff --git a/plugins/python-remote-file-source/setup.py b/plugins/python-remote-file-source/setup.py new file mode 100644 index 000000000..4e4963b87 --- /dev/null +++ b/plugins/python-remote-file-source/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup +import os +from deephaven.plugin.packaging import package_js + +# js_dir is the directory where the JavaScript source files are located +js_dir = "src/js/" +# dest_dir is the directory where the JavaScript source files will be copied to in the package +dest_dir = os.path.join("src/deephaven/python_remote_file_source/_js") + +package_js(js_dir, dest_dir) + +setup(package_data={"deephaven.python_remote_file_source._js": ["**"]}) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/.gitignore b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/.gitignore new file mode 100644 index 000000000..1b9252d0d --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/.gitignore @@ -0,0 +1,2 @@ +# This is where built js files are stored by setup.py +_js/ \ No newline at end of file diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/__init__.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/__init__.py new file mode 100644 index 000000000..19c6afa31 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/__init__.py @@ -0,0 +1,5 @@ +""" +This is a plugin for Deephaven that provides a simple object that can send messages to and from the client. +""" + +from .plugin_object import * diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py new file mode 100644 index 000000000..9e678f023 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py @@ -0,0 +1,52 @@ +from typing import Any, TypeGuard +import uuid +from .types import JsonRpcRequest, JsonRpcResponse + + +def create_request_msg(method: str, params: dict) -> JsonRpcRequest: + """ + Create a JSON-RPC v2 request message + """ + return { + "jsonrpc": "2.0", + "id": str(uuid.uuid4()), + "method": method, + "params": params, + } + + +def create_response_msg(id: str, result: Any) -> JsonRpcResponse: + """ + Create a JSON-RPC v2 response message + """ + return {"jsonrpc": "2.0", "id": id, "result": result} + + +def is_valid_json_rpc_request(msg: Any) -> TypeGuard[JsonRpcRequest]: + """ + Check if the message is a valid JSON-RPC v2 message + + Args: + msg: The message to check + """ + return ( + isinstance(msg, dict) + and msg.get("jsonrpc") == "2.0" + and "id" in msg + and "method" in msg + ) + + +def is_valid_json_rpc_response(msg: Any) -> TypeGuard[JsonRpcResponse]: + """ + Check if the message is a valid JSON-RPC v2 message + + Args: + msg: The message to check + """ + return ( + isinstance(msg, dict) + and msg.get("jsonrpc") == "2.0" + and "id" in msg + and ("result" in msg or "error" in msg) + ) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py new file mode 100644 index 000000000..c0a65df13 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py @@ -0,0 +1,15 @@ +class Logger: + def __init__(self, name: str): + self.name = name + + def debug(self, *args): + print("[DEBUG]", f"[{self.name}]", *args) + + def info(self, *args): + print("[INFO]", f"[{self.name}]", *args) + + def warning(self, *args): + print("[WARNING]", f"[{self.name}]", *args) + + def error(self, *args): + print("[ERROR]", f"[{self.name}]", *args) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py new file mode 100644 index 000000000..6a99a6e3f --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -0,0 +1,183 @@ +import asyncio +import sys +import io +import json +from typing import Any, Optional +from deephaven.plugin.object_type import MessageStream as MesssageStreamBase + +from .plugin_object import PluginObject +from .json_rpc import ( + create_response_msg, + is_valid_json_rpc_request, + is_valid_json_rpc_response, +) +from .logger import Logger +from .module_loader import RemoteMetaPathFinder +from .types import JsonRpcRequest, JsonRpcResponse, MessageStreamRequestInterface + +logger = Logger("DeephavenLocalExecPluginMessageStream") + + +class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): + """ + A custom MessageStream between the client and the server plugin + + Attributes: + _client_connection: MessageStream: The connection to the client + """ + + id: Optional[str] = None + _future_responses: dict[str, asyncio.Future[JsonRpcResponse]] = {} + _meta_path_finder: Optional[RemoteMetaPathFinder] = None + _plugin: Optional[PluginObject] = None + + def __init__(self, obj: PluginObject, client_connection: MesssageStreamBase): + logger.info("Creating DeephavenLocalExecPluginMessageStream") + super().__init__() + self._plugin = obj + self._client_connection = client_connection + + # Start the message stream. All we do is send a blank message to start. Client will respond with the initial state. + # Additional messages can be sent to the client by calling on_data on the client connection at any time after this. + # These additional messages are processed in DeephavenLocalExecPluginView.tsx + self._client_connection.on_data(b"", []) + + def _deregister_meta_path_finder(self): + if self._meta_path_finder is None: + return + + sys.meta_path.remove(self._meta_path_finder) + self._meta_path_finder = None + + def _register_meta_path_finder(self): + if self._plugin is None: + logger.error("PluginObject is None, cannot register meta path finder") + return + + self._meta_path_finder = RemoteMetaPathFinder(self, self._plugin) + sys.meta_path.insert(0, self._meta_path_finder) + + count = sum( + isinstance(finder, RemoteMetaPathFinder) for finder in sys.meta_path + ) + logger.info("Registered LocalMetaPathFinder:", count) + + def send_message(self, message: JsonRpcResponse | str) -> None: + """ + Send a message to the client + Args: + message: The message to send (str or dict) + """ + if isinstance(message, dict): + message = json.dumps(message) + + self._client_connection.on_data(message.encode(), []) + + def on_data(self, payload: bytes, references: list[Any]) -> None: + """ + Handle a payload from the client. If it is a JSON-RPC v2 response with a matching id, set the result. + """ + if self._plugin is None: + logger.error("PluginObject is None, cannot handle on_data") + return + + decoded_payload = io.BytesIO(payload).read().decode() + + try: + msg = json.loads(decoded_payload) + except Exception: + logger.info(f"Received non-JSON payload: {decoded_payload}") + return + + if is_valid_json_rpc_response(msg): + if msg["id"] in self._future_responses: + future_response = self._future_responses[msg["id"]] + loop = future_response.get_loop() + loop.call_soon_threadsafe(future_response.set_result, msg) + # Plugin client can request info to see what top-level modules are + # currently configured. + elif is_valid_json_rpc_request(msg): + match msg["method"]: + case "request_plugin_info": + full_names = list(self._plugin.get_top_level_module_fullnames()) + logger.info( + "Sending plugin info to client. Remote module count:", + len(full_names), + ) + self.send_message( + create_response_msg(msg["id"], {"full_names": full_names}) + ) + case "set_connection_id": + self.id = msg.get("id") + logger.info("Set connection id:", self.id) + + self._deregister_meta_path_finder() + self._register_meta_path_finder() + + self.send_message(create_response_msg(msg["id"], None)) + else: + logger.error(f"Received invalid JSON-RPC payload: {decoded_payload}") + return + + async def request_data(self, request_msg: JsonRpcRequest) -> JsonRpcResponse: + """ + Request data from the client asynchronously, waiting for a response. + Returns: + Any: The data from the client + """ + + future_response = asyncio.get_event_loop().create_future() + self._future_responses[request_msg["id"]] = future_response + + # Send the request as a JSON-RPC message + self.send_message(json.dumps(request_msg)) + + # Wait for the response + result = await future_response + del self._future_responses[request_msg["id"]] + + return result + + def request_data_sync( + self, request_msg: JsonRpcRequest, timeout: float = 1.0 + ) -> JsonRpcResponse: + """ + Synchronously request data from the client via JSON-RPC, blocking until a response is received. + Args: + method: The JSON-RPC method name + params: The parameters to send + timeout: Timeout in seconds + Returns: + The JSON-RPC response from the client + Raises: + RuntimeError: If called from an active event loop + """ + + async def do_request(): + try: + return await asyncio.wait_for(self.request_data(request_msg), timeout) + except Exception as ex: + logger.error("Error during request_data_sync:", ex) + del self._future_responses[request_msg["id"]] + raise + + try: + running = asyncio.get_running_loop().is_running() + except RuntimeError: + running = False + + if running: + raise RuntimeError( + "Cannot call request_data_sync from an active event loop" + ) + + # TODO: Do we need to run on a separate thread to avoid deadlocks? + return asyncio.run(do_request()) + + def on_close(self) -> None: + """ + Close the connection + """ + logger.info("Closing connection", self.id) + self._deregister_meta_path_finder() + self._plugin = None diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py new file mode 100644 index 000000000..d6205b337 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py @@ -0,0 +1,91 @@ +from importlib.machinery import ModuleSpec +from types import ModuleType +from typing import Optional, Sequence + +from .plugin_object import PluginObject +from .json_rpc import create_request_msg +from .logger import Logger +from .types import LocalModuleDescriptor, MessageStreamRequestInterface + + +logger = Logger("RemoteMetaPathFinder") + + +class RemoteModuleLoader: + """ + A custom module loader that loads modules from a remote source. + """ + + _module_descriptor: LocalModuleDescriptor | None + + def __init__(self, module_descriptor: LocalModuleDescriptor | None): + self._module_descriptor = module_descriptor + + def create_module(self, spec: ModuleSpec): + return None + + def exec_module(self, module: ModuleType): + if self._module_descriptor is None: + return + + source = self._module_descriptor.get("source") + if source is None: + return + + filepath = self._module_descriptor.get("filepath") + + exec(compile(source, filepath, "exec"), module.__dict__) + + +class RemoteMetaPathFinder: + """ + A custom meta path finder that finds modules that can be sourced remotely. + """ + + _connection: MessageStreamRequestInterface | None = None + _plugin: PluginObject + + def __init__(self, connection: MessageStreamRequestInterface, plugin: PluginObject): + self._connection = connection + self._plugin = plugin + + def find_spec( + self, + fullname: str, + path: Optional[Sequence[str]], + target: Optional[ModuleType] = None, + ): + if not self._connection or not self._plugin.is_sourced_by_execution_context( + fullname, self._connection.id + ): + # return None so that other finder/loaders can try + return None + + module_spec: LocalModuleDescriptor | None = None + + try: + msg = create_request_msg("fetch_module", {"module_name": fullname}) + response = self._connection.request_data_sync(msg) + except Exception as err: + logger.error("Error finding external module spec:", fullname, err) + raise + + module_spec = response.get("result") + if module_spec is None: + logger.info("Module spec not found:", fullname) + return + + logger.info( + "Fetched module spec:", + fullname, + "source" if module_spec.get("source") else "None", + ) + + origin = module_spec.get("filepath") if module_spec else None + + return ModuleSpec( + name=fullname, + loader=RemoteModuleLoader(module_spec), # type: ignore + origin=origin, + is_package=True, + ) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py new file mode 100644 index 000000000..3201341e0 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py @@ -0,0 +1,70 @@ +from __future__ import annotations +import sys +from typing import Optional + + +class PluginObject: + execution_context_connection_id: Optional[str] = None + _top_level_module_fullnames: set[str] = set() + + """ + Plugin object that holds state for the plugin. + + Attributes: + execution_context_connection_id: Optional[str]: The connection id of the current execution context + _top_level_module_fullnames: set[str]: The set of top level module fullnames that can be sourced by the client + """ + + def __init__(self): + pass + + def evict_module_cache(self) -> None: + """ + Evict any cached modules that were loaded from the `RemoteModuleLoader`. + """ + for mod_name in list(sys.modules.keys()): + if self.is_sourced_by_execution_context( + mod_name, self.execution_context_connection_id + ): + del sys.modules[mod_name] + + def get_top_level_module_fullnames(self) -> set[str]: + """ + Get the set of top level module fullnames that can be sourced by the client. + """ + return self._top_level_module_fullnames + + def is_sourced_by_execution_context( + self, module_fullname: str, connection_id: Optional[str] + ) -> bool: + """ + Check if a module fullname is included in the registered top-level module + names and that the given connection id matches the current execution context. + """ + if ( + connection_id is None + or connection_id != self.execution_context_connection_id + ): + return False + + if self._top_level_module_fullnames is None: + return False + + for top_level_name in self._top_level_module_fullnames: + if module_fullname == top_level_name or module_fullname.startswith( + top_level_name + "." + ): + return True + + return False + + def set_execution_context( + self, connection_id: Optional[str], top_level_module_fullnames: set[str] + ) -> None: + """ + Set the execution context for the object. This includes the set of top + level module fullnames that can be sourced by the client. + """ + self.evict_module_cache() + self.execution_context_connection_id = connection_id + self._top_level_module_fullnames = top_level_module_fullnames diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py new file mode 100644 index 000000000..2dd728017 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from typing import Any +from deephaven.plugin.object_type import BidirectionalObjectType + +from .message_stream import MessageStream +from .plugin_object import PluginObject + + +# The object type that will be registered with the plugin system. +# The object is bidirectional, meaning it can send messages to and from the client. +# A MessageStream is created for each object that is created. This needs to be saved and tied to the object. +# The value returned by name() should match supportedTypes in DeephavenLocalExecPluginPlugin.ts +class PluginType(BidirectionalObjectType): + """ + Defines the Element type for the Deephaven plugin system. + """ + + @property + def name(self) -> str: + """ + Get the name of the object type + + Returns: + str: The name of the object + """ + # this name should match the supportedTypes in PythonRemoteFileSourcePlugin.ts + return "DeephavenPythonRemoteFileSourcePlugin" + + def is_type(self, obj: Any) -> bool: + """ + Check if the object is an instance of the type that this plugin supports + + Args: + obj: The object to check + + Returns: + bool: True if the object is an instance of the type that this plugin supports + """ + # check if the object is an instance of the type that this plugin supports + # replace this with other objects or add additional checks as needed + return isinstance(obj, PluginObject) + + def create_client_connection( + self, obj: PluginObject, connection: MessageStream + ) -> MessageStream: + """ + Create a client connection for the object + + Args: + obj: The object to create the connection for + connection: The connection to the client + + Returns: + MessageStream: The connection to the client + """ + # Create the message stream for the object that can be used to send and receive messages + # Note that each object will have its own message stream + message_stream = MessageStream(obj, connection) + return message_stream diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/register.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/register.py new file mode 100644 index 000000000..b0e2268b3 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/register.py @@ -0,0 +1,23 @@ +from deephaven.plugin import Registration, Callback +from deephaven.plugin.utilities import create_js_plugin, DheSafeCallbackWrapper + +from .plugin_type import PluginType + +# The namespace that the Python plugin will be registered under. +PACKAGE_NAMESPACE = "deephaven.python_remote_file_source" +# Where the Javascript plugin is. This is set in setup.py. +JS_NAME = "_js" + + +class PluginRegistration(Registration): + @classmethod + def register_into(cls, callback: Callback) -> None: + callback = DheSafeCallbackWrapper(callback) + + # Register the Python plugin + callback.register(PluginType) + + # The JavaScript plugin requires a special registration process, which is handled here + js_plugin = create_js_plugin(PACKAGE_NAMESPACE, JS_NAME) + + callback.register(js_plugin) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py new file mode 100644 index 000000000..5ba54aba7 --- /dev/null +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py @@ -0,0 +1,63 @@ +from typing import Any, Literal, Optional, Protocol, TypedDict, Union + + +class JsonRpcRequest(TypedDict): + jsonrpc: Literal["2.0"] + id: str + method: str + params: dict + + +class JsonRpcSuccess(TypedDict): + jsonrpc: Literal["2.0"] + id: str + result: Any + + +class JsonRpcError(TypedDict): + jsonrpc: Literal["2.0"] + id: str + error: dict + + +JsonRpcResponse = Union[JsonRpcSuccess, JsonRpcError] + + +class LocalModuleDescriptor(TypedDict): + filepath: str + source: Optional[str] + + +class MessageStreamRequestInterface(Protocol): + id: str + + async def request_data(self, request_msg: JsonRpcRequest) -> JsonRpcResponse: + """ + Asynchronously send a JSON-RPC request to the client and wait for a response. + Args: + request_msg: The JSON-RPC request message to send to the client. + Returns: + The JSON-RPC response from the client (either result or error). + """ + ... + + def request_data_sync( + self, request_msg: JsonRpcRequest, timeout: Optional[float] = None + ) -> JsonRpcResponse: + """ + Synchronously send a JSON-RPC request to the client and block until a response is received. + Args: + request_msg: The JSON-RPC request message to send to the client. + timeout: Optional timeout in seconds to wait for a response. + Returns: + The JSON-RPC response from the client (either result or error). + """ + ... + + def send_message(self, message: str) -> None: + """ + Send a message to the client. + Args: + message: The message to send. + """ + ... diff --git a/plugins/python-remote-file-source/src/js/.eslintrc.js b/plugins/python-remote-file-source/src/js/.eslintrc.js new file mode 100644 index 000000000..aad277126 --- /dev/null +++ b/plugins/python-remote-file-source/src/js/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + root: true, + extends: ['@deephaven/eslint-config'], + overrides: [ + { + files: ['**/*.@(ts|tsx)'], + parserOptions: { + project: ['./tsconfig.json'], + tsconfigRootDir: __dirname, + }, + }, + ], +}; diff --git a/plugins/python-remote-file-source/src/js/.gitignore b/plugins/python-remote-file-source/src/js/.gitignore new file mode 100644 index 000000000..d22612a8d --- /dev/null +++ b/plugins/python-remote-file-source/src/js/.gitignore @@ -0,0 +1,5 @@ +# Ignore npm dependencies +/node_modules + +# Ignore output directory +/dist diff --git a/plugins/python-remote-file-source/src/js/.nvmrc b/plugins/python-remote-file-source/src/js/.nvmrc new file mode 100644 index 000000000..a2ad731bb --- /dev/null +++ b/plugins/python-remote-file-source/src/js/.nvmrc @@ -0,0 +1 @@ +v18.20.4 \ No newline at end of file diff --git a/plugins/python-remote-file-source/src/js/package.json b/plugins/python-remote-file-source/src/js/package.json new file mode 100644 index 000000000..0a123f00f --- /dev/null +++ b/plugins/python-remote-file-source/src/js/package.json @@ -0,0 +1,45 @@ +{ + "name": "@deephaven/js-plugin-python-remote-file-source", + "version": "0.0.1", + "description": "Deephaven plugin for sourcing Python files from a remote location", + "keywords": [ + "Deephaven", + "plugin" + ], + "author": "deephaven", + "license": "Apache-2.0", + "main": "dist/index.js", + "scripts": { + "start": "vite build --watch", + "build": "vite build" + }, + "devDependencies": { + "@deephaven/tsconfig": "^0.72.0", + "@types/react": "^17.0.2", + "@vitejs/plugin-react-swc": "^3.0.0", + "@types/react-dom": "^17.0.2", + "react": "^17.0.2", + "typescript": "^4.5.4", + "vite": "~4.1.4" + }, + "peerDependencies": { + "react": "^17.0.2", + "react-dom": "^17.0.2" + }, + "dependencies": { + "@deephaven/components": "^0.85.0", + "@deephaven/dashboard": "^0.85.0", + "@deephaven/icons": "^0.85.0", + "@deephaven/jsapi-bootstrap": "^0.85.0", + "@deephaven/jsapi-types": "1.0.0-dev0.35.2", + "@deephaven/log": "^0.85.0", + "@deephaven/plugin": "^0.85.0", + "@fortawesome/react-fontawesome": "^0.2.0" + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist/index.js" + ] +} diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts new file mode 100644 index 000000000..1ca3c4ef3 --- /dev/null +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts @@ -0,0 +1,20 @@ +import { type WidgetPlugin, PluginType } from '@deephaven/plugin'; +import { vsGraph } from '@deephaven/icons'; +import { PythonRemoteFileSourcePluginView } from './PythonRemoteFileSourcePluginView'; + +// Register the plugin with Deephaven +export const PythonRemoteFileSourcePlugin: WidgetPlugin = { + // The name of the plugin + name: '@deephaven/js-plugin-python-remote-file-source', + // The type of plugin - this will generally be WIDGET_PLUGIN + type: PluginType.WIDGET_PLUGIN, + // The supported types for the plugin. This should match the value returned by `name` + // in DeephavenLocalExecPluginType in plugin_type.py + supportedTypes: 'DeephavenPythonRemoteFileSourcePlugin', + // The component to render for the plugin + component: PythonRemoteFileSourcePluginView, + // The icon to display for the plugin + icon: vsGraph, +}; + +export default PythonRemoteFileSourcePlugin; diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx new file mode 100644 index 000000000..3aa69323f --- /dev/null +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx @@ -0,0 +1,108 @@ +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { useApi } from '@deephaven/jsapi-bootstrap'; +import { vsRefresh } from '@deephaven/icons'; +import Log from '@deephaven/log'; +import { WidgetComponentProps } from '@deephaven/plugin'; +import type { dh as DhType } from '@deephaven/jsapi-types'; +import { + ActionButton, + DebouncedSearchInput, + Flex, + Heading, + Icon, + ListView, +} from '@deephaven/components'; + +const REQUEST_PLUGIN_INFO_MSG = { + jsonrpc: '2.0', + id: '0', + method: 'request_plugin_info', +} as const; + +const log = Log.module( + '@deephaven/js-plugin-python-remote-file-source.DeephavenPythonRemoteFileSourcePluginView' +); + +export function PythonRemoteFileSourcePluginView( + props: WidgetComponentProps +): JSX.Element { + const { fetch } = props; + const [items, setItems] = useState([]); + const [searchText, setSearchText] = useState(''); + const [widget, setWidget] = useState(null); + const dh = useApi(); + + const autoFocusRef = useCallback((input: DebouncedSearchInput | null) => { + input?.focus(); + }, []); + + const searchTextLc = useMemo(() => searchText.toLowerCase(), [searchText]); + const filteredItems = useMemo( + () => + searchTextLc === '' + ? items + : items.filter(item => item.toLowerCase().includes(searchTextLc)), + [items, searchTextLc] + ); + + useEffect(() => { + async function init() { + // Fetch the widget from the server + const fetchedWidget = (await fetch()) as DhType.Widget; + setWidget(fetchedWidget); + + // Add an event listener to the widget to listen for messages from the server + fetchedWidget.addEventListener( + dh.Widget.EVENT_MESSAGE, + ({ detail }) => { + try { + const pluginInfo: { result: { full_names: string[] } } = JSON.parse( + detail.getDataAsString() + ); + const fullNames = pluginInfo.result.full_names.sort(); + setItems(fullNames); + } catch (err) { + log.error('Error handling message', err); + } + } + ); + + fetchedWidget.sendMessage(JSON.stringify(REQUEST_PLUGIN_INFO_MSG), []); + } + + init(); + }, [dh, fetch]); + + const onRefresh = useCallback(() => { + // Send the message to the server via the widget + if (widget != null) { + setItems([]); + widget.sendMessage(JSON.stringify(REQUEST_PLUGIN_INFO_MSG), []); + } + }, [widget]); + + // Render a component with the text and a form to send a message to the server + return ( + + + + Remote Modules + + + + + + + + + {filteredItems} + + ); +} + +export default PythonRemoteFileSourcePluginView; diff --git a/plugins/python-remote-file-source/src/js/src/index.ts b/plugins/python-remote-file-source/src/js/src/index.ts new file mode 100644 index 000000000..6ed8b9b63 --- /dev/null +++ b/plugins/python-remote-file-source/src/js/src/index.ts @@ -0,0 +1,3 @@ +import { PythonRemoteFileSourcePlugin } from './PythonRemoteFileSourcePlugin'; + +export default PythonRemoteFileSourcePlugin; diff --git a/plugins/python-remote-file-source/src/js/src/vite-env.d.ts b/plugins/python-remote-file-source/src/js/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/plugins/python-remote-file-source/src/js/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/plugins/python-remote-file-source/src/js/tsconfig.json b/plugins/python-remote-file-source/src/js/tsconfig.json new file mode 100644 index 000000000..baed111e0 --- /dev/null +++ b/plugins/python-remote-file-source/src/js/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "@deephaven/tsconfig", + "compilerOptions": { + "composite": false, + "rootDir": "src/", + "outDir": "dist/", + "types": [], + "emitDeclarationOnly": false, + "noEmit": false + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["**/node_modules/**/*", "dist/**/*"] +} diff --git a/plugins/python-remote-file-source/src/js/vite.config.js b/plugins/python-remote-file-source/src/js/vite.config.js new file mode 100644 index 000000000..a5d534830 --- /dev/null +++ b/plugins/python-remote-file-source/src/js/vite.config.js @@ -0,0 +1,33 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react-swc'; + +// https://vitejs.dev/config/ +export default defineConfig(({ mode }) => ({ + build: { + minify: false, + lib: { + entry: './src/index.ts', + fileName: () => 'index.js', + formats: ['cjs'], + }, + rollupOptions: { + external: [ + 'react', + 'react-dom', + 'redux', + 'react-redux', + // Externalize all Deephaven dependencies to reduce bundle size and maintain proper context for themes, etc. + '@deephaven/components', + '@deephaven/dashboard', + '@deephaven/icons', + '@deephaven/jsapi-bootstrap', + '@deephaven/jsapi-types', + '@deephaven/log', + '@deephaven/plugin' + ], + }, + }, + define: + mode === 'production' ? { 'process.env.NODE_ENV': '"production"' } : {}, + plugins: [react()], +})); From 5a006554431334961ae73505f261cd04fccbd4f4 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 2 Oct 2025 14:37:51 -0500 Subject: [PATCH 02/40] cleanup (#DH-19715) --- .../plugin_builder.py | 411 ------------------ plugins/python-remote-file-source/setup.cfg | 15 +- .../src/PythonRemoteFileSourcePluginView.tsx | 2 +- 3 files changed, 14 insertions(+), 414 deletions(-) delete mode 100644 plugins/python-remote-file-source/plugin_builder.py diff --git a/plugins/python-remote-file-source/plugin_builder.py b/plugins/python-remote-file-source/plugin_builder.py deleted file mode 100644 index 71cd7d20e..000000000 --- a/plugins/python-remote-file-source/plugin_builder.py +++ /dev/null @@ -1,411 +0,0 @@ -from __future__ import annotations - -import click -import os -import sys -from typing import Generator, Callable -import time -import subprocess -from watchdog.events import FileSystemEvent, RegexMatchingEventHandler -from watchdog.observers import Observer -import threading - -# get the directory of the current file -# this is used to watch for changes in this directory -current_dir = os.path.dirname(os.path.abspath(__file__)) - -# these are the patterns to watch for changes in this directory -# if in editable mode, the builder will rerun when these files change -REBUILD_REGEXES = [ - r".*\.py$", - r".*\.js$", - r".*\.ts$", - r".*\.tsx$", - r".*\.scss$", -] - -# ignore these patterns in particular -# prevents infinite loops when the builder is rerun -IGNORE_REGEXES = [ - r".*/dist/.*", - r".*/build/.*", - r".*/node_modules/.*", - r".*/_js/.*", - r".*/src/node/.*", - r".*/test_ws/.*$", - # ignore hidden files and directories - r".*/\..*/.*", -] - -# the path where the python files are located relative to this script -# modify this if the python files are moved -PYTHON_DIR = "." -# the path where the JS files are located relative to this script -# modify this if the JS files are moved -JS_DIR = "./src/js" - - -class PluginsChangedHandler(RegexMatchingEventHandler): - """ - A handler that watches for changes and reruns the function when changes are detected - - Args: - func: The function to run when changes are detected - stop_event: The event to signal the function to stop - - Attributes: - func: The function to run when changes are detected - stop_event: The event to signal the function to stop - rerun_lock: A lock to prevent multiple reruns from occurring at the same time - """ - - def __init__(self, func: Callable, stop_event: threading.Event) -> None: - super().__init__(regexes=REBUILD_REGEXES, ignore_regexes=IGNORE_REGEXES) - - self.func = func - - # A flag to indicate whether the function should continue running - # Also prevents unnecessary reruns - self.stop_event = stop_event - - # A lock to prevent multiple reruns from occurring at the same time - self.rerun_lock = threading.Lock() - - # always have an initial run - threading.Thread(target=self.attempt_rerun).start() - - def attempt_rerun(self) -> None: - """ - Attempt to rerun the function. - If the stop event is set, do not rerun because a rerun has already been scheduled. - """ - self.stop_event.set() - with self.rerun_lock: - self.stop_event.clear() - self.func() - - def event_handler(self, event: FileSystemEvent) -> None: - """ - Handle any file system event - - Args: - event: The event that occurred - """ - if self.stop_event.is_set(): - # a rerun has already been scheduled on another thread - print( - f"File {event.src_path} {event.event_type}, rerun has already been scheduled" - ) - return - print(f"File {event.src_path} {event.event_type}, new rerun scheduled") - threading.Thread(target=self.attempt_rerun).start() - - def on_created(self, event: FileSystemEvent) -> None: - """ - Handle a file creation event - - Args: - event: The event that occurred - """ - self.event_handler(event) - - def on_deleted(self, event: FileSystemEvent) -> None: - """ - Handle a file deletion event - - Args: - event: The event that occurred - """ - self.event_handler(event) - - def on_modified(self, event: FileSystemEvent) -> None: - """ - Handle a file modification event - - Args: - event: The event that occurred - """ - self.event_handler(event) - - def on_moved(self, event: FileSystemEvent) -> None: - """ - Handle a file move event - - Args: - event: The event that occurred - - Returns: - - """ - self.event_handler(event) - - -def clean_build_dist() -> None: - """ - Remove the build and dist directories. - """ - # these folders may not exist, so ignore the errors - if os.path.exists(f"{PYTHON_DIR}/build"): - os.system(f"rm -rf {PYTHON_DIR}/build") - if os.path.exists(f"{PYTHON_DIR}/dist"): - os.system(f"rm -rf {PYTHON_DIR}/dist") - - -def run_command(command: str) -> None: - """ - Run a command and exit if it fails. - This should only be used in a non-main thread. - - Args: - command: The command to run. - - Returns: - None - """ - code = os.system(command) - if code != 0: - os._exit(1) - - -def run_build() -> None: - """ - Build the plugin - """ - - clean_build_dist() - - click.echo(f"Building plugin") - run_command(f"python -m build --wheel {PYTHON_DIR}") - - -def run_install( - reinstall: bool, -) -> None: - """ - Install plugins that have been built - - Args: - reinstall: Whether to reinstall the plugins. - If True, the --force-reinstall and --no-deps flags are added to pip install. - - Returns: - None - """ - install = "pip install" - if reinstall: - install += " --force-reinstall --no-deps" - - click.echo("Installing plugin") - run_command(f"{install} {PYTHON_DIR}/dist/*.whl") - - -def run_build_js() -> None: - """ - Build the JS files for the plugin - """ - click.echo(f"Building the JS plugin") - run_command(f"npm run build --prefix {JS_DIR}") - - -def build_server_args(server_arg: tuple[str]) -> list[str]: - """ - Build the server arguments to pass to the deephaven server - By default, the --no-browser flag is added to the server arguments unless the --browser flag is present - - Args: - server_arg: The arguments to pass to the server - """ - server_args = ["--no-browser"] - if server_arg: - if "--no-browser" in server_arg or "--browser" in server_arg: - server_args = list(server_arg) - else: - server_args = server_args + list(server_arg) - return server_args - - -def handle_args( - build: bool, - install: bool, - reinstall: bool, - server: bool, - server_arg: tuple[str], - js: bool, - stop_event: threading.Event, -) -> None: - """ - Handle all arguments for the builder command - - Args: - build: True to build the plugins - install: True to install the plugins - reinstall: True to reinstall the plugins - server: True to run the deephaven server after building and installing the plugins - server_arg: The arguments to pass to the server - js: True to build the JS files for the plugins - stop_event: The event to signal the function to stop - """ - # it is possible that the stop event is set before this function is called - if stop_event.is_set(): - return - - # default is to install, but don't if just configuring - if not any([build, install, reinstall, js]): - js = True - install = True - - # if this thread is signaled to stop, return after the current command - # instead of in the middle of a command, which could leave the environment in a bad state - if stop_event.is_set(): - return - - if js: - run_build_js() - - if stop_event.is_set(): - return - - if build or install or reinstall: - run_build() - - if stop_event.is_set(): - return - - if install or reinstall: - run_install(reinstall) - - if stop_event.is_set(): - return - - if server or server_arg: - server_args = build_server_args(server_arg) - - click.echo(f"Running deephaven server with args: {server_args}") - process = subprocess.Popen(["deephaven", "server"] + server_args) - - # waiting on either the process to finish or the stop event to be set - while not stop_event.wait(1): - poll = process.poll() - if poll is not None: - # process threw an error or was killed, so exit - os._exit(process.returncode) - - # stop event is set, so kill the process - process.terminate() - try: - process.wait(timeout=1) - except subprocess.TimeoutExpired: - process.kill() - process.wait() - - -@click.command( - short_help="Build and install plugin.", - help="Build and install plugins. " - "By default, all plugins with the necessary file are used unless specified via the plugins arg.", -) -@click.option("--build", "-b", is_flag=True, help="Build the plugin.") -@click.option( - "--install", - "-i", - is_flag=True, - help="Install the plugin. This is the default behavior if no flags are provided.", -) -@click.option( - "--reinstall", - "-r", - is_flag=True, - help="Reinstall the plugin. " - "This adds the --force-reinstall and --no-deps flags to pip install. " - "Useful if the plugin has already been installed and does not have a new version number.", -) -@click.option( - "--server", - "-s", - is_flag=True, - help="Run the deephaven server after building and installing the plugin.", -) -@click.option( - "--server-arg", - "-sa", - default=tuple(), - multiple=True, - help="Run the deephaven server after building and installing the plugin with the provided argument.", -) -@click.option( - "--js", - "-j", - is_flag=True, - help="Build the JS files for the plugin.", -) -@click.option( - "--watch", - "-w", - is_flag=True, - help="Run the other provided commands in an editable-like mode, watching for changes " - "This will rerun all other commands (except configure) when files are changed. " - "The top level directory of this project is watched.", -) -def builder( - build: bool, - install: bool, - reinstall: bool, - server: bool, - server_arg: tuple[str], - js: bool, - watch: bool, -) -> None: - """ - Build and install plugins. - - Args: - build: True to build the plugin - install: True to install the plugin - reinstall: True to reinstall the plugin - server: True to run the deephaven server after building and installing the plugin - server_arg: The arguments to pass to the server - js: True to build the JS files for the plugin - watch: True to rerun the other commands when files are changed - """ - stop_event = threading.Event() - - def run_handle_args() -> None: - """ - Run the handle_args function with the provided arguments - """ - handle_args( - build, - install, - reinstall, - server, - server_arg, - js, - stop_event, - ) - - if not watch: - # since editable is not specified, only run the handler once - # call it from a thread to allow the usage of os._exit to exit the process - # rather than sys.exit because sys.exit will not exit the process when called from a thread - # and os._exit should be called from a thread - thread = threading.Thread(target=run_handle_args) - thread.start() - thread.join() - return - - # editable is specified, so run the handler in a loop that watches for changes and - # reruns the handler when changes are detected - event_handler = PluginsChangedHandler(run_handle_args, stop_event) - observer = Observer() - observer.schedule(event_handler, current_dir, recursive=True) - observer.start() - try: - while True: - input() - finally: - observer.stop() - observer.join() - - -if __name__ == "__main__": - builder() diff --git a/plugins/python-remote-file-source/setup.cfg b/plugins/python-remote-file-source/setup.cfg index 37a94a1c7..e2ec0877f 100644 --- a/plugins/python-remote-file-source/setup.cfg +++ b/plugins/python-remote-file-source/setup.cfg @@ -4,9 +4,20 @@ description = Deephaven plugin for sourcing Python files from a remote location long_description = file: README.md long_description_content_type = text/markdown version = 0.0.1.dev0 +url = https://github.com/deephaven/deephaven-plugins +project_urls = + Source Code = https://github.com/deephaven/deephaven-plugins + Bug Tracker = https://github.com/deephaven/deephaven-plugins/issues +classifiers = + Programming Language :: Python :: 3 + License :: OSI Approved :: Apache Software License + Operating System :: OS Independent + Environment :: Plugins + Topic :: Scientific/Engineering :: Visualization + Development Status :: 3 - Alpha keywords = deephaven, plugin, graph -author = deephaven -author_email = Anonymous +author = Deephaven Data Labs +author_email = support@deephaven.io platforms = any [options] diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx index 3aa69323f..83da28039 100644 --- a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx @@ -21,7 +21,7 @@ const REQUEST_PLUGIN_INFO_MSG = { } as const; const log = Log.module( - '@deephaven/js-plugin-python-remote-file-source.DeephavenPythonRemoteFileSourcePluginView' + '@deephaven/js-plugin-python-remote-file-source/DeephavenPythonRemoteFileSourcePluginView' ); export function PythonRemoteFileSourcePluginView( From cd974de0a41f960be1bed57049da32fc0c828495 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 2 Oct 2025 14:44:41 -0500 Subject: [PATCH 03/40] latest package-lock (#DH-19715) --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba72eb24b..3ef3e91de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4193,6 +4193,10 @@ "resolved": "plugins/plotly-express/src/js", "link": true }, + "node_modules/@deephaven/js-plugin-python-remote-file-source": { + "resolved": "plugins/python-remote-file-source/src/js", + "link": true + }, "node_modules/@deephaven/js-plugin-simple-pivot": { "resolved": "plugins/simple-pivot/src/js", "link": true @@ -15410,10 +15414,6 @@ "dev": true, "license": "MIT" }, - "node_modules/deephaven-python-remote-file-source-plugin": { - "resolved": "plugins/python-remote-file-source/src/js", - "link": true - }, "node_modules/deepmerge": { "version": "4.3.1", "dev": true, @@ -34367,7 +34367,7 @@ } }, "plugins/python-remote-file-source/src/js": { - "name": "deephaven-python-remote-file-source-plugin", + "name": "@deephaven/js-plugin-python-remote-file-source", "version": "0.0.1", "license": "Apache-2.0", "dependencies": { From 0ab9a4ed7b9aee683e1b025f33c7d05019266b3a Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 2 Oct 2025 15:15:48 -0500 Subject: [PATCH 04/40] Cleaned up docs (#DH-19715) --- plugins/python-remote-file-source/.gitignore | 3 +- plugins/python-remote-file-source/README.md | 49 +++- .../README_TEMPLATE.md | 213 ------------------ .../python-remote-file-source/docs/DESIGN.md | 57 ----- 4 files changed, 45 insertions(+), 277 deletions(-) delete mode 100644 plugins/python-remote-file-source/README_TEMPLATE.md delete mode 100644 plugins/python-remote-file-source/docs/DESIGN.md diff --git a/plugins/python-remote-file-source/.gitignore b/plugins/python-remote-file-source/.gitignore index af03e23eb..4da5acac4 100644 --- a/plugins/python-remote-file-source/.gitignore +++ b/plugins/python-remote-file-source/.gitignore @@ -6,5 +6,4 @@ dist/ .idea .DS_store __pycache__/ -node_modules -docs/*.html \ No newline at end of file +node_modules \ No newline at end of file diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md index 2d1174ca7..757ab2947 100644 --- a/plugins/python-remote-file-source/README.md +++ b/plugins/python-remote-file-source/README.md @@ -2,11 +2,50 @@ A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. -## Additional Docs +## Plugin Structure -- [docs/DESIGN.md](docs/DESIGN.md) - Notes on architecture / design. -- [README_TEMPLATE.md](README_TEMPLATE.md) - Template scafolded by original cookiecutter template. Will eventually delete once `README` is completed. +The `src` directory contains the Python and JavaScript code for the plugin. +Within the `src` directory, the `deephaven/python_remote_file_source` directory contains the Python code, and the `js` directory contains the JavaScript code. -## Dev +The Python files have the following structure: +`plugin_object.py` defines a simple Python class that can send messages to the client. This object can be modified to have other plugin functionality or replaced with a different object entirely, depending on the plugin's needs. +`plugin_type.py` defines the Python type for the plugin (which is used for registration) and a simple message stream. These can be modified to handle different objects or messages. An initial message is sent from the Python side to the client, then additional messages can be sent back and forth. +`register.py` registers the plugin with Deephaven. This file will not need to be modified for most plugins at the initial stages, but will need to be if the package is renamed or JavaScript files are moved. -A DH server can be started via `./scripts/dev.sh` (Note that this requires venv to be active and initial build to have been run at least once per the template docs) +The JavaScript files have the following structure: +`PythonRemoteFileSourcePlugin.ts` registers the plugin with Deephaven. This contains the client equivalent of the type in `plugin_type.py` and these should be kept in sync. +`PythonRemoteFileSourcePluginView.tsx` defines the plugin panel and message handling. This is where messages are received when sent from the Python side of the plugin. This file is a good starting point for adding more complex plugin functionality. + +Additionally, the `test` directory contains Python tests for the plugin. +It's recommended to use `tox` to run the tests, and the `tox.ini` file is included in the project. + +## Building the Plugin + +Use the [`plugin_builder.py`](../../README.md#using-plugin_builderpy) from the root directory to build the plugin. + +## Installing the Plugin + +The plugin can be installed into a Deephaven instance with `pip install `. +The wheel file is stored in the `dist` directory after building the plugin. +Exactly how this is done will depend on how you are running Deephaven. +If using the venv created above, the plugin and server can be created with the following commands: +```sh +pip install deephaven-server +pip install dist/deephaven_python_remote_file_source-0.0.1.dev0-py3-none-any.whl +deephaven server +``` +See the [plug-in documentation](https://deephaven.io/core/docs/how-to-guides/install-use-plugins/) for more information. + +## Using the Plugin + +Once the Deephaven server is running, the plugin should be available to use. + +```python +from deephaven.python_remote_file_source_plugin import ( + PluginObject as DeephavenRemoteFileSourcePlugin, +) + +obj = DeephavenRemoteFileSourcePlugin() +``` + +A panel should appear. diff --git a/plugins/python-remote-file-source/README_TEMPLATE.md b/plugins/python-remote-file-source/README_TEMPLATE.md deleted file mode 100644 index a4dae1253..000000000 --- a/plugins/python-remote-file-source/README_TEMPLATE.md +++ /dev/null @@ -1,213 +0,0 @@ -# deephaven_python_remote_file_source - -This is a Python plugin for Deephaven generated from a [deephaven-plugin](https://github.com/deephaven/deephaven-plugins) template. - -Specifically, this plugin is a bidirectional widget plugin, which can send and receive messages on both the client and server. -The plugin works out of the box, demonstrates basic plugin structure, and can be used as a starting point for building more complex plugins. - -## Plugin Structure - -The `src` directory contains the Python and JavaScript code for the plugin. -Within the `src` directory, the `deephaven/python_remote_file_source` directory contains the Python code, and the `js` directory contains the JavaScript code. - -The Python files have the following structure: -`plugin_object.py` defines a simple Python class that can send messages to the client. This object can be modified to have other plugin functionality or replaced with a different object entirely, depending on the plugin's needs. -`plugin_type.py` defines the Python type for the plugin (which is used for registration) and a simple message stream. These can be modified to handle different objects or messages. An initial message is sent from the Python side to the client, then additional messages can be sent back and forth. -`register.py` registers the plugin with Deephaven. This file will not need to be modified for most plugins at the initial stages, but will need to be if the package is renamed or JavaScript files are moved. - -The JavaScript files have the following structure: -`PythonRemoteFileSourcePlugin.ts` registers the plugin with Deephaven. This contains the client equivalent of the type in `plugin_type.py` and these should be kept in sync. -`PythonRemoteFileSourcePluginView.tsx` defines the plugin panel and message handling. This is where messages are received when sent from the Python side of the plugin. This file is a good starting point for adding more complex plugin functionality. - -Additionally, the `test` directory contains Python tests for the plugin. This demonstrates how the embedded Deephaven server can be used in tests. -It's recommended to use `tox` to run the tests, and the `tox.ini` file is included in the project. - -## Using plugin_builder.py -The `plugin_builder.py` script is the recommended way to build the plugin. -See [Building the Plugin](#building-the-plugin) for more information if you want to build the plugin manually instead. - -To use `plugin_builder.py`, first set up your Python environment and install the required packages. -To build the plugin, you will need `npm` and `python` installed, as well as the `build` package for Python. -`nvm` is also strongly recommended, and an `.nvmrc` file is included in the project. -The script uses `watchdog` and `deephaven-server` for `--watch` mode and `--server` mode, respectively. -```sh -cd plugins/python-remote-file-source -python -m venv .venv -source .venv/bin/activate -pip install --upgrade -r requirements.txt -pip install deephaven-server watchdog - -cd src/js -nvm install -npm install -cd ../.. -``` - -First, run an initial install of the plugin: -This builds and installs the full plugin, including the JavaScript code. -```sh -python plugin_builder.py --install --js -``` - -After this, more advanced options can be used. -For example, if only iterating on the plugins with no version bumps, use the `--reinstall` flag for faster builds. -This adds `--force-reinstall --no-deps` to the `pip install` command. -```sh -python plugin_builder.py --reinstall --js -``` - -If only the Python code has changed, the `--js` flag can be omitted. -```sh -python plugin_builder.py --reinstall -``` - -Additional especially useful flags are `--watch` and `--server`. -`--watch` will watch the Python and JavaScript files for changes and rebuild the plugin when they are modified. -`--server` will start the Deephaven server with the plugin installed. -Taken in combination with `--reinstall` and `--js`, this command will rebuild and restart the server when changes are made to the plugin. -```sh -python plugin_builder.py --reinstall --js --watch --server -``` - -If interested in passing args to the server, the `--server-arg` flag can be used as well -Check `deephaven server --help` for more information on the available arguments. -```sh -python plugin_builder.py --reinstall --js --watch --server --server-arg --port=9999 -``` - -See [Using the Plugin](#using-the-plugin) for more information on how to use the plugin. - -## Manually Building the Plugin - -To build the plugin, you will need `npm` and `python` installed, as well as the `build` package for Python. -`nvm` is also strongly recommended, and an `.nvmrc` file is included in the project. -The python venv can be created and the recommended packages installed with the following commands: -```sh -cd plugins/python-remote-file-source -python -m venv .venv -source .venv/bin/activate -pip install --upgrade -r requirements.txt -``` - -Build the JavaScript plugin from the `src/js` directory: - -```sh -cd src/js -nvm install -npm install -npm run build -``` - -Then, build the Python plugin from the top-level directory: - -```sh -cd ../.. -python -m build --wheel -``` - -The built wheel file will be located in the `dist` directory. - -If you modify the JavaScript code, remove the `build` and `dist` directories before rebuilding the wheel: -```sh -rm -rf build dist -``` - -## Installing the Plugin - -The plugin can be installed into a Deephaven instance with `pip install `. -The wheel file is stored in the `dist` directory after building the plugin. -Exactly how this is done will depend on how you are running Deephaven. -If using the venv created above, the plugin and server can be created with the following commands: -```sh -pip install deephaven-server -pip install dist/deephaven_python_remote_file_source-0.0.1.dev0-py3-none-any.whl -deephaven server -``` -See the [plug-in documentation](https://deephaven.io/core/docs/how-to-guides/install-use-plugins/) for more information. - -## Using the Plugin - -Once the Deephaven server is running, the plugin should be available to use. - -```python -from deephaven.python_remote_file_source_plugin import ( - PluginObject as DeephavenRemoteFileSourcePlugin, -) - -obj = DeephavenRemoteFileSourcePlugin() -``` - -A panel should appear. You can now use the object to send messages to the client. - -```python -obj.send_message("Hello, world!") -``` - -The panel can also send messages back to the Python client by using the input field. - -## Debugging the Plugin -It's recommended to run through all the steps in [Using plugin_builder.py](#Using-plugin_builder.py) and [Using the Plugin](#Using-the-plugin) to ensure the plugin is working correctly. -Then, make changes to the plugin and rebuild it to see the changes in action. -Checkout the [Deephaven plugins repo](https://github.com/deephaven/deephaven-plugins), which is where this template was generated from, for more examples and information. -The `plugins` folder contains current plugins that are developed and maintained by Deephaven. -Below are some common issues and how to resolve them as you develop your plugin. -If there is an issue with the process while following the Installation and Usage steps on the originally generated plugin, please open an issue. - -### The Panel is Not Appearing -#### Checking if the Plugin is Registered -If the panel is not appearing or an error is thrown that the import is not found, the plugin may not be registered correctly. -To verify the plugin is registered, check either the console logs or the versions in the settings panel. -- In the console logs, there should be a messaging saying `Plugins loaded:` with a map that includes this plugin. -![plugin map](./_assets/plugin_map.png "Plugin Map") - -- To get to the settings panel, click on the gear icon in the top right corner of the Deephaven window. Towards the bottom this plugin should be listed. -![plugin settings](./_assets/plugin_settings.png "Plugin Settings") -- If the plugin is not listed, attempt to rebuild and reinstall the plugin and check for errors during that process. - -#### Checking if the Python Package is Installed -- Running `pip list` in the `.venv` environment should show the Python package installed, but this is not a guarantee that the plugin is registered properly. -- The version can also be checked directly from the Python console with: -```{python} -from importlib.metadata import version -print(version("deephaven_python_remote_file_source")) -``` - -### The Panel is Appearing but with Errors or Not Functioning Correctly -Check both the Python and JavaScript logs for errors as either side could be causing the issue. - -## Distributing the Plugin -To distribute the plugin, you can upload the wheel file to a package repository, such as [PyPI](https://pypi.org/). -The version of the plugin can be updated in the `setup.cfg` file. - -There is a separate instance of PyPI for testing purposes. -Start by creating an account at [TestPyPI](https://test.pypi.org/account/register/). -Then, get an API token from [account management](https://test.pypi.org/manage/account/#api-tokens), setting the “Scope” to “Entire account”. - -To upload to the test instance, use the following commands: -```sh -python -m pip install --upgrade twine -python -m twine upload --repository testpypi dist/* -``` - -Now, you can install the plugin from the test instance. The extra index is needed to find dependencies: -```sh -pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ deephaven_python_remote_file_source -``` - -For a production release, create an account at [PyPI](https://pypi.org/account/register/). -Then, get an API token from [account management](https://pypi.org/manage/account/#api-tokens), setting the “Scope” to “Entire account”. - -To upload to the production instance, use the following commands. -Note that `--repository` is the production instance by default, so it can be omitted: -```sh -python -m pip install --upgrade twine -python -m twine upload dist/* -``` - -Now, you can install the plugin from the production instance: -```sh -pip install deephaven_python_remote_file_source -``` - -See the [Python packaging documentation](https://packaging.python.org/en/latest/tutorials/packaging-projects/#uploading-the-distribution-archives) for more information. - diff --git a/plugins/python-remote-file-source/docs/DESIGN.md b/plugins/python-remote-file-source/docs/DESIGN.md deleted file mode 100644 index 0c639abd3..000000000 --- a/plugins/python-remote-file-source/docs/DESIGN.md +++ /dev/null @@ -1,57 +0,0 @@ -# Deephaven Python Remote File Source Plugin - -A Deephaven bi-directional plugin to allow sourcing Python imports from the local filesystem. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. As part of initialization, a custom Python `sys.meta_path` finder and loader will be registered that will send messages to the client to request content for loading modules under a special module root. - -## Implementation - -### Python - -**DeephavenLocalExecPluginObject** - -- Deephaven Bi-directional plugin. -- Handles plugin registration + exposes message passing utils -- VS Code extension will use the JS API to run a snippet of Python code to initialize the plugin and assign it to a special variable. e.g. - - ```py - from deephaven.python_remote_file_source_plugin import PluginObject as DeephavenRemoteFileSourcePlugin - - __deephaven_vscode = DeephavenRemoteFileSourcePlugin() - ``` - -- VS Code can then fetch the object and subscribe to messages from the server - -**LocalMetaPathFinder class** - -- Instantiated with a "root" module name (e.g. `vscode`) defining the scope of module paths it will handle. e.g. A root of `vscode` would handle `vscode.module_a`, `vscode.module_b`, etc. -- Implements `find_spec`. Returns a `ModuleSpec` if it can handle the import. If so, this will also include an instance of `LocalModuleLoader`. -- Sends messages to clients running in user's local environment to request module source content. - - If available, clients will send source content back to the path finder. The path finder will then construct a `ModuleSpec` with a loader capable of serving the source. - - If not, will return `None` telling the import system to move on to next finder / loader - -> Note: `find_spec` is a synchronous api, but message passing between the local client and server plugin is asynchronous. We'll need to handle this somehow. Possibly with `asyncio` or some other blocking mechanism. - -**LocalModuleLoader class** - -- Responsible for executing the module source content and updating `module.__dict__` with the resulting variables. - -### VS Code Extension - -- After establishing a session, send a Python snippet to instantiate the plugin and assign to `__deephaven_vscode `if it isn't already assigned. Fetch the `__deephaven_vscode` object, and add an event listener for messages. -- Still need to figure out what happens if multiple clients are subscribed. This "might" only be possible in Community -- We probably will need to provide a way to specify the root folder to use for local module sourcing. The "root" used by the plugin will need to have the same name as the folder in VS Code in order for pylance to resolve imports locally for intellisense. There's also some pylance VS Code settings that can be tweaked to allow the workspace folder name to be found. e.g. "python.analysis.extraPaths": [".."]. Would be nice if DH extension can hhandle this automatically if the workspace root is the intended folder. For simpler config, we could just always require a subfolder and a way to specify that as the root, but this could be annoying if users don't want that assuming we can reasonably configure automatically for them. - -### Testing - -- Single root workspaces -- Multi root workspaces -- **init**.py modules -- Include / exclude folders -- Error handling. Timeouts + other - -### Questions - -- Can another user get access to filesystem. Seems yes without some sort of user check - yea -- Make sure VS Code will not serve modules that haven't been exposed / allowed -- Embed widget seems to not close connection when panel is closed -- Potential rename to "Remote module source" plugin From 779c9425f855c41b479b9bb974a8634e3bf5371c Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Mon, 6 Oct 2025 12:32:22 -0500 Subject: [PATCH 05/40] Fixed a bug in detecting is_package (#DH-19715) --- .../src/deephaven/python_remote_file_source/module_loader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py index d6205b337..ddb0c5ff2 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py @@ -82,10 +82,11 @@ def find_spec( ) origin = module_spec.get("filepath") if module_spec else None + is_package = origin is not None and origin.endswith("__init__.py") return ModuleSpec( name=fullname, loader=RemoteModuleLoader(module_spec), # type: ignore origin=origin, - is_package=True, + is_package=is_package, ) From bb65f4327b47ab5831c2ab01767599e46ef7f353 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 30 Oct 2025 16:19:06 -0500 Subject: [PATCH 06/40] NodeJS test client (#DH-19715) --- package-lock.json | 564 +++++++++++++++++- package.json | 3 +- plugins/example-theme/src/js/dist/index.js | 16 + .../test-node-client/.gitignore | 2 + .../test-node-client/package.json | 22 + .../test-node-client/src/PythonModuleMap.ts | 56 ++ .../test-node-client/src/index.mts | 93 +++ .../test-node-client/src/jsonRpc.mts | 33 + .../test-node-client/src/utils.mts | 150 +++++ .../test-node-client/tsconfig.json | 9 + .../workspace/aaa/__init__.py | 0 .../test-node-client/workspace/aaa/aaa1.py | 9 + .../test-node-client/workspace/aaa/aaa2.py | 1 + .../workspace/aaa/xxx/xxx1.py | 1 + .../workspace/bbb/__init__.py | 0 .../test-node-client/workspace/bbb/bbb1.py | 1 + tools/plugin_builder.py | 4 + 17 files changed, 960 insertions(+), 4 deletions(-) create mode 100644 plugins/example-theme/src/js/dist/index.js create mode 100644 plugins/python-remote-file-source/test-node-client/.gitignore create mode 100644 plugins/python-remote-file-source/test-node-client/package.json create mode 100644 plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts create mode 100644 plugins/python-remote-file-source/test-node-client/src/index.mts create mode 100644 plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts create mode 100644 plugins/python-remote-file-source/test-node-client/src/utils.mts create mode 100644 plugins/python-remote-file-source/test-node-client/tsconfig.json create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py diff --git a/package-lock.json b/package-lock.json index 3ef3e91de..28f2f570d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "name": "deephaven-plugins", "version": "0.1.0", "workspaces": [ - "./plugins/*/src/js/" + "./plugins/*/src/js/", + "./plugins/python-remote-file-source/test-node-client" ], "devDependencies": { "@deephaven/babel-preset": "^0.72.0", @@ -4307,6 +4308,50 @@ "react": "^17.x" } }, + "node_modules/@deephaven/jsapi-nodejs": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-nodejs/-/jsapi-nodejs-1.7.1.tgz", + "integrity": "sha512-AyqzrILtvAeST08ewOxtvqULcIJhmmkHraXrNpnoxMY5VGDupVk7omz1wH0dRmTfa6MikBRht9t7UI5J1t+Ecw==", + "dependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/log": "^1.5.3", + "@deephaven/utils": "^1.7.1", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", + "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + }, + "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/log": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.5.3.tgz", + "integrity": "sha512-1GSRW64QKkkQFfzrgtRcKDVeOAyJisZfsy0BR2Ob7cNCl64xBlE6Q3J3W9+H96okYcbErZa8dsekdLDbrwmxLA==", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/utils": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-1.7.1.tgz", + "integrity": "sha512-42QJK5a/yRox8iZQm+iR4t0jVrYJdPL+qZs/s3sD+ruU+N6iQ7A1DjKIFoDsfkViQ8ot1hS32s+Sj8RF3Cd+aA==", + "dependencies": { + "@deephaven/log": "^1.5.3", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@deephaven/jsapi-types": { "version": "0.40.0", "license": "Apache-2.0", @@ -4850,6 +4895,10 @@ "prettier": "^3.0.0" } }, + "node_modules/@deephaven/python-remote-file-source-test-client": { + "resolved": "plugins/python-remote-file-source/test-node-client", + "link": true + }, "node_modules/@deephaven/react-hooks": { "version": "0.106.2", "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.106.2.tgz", @@ -5744,6 +5793,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", @@ -5759,6 +5824,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", @@ -5774,6 +5855,22 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", @@ -27864,7 +27961,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "dev": true, "engines": { "node": ">=10" } @@ -29615,6 +29711,434 @@ "dev": true, "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, "node_modules/tuf-js": { "version": "1.1.7", "dev": true, @@ -35227,6 +35751,40 @@ } } }, + "plugins/python-remote-file-source/test-node-client": { + "name": "@deephaven/python-remote-file-source-test-client", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/jsapi-nodejs": "1.7.1" + }, + "devDependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", + "@types/node": "^24.5.0", + "tsx": "^4.20.5" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.2", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", + "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==", + "dev": true + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@types/node": { + "version": "24.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", + "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", + "dev": true, + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "dev": true + }, "plugins/simple-pivot/src/js": { "name": "@deephaven/js-plugin-simple-pivot", "version": "0.0.3-dev.2", @@ -36172,7 +36730,7 @@ }, "plugins/theme-pack/src/js": { "name": "@deephaven/js-plugin-theme-pack", - "version": "0.1.2", + "version": "0.1.0", "devDependencies": { "@deephaven/plugin": "^1.6.0" } diff --git a/package.json b/package.json index aaa726269..52cb38e38 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "private": true, "version": "0.1.0", "workspaces": [ - "./plugins/*/src/js/" + "./plugins/*/src/js/", + "./plugins/python-remote-file-source/test-node-client" ], "scripts": { "docker": "docker compose up deephaven-plugins --build", diff --git a/plugins/example-theme/src/js/dist/index.js b/plugins/example-theme/src/js/dist/index.js new file mode 100644 index 000000000..c74d8cb02 --- /dev/null +++ b/plugins/example-theme/src/js/dist/index.js @@ -0,0 +1,16 @@ +"use strict"; +const styleContent = "/* override the inherited base theme by scoping variables to :root */\n:root {\n /*\n ============ PALETTE ===========\n GRAY 50, 75, 100, 200, 300, 400, 500, 600, 700, 800, 900\n\n RED, ORANGE, YELLOW, CHARTREUSE, CELERY, GREEN, SEAFOAM,\n CYAN, BLUE, INDIGO, PURPLE, FUSCIA AND MAGENTA\n 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400\n\n Use any srgb color space value (hex, rgb, hsl, etc) to define a color.\n\n See for reference: \n github repo deephaven/web-client-ui\n /packages/components/src/theme/theme-light/theme-light-palette.css\n */\n\n /* Create a custom gray palette for background colors */\n --dh-color-gray-50: hsl(30, 100%, 99.22%);\n --dh-color-gray-75: hsl(30, 100%, 97.65%);\n --dh-color-gray-100: hsl(27.69, 100%, 94.9%);\n --dh-color-gray-200: hsl(29.19, 78.72%, 90.78%);\n --dh-color-gray-300: hsl(28.33, 58.06%, 87.84%);\n --dh-color-gray-400: hsl(28, 18.99%, 69.02%);\n --dh-color-gray-500: hsl(27.5, 10.34%, 54.51%);\n --dh-color-gray-600: hsl(26.67, 8.57%, 41.18%);\n --dh-color-gray-700: hsl(25, 9.38%, 25.1%);\n --dh-color-gray-800: hsl(34.29, 10.77%, 12.75%);\n --dh-color-gray-900: hsl(0, 0%, 0%);\n\n /* Create a custom seafoam palette */\n --dh-color-seafoam-100: hsl(185, 30%, 92.16%);\n --dh-color-seafoam-200: hsl(186, 31.25%, 87.45%);\n --dh-color-seafoam-300: hsl(186.67, 31.03%, 82.94%);\n --dh-color-seafoam-400: hsl(187.14, 32.81%, 74.9%);\n --dh-color-seafoam-500: hsl(186.43, 32.18%, 65.88%);\n --dh-color-seafoam-600: hsl(186.86, 31.82%, 56.86%);\n --dh-color-seafoam-700: hsl(186.43, 34.43%, 47.84%);\n --dh-color-seafoam-800: hsl(186.19, 49.74%, 38.24%);\n --dh-color-seafoam-900: hsl(185.17, 84.06%, 27.06%);\n --dh-color-seafoam-1000: hsl(185.61, 100%, 20.98%);\n --dh-color-seafoam-1100: hsl(186.21, 100%, 17.06%);\n --dh-color-seafoam-1200: hsl(187.06, 100%, 13.33%);\n --dh-color-seafoam-1300: hsl(187.2, 100%, 9.8%);\n --dh-color-seafoam-1400: hsl(188.33, 100%, 7.06%);\n\n /* Create a custom green palette */\n --dh-color-green-100: hsl(102.35, 39.53%, 91.57%);\n --dh-color-green-200: hsl(102, 41.67%, 85.88%);\n --dh-color-green-300: hsl(101.43, 41.18%, 80%);\n --dh-color-green-400: hsl(100.33, 40.94%, 70.78%);\n --dh-color-green-500: hsl(99.49, 39.7%, 60.98%);\n --dh-color-green-600: hsl(98.13, 38.4%, 50.98%);\n --dh-color-green-700: hsl(96.22, 53.11%, 40.98%);\n --dh-color-green-800: hsl(91.34, 90.54%, 29.02%);\n --dh-color-green-900: hsl(93.72, 100%, 23.73%);\n --dh-color-green-1000: hsl(96.6, 100%, 19.61%);\n --dh-color-green-1100: hsl(99.26, 100%, 15.88%);\n --dh-color-green-1200: hsl(101.9, 100%, 12.35%);\n --dh-color-green-1300: hsl(105.65, 100%, 9.02%);\n --dh-color-green-1400: hsl(109.09, 100%, 6.47%);\n\n /* Create a custom red palette */\n --dh-color-red-100: hsl(10, 100%, 95.29%);\n --dh-color-red-200: hsl(8.78, 100%, 91.96%);\n --dh-color-red-300: hsl(9.15, 100%, 88.43%);\n --dh-color-red-400: hsl(8.47, 100%, 83.33%);\n --dh-color-red-500: hsl(8.28, 100%, 77.25%);\n --dh-color-red-600: hsl(7.03, 96.03%, 70.39%);\n --dh-color-red-700: hsl(5.85, 87.23%, 63.14%);\n --dh-color-red-800: hsl(4.67, 77.59%, 54.51%);\n --dh-color-red-900: hsl(2.14, 86.73%, 44.31%);\n --dh-color-red-1000: hsl(0, 100%, 35.29%);\n --dh-color-red-1100: hsl(0, 100%, 28.63%);\n --dh-color-red-1200: hsl(0, 100%, 22.75%);\n --dh-color-red-1300: hsl(0, 100%, 17.25%);\n --dh-color-red-1400: hsl(0, 100%, 12.94%);\n\n /*\n ============ SEMANTIC VARIABLES ===========\n Assign things like accent colors, apply how background colors\n are mapped, positive/negative colors, etc. \n \n See: \n /packages/components/src/theme/theme-light/theme-light-semantic.css\n */\n\n /*\n Assign the accent colors to use seafoam. We could have assigned colors \n directly to accent-XXX but by first setting our brand color to the \n nearest palette color it allows it to also be exposed as a color option \n in color pickers within the UI.\n */\n\n --dh-color-accent-100: var(--dh-color-seafoam-100);\n --dh-color-accent-200: var(--dh-color-seafoam-200);\n --dh-color-accent-300: var(--dh-color-seafoam-300);\n --dh-color-accent-400: var(--dh-color-seafoam-400);\n --dh-color-accent-500: var(--dh-color-seafoam-500);\n --dh-color-accent-600: var(--dh-color-seafoam-600);\n --dh-color-accent-700: var(--dh-color-seafoam-700);\n --dh-color-accent-800: var(--dh-color-seafoam-800);\n --dh-color-accent-900: var(--dh-color-seafoam-900);\n --dh-color-accent-1000: var(--dh-color-seafoam-1000);\n --dh-color-accent-1100: var(--dh-color-seafoam-1100);\n --dh-color-accent-1200: var(--dh-color-seafoam-1200);\n --dh-color-accent-1300: var(--dh-color-seafoam-1300);\n --dh-color-accent-1400: var(--dh-color-seafoam-1400);\n\n /*\n ============ COMPONENT SPECIFIC SEMANTIC VARIABLES ===========\n Override specific colors to components like grid, plots, code editor, etc.\n\n See: \n /packages/components/src/theme/theme-light/theme-dark-components.css\n /packages/components/src/theme/theme-light/theme-dark-semantic-grid.css\n /packages/components/src/theme/theme-light/theme-dark-semantic-charts.css\n /packages/components/src/theme/theme-light/theme-dark-editor.css\n */\n\n --dh-color-grid-header-bg: var(--dh-color-gray-100);\n --dh-color-grid-row-0-bg: var(--dh-color-gray-200);\n --dh-color-grid-row-1-bg: var(--dh-color-gray-100);\n --dh-color-grid-date: var(--dh-color-black);\n\n /* Chart colorway is special in that it contains a space seperated \n list of colors to assign in order for each series in a chart. \n Consider including at least 10 colors. */\n --dh-color-chart-colorway: var(--dh-color-accent-bg)\n var(--dh-color-visual-green) var(--dh-color-visual-yellow)\n var(--dh-color-visual-purple) var(--dh-color-visual-orange)\n var(--dh-color-visual-red) var(--dh-color-visual-chartreuse)\n var(--dh-color-visual-fuchsia) var(--dh-color-visual-blue)\n var(--dh-color-visual-magenta) var(--dh-color-white);\n}\n\n/*\n============ CUSTOM CLASS OVERRIDES ===========\nExampe of overriding specific class color variables for one off customizations.\nUse sparingly as these are not guaranteed to be stable across releases.\n*/\n\n/* target a specific class in the DOM and override the variables or properties */\n.console-input-wrapper {\n --console-input-bg: var(--dh-color-gray-75);\n padding: 4px;\n}\n"; +const plugin = { + name: "example-theme", + // match the plugin name in the package.json, and the folder name + type: "ThemePlugin", + themes: { + name: "Example Theme", + // A human-readable name for the theme + baseTheme: "light", + // The base theme to extend from, either 'light' or 'dark' + styleContent + // this is a string containing your .css file contents, you could also manually inline css rules here + } +}; +module.exports = plugin; diff --git a/plugins/python-remote-file-source/test-node-client/.gitignore b/plugins/python-remote-file-source/test-node-client/.gitignore new file mode 100644 index 000000000..79eb78346 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/.gitignore @@ -0,0 +1,2 @@ +node_modules +tmp \ No newline at end of file diff --git a/plugins/python-remote-file-source/test-node-client/package.json b/plugins/python-remote-file-source/test-node-client/package.json new file mode 100644 index 000000000..5b85a1867 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/package.json @@ -0,0 +1,22 @@ +{ + "name": "@deephaven/python-remote-file-source-test-client", + "version": "1.0.0", + "private": true, + "decription": "", + "main": "lib/index.mjs", + "keywords": [], + "author": "Deephaven Data Labs LLC", + "license": "Apache-2.0", + "type": "module", + "scripts": { + "start": "tsx src/index.mts" + }, + "devDependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", + "@types/node": "^24.5.0", + "tsx": "^4.20.5" + }, + "dependencies": { + "@deephaven/jsapi-nodejs": "1.7.1" + } +} diff --git a/plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts b/plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts new file mode 100644 index 000000000..7bc36b2ac --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts @@ -0,0 +1,56 @@ +import fs from 'node:fs'; +import { getPythonModuleMaps } from './utils.mjs'; + +export class PythonModuleMap { + /** + * Create and initialize a PythonModuleMap for the given workspace path. + * @param workspacePath + * @returns The initialized PythonModuleMap. + */ + static async create(workspacePath: string): Promise { + const pythonModuleMap = new PythonModuleMap(workspacePath); + await pythonModuleMap.refresh(); + return pythonModuleMap; + } + + private constructor(private workspacePath: string) {} + + private topLevelModuleNames = new Set(); + + private map = new Map(); + + private async refresh(): Promise { + const [set, map] = await getPythonModuleMaps(this.workspacePath); + this.topLevelModuleNames = set; + this.map = map; + } + + /** + * Get source content for a module. + * @param moduleName The module name to get the source for. + * @returns A tuple of the file path and the source content, or undefined if + * the module + */ + async getModuleSource( + moduleName: string + ): Promise<[string, string | undefined]> { + const filepath = + this.map.get(moduleName) ?? this.map.get(`${moduleName}.__init__`); + + if (filepath == null) { + return ['', undefined]; + } + + return [filepath, await fs.promises.readFile(filepath, 'utf-8')]; + } + + /** + * Get the set of top level module names in the workspace. + * @returns A readonly set of top level module names. + */ + getTopLevelModuleNames(): ReadonlySet { + return this.topLevelModuleNames; + } +} + +export default PythonModuleMap; diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts new file mode 100644 index 000000000..b68a96a99 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -0,0 +1,93 @@ +/** + * Example of consuming DH Jsapi from an ESM module. + */ +import path from 'node:path'; +import { dh as DhType } from '@deephaven/jsapi-types'; +import { + JsonRpcRequest, + JsonRpcSuccess, + type JsonRpcSetConnectionIdRequest, +} from './jsonRpc.mjs'; +import { + createModuleSourceResponseMessage, + DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT, + getSetExecutionContextScript, + initDh, + PLUGIN_QUERY, +} from './utils.mjs'; +import PythonModuleMap from './PythonModuleMap.js'; + +console.log('Node.js version:', process.version); + +if (typeof globalThis.__dirname === 'undefined') { + globalThis.__dirname = import.meta.dirname; +} + +const SERVER_URL = new URL('http://localhost:10000/'); +const PSK = 'plugins.repo.test' as const; +const TEST_WORKSPACE_PATH = path.resolve(__dirname, '../workspace'); +const CN_ID = '1' as const; + +const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); + +const { dh, session } = await initDh(SERVER_URL, PSK); + +try { + await session.runCode(DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT); + console.log('Initialized Deephaven VS Code local execution plugin.'); + + const obj: DhType.Widget = await session.getObject(PLUGIN_QUERY); + + const msg: JsonRpcSetConnectionIdRequest = { + jsonrpc: '2.0', + id: CN_ID, + method: 'set_connection_id', + }; + + obj.sendMessage(JSON.stringify(msg)); + + obj.addEventListener( + dh.Widget.EVENT_MESSAGE, + async ({ detail }) => { + try { + const message: JsonRpcRequest = JSON.parse(detail.getDataAsString()); + console.log('Received message from server:', message); + if (message.method !== 'fetch_module') { + return; + } + + const [filepath, source] = await pythonModuleMap.getModuleSource( + message.params.module_name + ); + + const response: JsonRpcSuccess = createModuleSourceResponseMessage( + message.id, + source, + filepath + ); + console.log('Sending response to server:', response); + obj.sendMessage(JSON.stringify(response)); + } catch (e) { + console.error('Error parsing message from server:', e); + } + } + ); + + await session.runCode( + getSetExecutionContextScript( + CN_ID, + pythonModuleMap.getTopLevelModuleNames() + ) + ); + + // session.runCode( + // ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') + // ); + // session.runCode( + // ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') + // ); +} catch (e) { + console.log(e); +} + +// process.exit(0); diff --git a/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts b/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts new file mode 100644 index 000000000..de97b6a08 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts @@ -0,0 +1,33 @@ +interface JsonRpcRequestBase { + jsonrpc: '2.0'; + id: string; +} + +export interface JsonRpcFetchModuleRequest extends JsonRpcRequestBase { + method: 'fetch_module'; + params: { module_name: string }; +} + +export interface JsonRpcSetConnectionIdRequest extends JsonRpcRequestBase { + method: 'set_connection_id'; +} + +export type JsonRpcRequest = JsonRpcFetchModuleRequest; + +export interface JsonRpcSuccess { + jsonrpc: '2.0'; + id: string; + result: unknown; +} + +export interface JsonRpcError { + jsonrpc: '2.0'; + id: string; + error: { + code: number; + message: string; + data?: unknown; + }; +} + +export type JsonRpcResponse = JsonRpcSuccess | JsonRpcError; diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts new file mode 100644 index 000000000..c95402bc8 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -0,0 +1,150 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { loadDhModules, NodeHttp2gRPCTransport } from '@deephaven/jsapi-nodejs'; +import { dh as DhType } from '@deephaven/jsapi-types'; +import type { JsonRpcSuccess } from './jsonRpc.mjs'; + +export const AUTH_HANDLER_TYPE_PSK = + 'io.deephaven.authentication.psk.PskAuthenticationHandler'; + +export const PLUGIN_VARIABLE = '__deephaven_vscode' as const; + +export const PLUGIN_CLASS = 'DeephavenPythonRemoteFileSourcePlugin' as const; + +export const PLUGIN_QUERY = { + name: PLUGIN_VARIABLE, + type: PLUGIN_CLASS, +}; + +export const DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT = [ + 'try:', + ` ${PLUGIN_VARIABLE}`, + 'except NameError:', + ' from deephaven.python_remote_file_source import PluginObject as DeephavenRemoteFileSourcePlugin', + ` ${PLUGIN_VARIABLE} = DeephavenRemoteFileSourcePlugin()`, +].join('\n'); + +/** + * Get a JsonRpc success response message to send module source to the server. + * @param id The id of the request to respond to. + * @param source The source code of the module, or undefined for no source. + * @param filepath The path to the module source file (defaults to ''). + * @returns A JsonRpc success response message. + */ +export function createModuleSourceResponseMessage( + id: string, + source: string | undefined, + filepath: string = '' +): JsonRpcSuccess { + return { + jsonrpc: '2.0', + id, + result: { + filepath, + source, + }, + }; +} + +/** + * Get a map of python module names to their file paths in the workspace. + * @returns A map of module names to file paths. + */ +export async function getPythonModuleMaps( + workspacePath: string +): Promise<[Set, Map]> { + const workspaceEntries = await fs.promises.readdir(workspacePath, { + recursive: true, + withFileTypes: true, + }); + + const topLevelModuleNames = new Set(); + const moduleMap = new Map(); + + for (const dirent of workspaceEntries) { + const relativePath = path + .join(dirent.parentPath, dirent.name) + .replace(workspacePath, ''); + + const moduleName = relativePath + .slice(1) + .replace(/\.py$/, '') + .replaceAll(path.sep, '.'); + + if (dirent.isDirectory()) { + moduleMap.set(moduleName, null); + if (!moduleName.includes('.')) { + topLevelModuleNames.add(moduleName); + } + continue; + } + + const fullPath = path.join(dirent.parentPath, dirent.name); + moduleMap.set(moduleName, fullPath); + } + + return [topLevelModuleNames, moduleMap]; +} + +/** + * Gets a python script to set the execution context for the remote file source plugin. + * This includes the connection id and the set of module fullnames that can be + * loaded. + * @param connectionId The connection id to set, or null to clear it. + * @param moduleFullnames The set of module fullnames that can be loaded. + * @returns A python script to set the execution context. + */ +export function getSetExecutionContextScript( + connectionId: string, + moduleFullnames: Iterable +): string { + const connectionIdStr = `'${connectionId}'`; + const moduleFullnamesStr = `{${[...moduleFullnames] + .map(modulePath => `"${modulePath}"`) + .join(',')}}`; + return `${PLUGIN_VARIABLE}.set_execution_context(${connectionIdStr}, ${moduleFullnamesStr})`; +} + +/** + * Initialize a Deephaven api, client, connection, and session. + * @param serverUrl The URL of the Deephaven server. + * @param psk The pre-shared key for authentication. + * @param debug Whether to enable debug logging. + * @returns The initialized dh, client, cn, and session. + */ +export async function initDh( + serverUrl: URL, + psk: string, + debug: boolean = false +): Promise<{ + dh: typeof DhType; + client: DhType.CoreClient; + cn: DhType.IdeConnection; + session: DhType.IdeSession; +}> { + const storageDir = path.join(__dirname, '..', 'tmp'); + + const dh = await loadDhModules({ + serverUrl, + storageDir, + targetModuleType: 'esm', + }); + + const client = new dh.CoreClient(serverUrl.href, { + debug, + transportFactory: NodeHttp2gRPCTransport.factory, + }); + + await client.login({ + type: AUTH_HANDLER_TYPE_PSK, + token: psk, + }); + + console.log('Logged in to Deephaven server'); + + const cn = await client.getAsIdeConnection(); + + const session = await cn.startSession('python'); + + return { dh, client, cn, session }; +} diff --git a/plugins/python-remote-file-source/test-node-client/tsconfig.json b/plugins/python-remote-file-source/test-node-client/tsconfig.json new file mode 100644 index 000000000..46d151eb1 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "NodeNext", + "outDir": "dist", + "rootDir": "src", + "strict": true + }, + "include": ["src/**/*"] +} diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py new file mode 100644 index 000000000..a89493061 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py @@ -0,0 +1,9 @@ +__deephaven_vscode.evict_module_cache() + +from aaa import aaa2 +from bbb import bbb1 + +print("Module aaa1.py loaded") + +# import sys +# print(sys.modules.get('aaa')) diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py new file mode 100644 index 000000000..d2c3740f6 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py @@ -0,0 +1 @@ +print("Module aaa2.py loaded") diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py new file mode 100644 index 000000000..b4efe2412 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py @@ -0,0 +1 @@ +print("Module xxx1.py loaded") diff --git a/plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py b/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py new file mode 100644 index 000000000..e3cd7c6bb --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py @@ -0,0 +1 @@ +print("Module bbb1.py loaded") diff --git a/tools/plugin_builder.py b/tools/plugin_builder.py index 49598ae4e..6bf26eca4 100644 --- a/tools/plugin_builder.py +++ b/tools/plugin_builder.py @@ -36,8 +36,12 @@ r".*/build/.*", r".*/node_modules/.*", r".*/_js/.*", + r".*/test_ws/.*$", # ignore hidden files and directories r".*/\..*/.*", + # ignore the test node client since it is not part of plugin code, and we + # don't want changes to restart the builder / server + r".*/plugins/python-remote-file-source/test-node-client/.*", ] From 93bc21681e8e15138997ab756ee9b88ebfac0563 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 10:39:22 -0500 Subject: [PATCH 07/40] Cleanup (#DH-19715) --- .../test-node-client/src/index.mts | 89 ++----------- .../test-node-client/src/jsonRpc.mts | 40 ++++++ .../test-node-client/src/utils.mts | 123 +++++++++++++++--- 3 files changed, 154 insertions(+), 98 deletions(-) diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts index b68a96a99..795b4e962 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -1,93 +1,24 @@ -/** - * Example of consuming DH Jsapi from an ESM module. - */ import path from 'node:path'; -import { dh as DhType } from '@deephaven/jsapi-types'; -import { - JsonRpcRequest, - JsonRpcSuccess, - type JsonRpcSetConnectionIdRequest, -} from './jsonRpc.mjs'; -import { - createModuleSourceResponseMessage, - DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT, - getSetExecutionContextScript, - initDh, - PLUGIN_QUERY, -} from './utils.mjs'; +import { initDh, initPlugin } from './utils.mjs'; import PythonModuleMap from './PythonModuleMap.js'; console.log('Node.js version:', process.version); -if (typeof globalThis.__dirname === 'undefined') { - globalThis.__dirname = import.meta.dirname; -} - const SERVER_URL = new URL('http://localhost:10000/'); const PSK = 'plugins.repo.test' as const; -const TEST_WORKSPACE_PATH = path.resolve(__dirname, '../workspace'); -const CN_ID = '1' as const; +const TEST_WORKSPACE_PATH = path.resolve(import.meta.dirname, '../workspace'); const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); -const { dh, session } = await initDh(SERVER_URL, PSK); - -try { - await session.runCode(DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT); - console.log('Initialized Deephaven VS Code local execution plugin.'); - - const obj: DhType.Widget = await session.getObject(PLUGIN_QUERY); - - const msg: JsonRpcSetConnectionIdRequest = { - jsonrpc: '2.0', - id: CN_ID, - method: 'set_connection_id', - }; - - obj.sendMessage(JSON.stringify(msg)); - - obj.addEventListener( - dh.Widget.EVENT_MESSAGE, - async ({ detail }) => { - try { - const message: JsonRpcRequest = JSON.parse(detail.getDataAsString()); - console.log('Received message from server:', message); - if (message.method !== 'fetch_module') { - return; - } - - const [filepath, source] = await pythonModuleMap.getModuleSource( - message.params.module_name - ); - - const response: JsonRpcSuccess = createModuleSourceResponseMessage( - message.id, - source, - filepath - ); - console.log('Sending response to server:', response); - obj.sendMessage(JSON.stringify(response)); - } catch (e) { - console.error('Error parsing message from server:', e); - } - } - ); +const { session } = await initDh(SERVER_URL, PSK); - await session.runCode( - getSetExecutionContextScript( - CN_ID, - pythonModuleMap.getTopLevelModuleNames() - ) - ); +const plugin = await initPlugin(pythonModuleMap, session); - // session.runCode( - // ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') - // ); - // session.runCode( - // ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') - // ); -} catch (e) { - console.log(e); -} +// session.runCode( +// ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') +// ); +// session.runCode( +// ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') +// ); // process.exit(0); diff --git a/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts b/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts index de97b6a08..e6ece0f15 100644 --- a/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts +++ b/plugins/python-remote-file-source/test-node-client/src/jsonRpc.mts @@ -31,3 +31,43 @@ export interface JsonRpcError { } export type JsonRpcResponse = JsonRpcSuccess | JsonRpcError; + +/** + * Get a JsonRpc success response message to send module source to the server. + * @param id The id of the request to respond to. + * @param source The source code of the module, or undefined for no source. + * @param filepath The path to the module source file (defaults to ''). + * @returns A JsonRpc success response message. + */ +function moduleSourceResponse( + id: string, + source: string | undefined, + filepath: string = '' +): JsonRpcSuccess { + return { + jsonrpc: '2.0', + id, + result: { + filepath, + source, + }, + }; +} + +/** + * Create a JsonRpc set_connection_id request message. + * @param id The connection id to set. + * @returns A JsonRpc set_connection_id request message. + */ +function setConnectionId(id: string): JsonRpcSetConnectionIdRequest { + return { + jsonrpc: '2.0', + id, + method: 'set_connection_id', + }; +} + +export const Msg = { + setConnectionId, + moduleSourceResponse, +}; diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index c95402bc8..ebd5bbf7c 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -2,11 +2,18 @@ import fs from 'node:fs'; import path from 'node:path'; import { loadDhModules, NodeHttp2gRPCTransport } from '@deephaven/jsapi-nodejs'; import { dh as DhType } from '@deephaven/jsapi-types'; -import type { JsonRpcSuccess } from './jsonRpc.mjs'; +import { Msg, type JsonRpcRequest, type JsonRpcResponse } from './jsonRpc.mjs'; +import type PythonModuleMap from './PythonModuleMap.js'; export const AUTH_HANDLER_TYPE_PSK = 'io.deephaven.authentication.psk.PskAuthenticationHandler'; +const CN_ID = '12345' as const; + +// Alias for `dh.Widget.EVENT_MESSAGE` to avoid having to pass in a `dh` instance +// to util functions that only need the event name. +export const DH_WIDGET_EVENT_MESSAGE = 'message' as const; + export const PLUGIN_VARIABLE = '__deephaven_vscode' as const; export const PLUGIN_CLASS = 'DeephavenPythonRemoteFileSourcePlugin' as const; @@ -25,24 +32,34 @@ export const DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT = [ ].join('\n'); /** - * Get a JsonRpc success response message to send module source to the server. - * @param id The id of the request to respond to. - * @param source The source code of the module, or undefined for no source. - * @param filepath The path to the module source file (defaults to ''). - * @returns A JsonRpc success response message. + * Create a message handler for the given plugin that responds to fetch_module + * requests using the given PythonModuleMap. + * @param plugin The plugin widget to send responses to. + * @param pythonModuleMap The PythonModuleMap to use for fetching module source. + * @returns A message event handler function. */ -export function createModuleSourceResponseMessage( - id: string, - source: string | undefined, - filepath: string = '' -): JsonRpcSuccess { - return { - jsonrpc: '2.0', - id, - result: { - filepath, - source, - }, +export function createModuleSourceRequestHandler( + plugin: DhType.Widget, + pythonModuleMap: PythonModuleMap +) { + return async ({ detail }: DhType.Event): Promise => { + try { + const message: JsonRpcRequest = JSON.parse(detail.getDataAsString()); + console.log('Received message from server:', message); + if (message.method !== 'fetch_module') { + return; + } + + const [filepath, source] = await pythonModuleMap.getModuleSource( + message.params.module_name + ); + + plugin.sendMessage( + JSON.stringify(Msg.moduleSourceResponse(message.id, source, filepath)) + ); + } catch (e) { + console.error('Error parsing message from server:', e); + } }; } @@ -122,7 +139,7 @@ export async function initDh( cn: DhType.IdeConnection; session: DhType.IdeSession; }> { - const storageDir = path.join(__dirname, '..', 'tmp'); + const storageDir = path.join(import.meta.dirname, '..', 'tmp'); const dh = await loadDhModules({ serverUrl, @@ -148,3 +165,71 @@ export async function initDh( return { dh, client, cn, session }; } + +export async function initPlugin( + pythonModuleMap: PythonModuleMap, + session: DhType.IdeSession +): Promise { + await session.runCode(DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT); + console.log('Initialized Deephaven VS Code local execution plugin.'); + + const plugin: DhType.Widget = await session.getObject(PLUGIN_QUERY); + plugin.addEventListener( + DH_WIDGET_EVENT_MESSAGE, + createModuleSourceRequestHandler(plugin, pythonModuleMap) + ); + + // The connection id must be set on the plugin and match the id used in the + // execution context in order for server plugin to request source from this + // client. + await setConnectionId(plugin, CN_ID); + + // Tell the server the connection id and top level module names that can be + // sourced from this client. + await session.runCode( + getSetExecutionContextScript( + CN_ID, + pythonModuleMap.getTopLevelModuleNames() + ) + ); + + return plugin; +} + +/** + * Send a set_connection_id request to the plugin and wait for a response. + * @param plugin The plugin widget to send the request to. + * @param id The connection id to set. + */ +export async function setConnectionId( + plugin: DhType.Widget, + id: string +): Promise { + const request = Msg.setConnectionId(id); + + const result = new Promise((resolve, reject) => { + const removeEventListener = plugin.addEventListener( + DH_WIDGET_EVENT_MESSAGE, + async ({ detail }) => { + try { + const message: JsonRpcResponse | JsonRpcRequest = JSON.parse( + detail.getDataAsString() + ); + + if ('id' in message && message.id === request.id) { + console.log('Connection ID set:', message.id); + resolve(); + removeEventListener(); + } + } catch (err) { + console.error('Error parsing message from server:', err); + reject(err); + } + } + ); + }); + + plugin.sendMessage(JSON.stringify(request)); + + return result; +} From 26496ffb64c79004e7a8759677f479eb69a1aa00 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 12:07:23 -0500 Subject: [PATCH 08/40] TestLogger (#DH-19715) --- package-lock.json | 3 +- .../test-node-client/package.json | 3 +- ...PythonModuleMap.ts => PythonModuleMap.mts} | 0 .../test-node-client/src/TestLogger.mts | 35 ++++++++++ .../test-node-client/src/index.mts | 21 +++++- .../test-node-client/src/utils.mts | 64 +++++++++++++++---- 6 files changed, 111 insertions(+), 15 deletions(-) rename plugins/python-remote-file-source/test-node-client/src/{PythonModuleMap.ts => PythonModuleMap.mts} (100%) create mode 100644 plugins/python-remote-file-source/test-node-client/src/TestLogger.mts diff --git a/package-lock.json b/package-lock.json index 28f2f570d..3d0acbfc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35756,7 +35756,8 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@deephaven/jsapi-nodejs": "1.7.1" + "@deephaven/jsapi-nodejs": "1.7.1", + "nanoid": "^5.0.7" }, "devDependencies": { "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", diff --git a/plugins/python-remote-file-source/test-node-client/package.json b/plugins/python-remote-file-source/test-node-client/package.json index 5b85a1867..e3e1f232f 100644 --- a/plugins/python-remote-file-source/test-node-client/package.json +++ b/plugins/python-remote-file-source/test-node-client/package.json @@ -17,6 +17,7 @@ "tsx": "^4.20.5" }, "dependencies": { - "@deephaven/jsapi-nodejs": "1.7.1" + "@deephaven/jsapi-nodejs": "1.7.1", + "nanoid": "^5.0.7" } } diff --git a/plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts b/plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.mts similarity index 100% rename from plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.ts rename to plugins/python-remote-file-source/test-node-client/src/PythonModuleMap.mts diff --git a/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts b/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts new file mode 100644 index 000000000..e28236852 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts @@ -0,0 +1,35 @@ +import type { dh as DhType } from '@deephaven/jsapi-types'; +import { waitForLogMarker } from './utils.mjs'; + +/** + * Test logger that can track log messages between unique marker identifiers. + * This is needed since `onLogMessage` will subscribe to all log messages from + * the start of the server, and tests will need to isolate ones specific to the + * test. + */ +export class TestLogger { + constructor(private session: DhType.IdeSession) { + this.session.onLogMessage(msg => { + if (!this.isTracking) { + return; + } + + this.logItems.push(msg); + }); + } + + isTracking: boolean = false; + logItems: DhType.ide.LogItem[] = []; + + async start(): Promise { + await waitForLogMarker(this.session); + this.isTracking = true; + } + + async stop(): Promise { + await waitForLogMarker(this.session); + this.isTracking = false; + } +} + +export default TestLogger; diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts index 795b4e962..250335b3d 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -1,6 +1,8 @@ +import fs from 'node:fs'; import path from 'node:path'; import { initDh, initPlugin } from './utils.mjs'; -import PythonModuleMap from './PythonModuleMap.js'; +import { PythonModuleMap } from './PythonModuleMap.mjs'; +import { TestLogger } from './TestLogger.mjs'; console.log('Node.js version:', process.version); @@ -8,11 +10,26 @@ const SERVER_URL = new URL('http://localhost:10000/'); const PSK = 'plugins.repo.test' as const; const TEST_WORKSPACE_PATH = path.resolve(import.meta.dirname, '../workspace'); +const aaa_source = await fs.promises.readFile( + path.join(TEST_WORKSPACE_PATH, 'aaa', 'aaa1.py'), + 'utf-8' +); + const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); const { session } = await initDh(SERVER_URL, PSK); -const plugin = await initPlugin(pythonModuleMap, session); +const { runCode } = await initPlugin(pythonModuleMap, session); + +const testLogger = new TestLogger(session); +await testLogger.start(); + +const result = await runCode(aaa_source); + +await testLogger.stop(); +console.log('result', testLogger.logItems); + +process.exit(0); // session.runCode( // ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index ebd5bbf7c..ee3b3f3ee 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -1,9 +1,10 @@ import fs from 'node:fs'; import path from 'node:path'; +import { nanoid } from 'nanoid'; import { loadDhModules, NodeHttp2gRPCTransport } from '@deephaven/jsapi-nodejs'; -import { dh as DhType } from '@deephaven/jsapi-types'; +import type { dh as DhType } from '@deephaven/jsapi-types'; import { Msg, type JsonRpcRequest, type JsonRpcResponse } from './jsonRpc.mjs'; -import type PythonModuleMap from './PythonModuleMap.js'; +import type PythonModuleMap from './PythonModuleMap.mjs'; export const AUTH_HANDLER_TYPE_PSK = 'io.deephaven.authentication.psk.PskAuthenticationHandler'; @@ -169,7 +170,7 @@ export async function initDh( export async function initPlugin( pythonModuleMap: PythonModuleMap, session: DhType.IdeSession -): Promise { +): Promise<{ runCode: (code: string) => Promise }> { await session.runCode(DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT); console.log('Initialized Deephaven VS Code local execution plugin.'); @@ -184,16 +185,36 @@ export async function initPlugin( // client. await setConnectionId(plugin, CN_ID); - // Tell the server the connection id and top level module names that can be - // sourced from this client. + return { + /** + * Augmented runCode function that sets plugin execution context before + * running DH code. + */ + runCode: async (code: string): Promise => { + await setExecutionContext( + session, + CN_ID, + pythonModuleMap.getTopLevelModuleNames() + ); + return session.runCode(code); + }, + }; +} + +/** + * Set the connection id and top level module names in the server execution context. + * @param session The ide session to run the code in. + * @param cnId connection id + * @param topLevelModuleNames The set of top level module names in the workspace. + */ +async function setExecutionContext( + session: DhType.IdeSession, + cnId: string, + topLevelModuleNames: ReadonlySet +): Promise { await session.runCode( - getSetExecutionContextScript( - CN_ID, - pythonModuleMap.getTopLevelModuleNames() - ) + getSetExecutionContextScript(cnId, topLevelModuleNames) ); - - return plugin; } /** @@ -233,3 +254,24 @@ export async function setConnectionId( return result; } + +/** + * Send a print message with a unique marker and wait for it to appear in the + * log messages. + * @param session The ide session to listen for log messages on. + * @returns A promise that resolves when the marker is found in the log messages. + */ +export function waitForLogMarker(session: DhType.IdeSession): Promise { + // unique marker to wait for in log messages + const marker = ``; + + return new Promise(resolve => { + const unsubscribe = session.onLogMessage(msg => { + if (msg.message === `${marker}\n`) { + resolve(); + unsubscribe(); + } + }); + session.runCode(`print("${marker}")`); + }); +} From 5f7493f1ad4678105e6b05229e1e4bd4264f814e Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 12:43:49 -0500 Subject: [PATCH 09/40] Basic test for local sourcing (#DH-19715) --- .../test-node-client/src/index.mts | 34 ++++++++----------- .../workspace/aaa/__init__.py | 0 .../test-node-client/workspace/aaa/aaa1.py | 9 ----- .../test-node-client/workspace/aaa/aaa2.py | 1 - .../workspace/aaa/xxx/xxx1.py | 1 - .../workspace/bbb/__init__.py | 0 .../test-node-client/workspace/bbb/bbb1.py | 1 - .../package_with_absolute_imports/__init__.py | 1 + .../utils/__init__.py | 2 ++ .../utils/constants.py | 1 + .../utils/simple_ticking.py | 6 ++++ .../package_with_relative_imports/__init__.py | 1 + .../utils/__init__.py | 1 + .../utils/constants.py | 1 + .../utils/simple_ticking.py | 6 ++++ .../workspace/test_absolute_imports.py | 3 ++ .../workspace/test_relative_imports.py | 3 ++ 17 files changed, 39 insertions(+), 32 deletions(-) delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py delete mode 100644 plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/constants.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/simple_ticking.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/__init__.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/constants.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/simple_ticking.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/test_absolute_imports.py create mode 100644 plugins/python-remote-file-source/test-node-client/workspace/test_relative_imports.py diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts index 250335b3d..de7aa6c68 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -1,8 +1,8 @@ import fs from 'node:fs'; +import assert from 'node:assert'; import path from 'node:path'; -import { initDh, initPlugin } from './utils.mjs'; +import { initDh, initPlugin, waitForLogMarker } from './utils.mjs'; import { PythonModuleMap } from './PythonModuleMap.mjs'; -import { TestLogger } from './TestLogger.mjs'; console.log('Node.js version:', process.version); @@ -10,32 +10,26 @@ const SERVER_URL = new URL('http://localhost:10000/'); const PSK = 'plugins.repo.test' as const; const TEST_WORKSPACE_PATH = path.resolve(import.meta.dirname, '../workspace'); -const aaa_source = await fs.promises.readFile( - path.join(TEST_WORKSPACE_PATH, 'aaa', 'aaa1.py'), +const TEST_RELATIVE_IMPORTS_SOURCE = await fs.promises.readFile( + path.join(TEST_WORKSPACE_PATH, 'test_relative_imports.py'), + 'utf-8' +); +const TEST_ABSOLUTE_IMPORTS_SOURCE = await fs.promises.readFile( + path.join(TEST_WORKSPACE_PATH, 'test_absolute_imports.py'), 'utf-8' ); const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); - const { session } = await initDh(SERVER_URL, PSK); - const { runCode } = await initPlugin(pythonModuleMap, session); -const testLogger = new TestLogger(session); -await testLogger.start(); +const result = await runCode(TEST_RELATIVE_IMPORTS_SOURCE); +assert.strictEqual(result.changes.created[0].title, 'simple_ticking'); -const result = await runCode(aaa_source); +const result2 = await runCode(TEST_ABSOLUTE_IMPORTS_SOURCE); +console.log(result2.error); +assert.strictEqual(result2.changes.created[0].title, 'simple_ticking_absolute'); -await testLogger.stop(); -console.log('result', testLogger.logItems); +await waitForLogMarker(session); process.exit(0); - -// session.runCode( -// ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') -// ); -// session.runCode( -// ['__deephaven_vscode.evict_module_cache()', 'import test_ws.bbb'].join('\n') -// ); - -// process.exit(0); diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py deleted file mode 100644 index a89493061..000000000 --- a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa1.py +++ /dev/null @@ -1,9 +0,0 @@ -__deephaven_vscode.evict_module_cache() - -from aaa import aaa2 -from bbb import bbb1 - -print("Module aaa1.py loaded") - -# import sys -# print(sys.modules.get('aaa')) diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py deleted file mode 100644 index d2c3740f6..000000000 --- a/plugins/python-remote-file-source/test-node-client/workspace/aaa/aaa2.py +++ /dev/null @@ -1 +0,0 @@ -print("Module aaa2.py loaded") diff --git a/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py b/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py deleted file mode 100644 index b4efe2412..000000000 --- a/plugins/python-remote-file-source/test-node-client/workspace/aaa/xxx/xxx1.py +++ /dev/null @@ -1 +0,0 @@ -print("Module xxx1.py loaded") diff --git a/plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/bbb/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py b/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py deleted file mode 100644 index e3cd7c6bb..000000000 --- a/plugins/python-remote-file-source/test-node-client/workspace/bbb/bbb1.py +++ /dev/null @@ -1 +0,0 @@ -print("Module bbb1.py loaded") diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/__init__.py new file mode 100644 index 000000000..986983663 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/__init__.py @@ -0,0 +1 @@ +from package_with_absolute_imports.utils import * diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/__init__.py new file mode 100644 index 000000000..88bc92ac2 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/__init__.py @@ -0,0 +1,2 @@ +from package_with_absolute_imports.utils.constants import * +from package_with_absolute_imports.utils.simple_ticking import * diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/constants.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/constants.py new file mode 100644 index 000000000..9f2b035b2 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/constants.py @@ -0,0 +1 @@ +DEFAULT_PERIOD = "PT2S" diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/simple_ticking.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/simple_ticking.py new file mode 100644 index 000000000..0d6641fb5 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_absolute_imports/utils/simple_ticking.py @@ -0,0 +1,6 @@ +from deephaven import time_table +from package_with_absolute_imports.utils.constants import DEFAULT_PERIOD + + +def create_simple_ticking(): + return time_table(DEFAULT_PERIOD) diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/__init__.py new file mode 100644 index 000000000..16281fe0b --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/__init__.py @@ -0,0 +1 @@ +from .utils import * diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/__init__.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/__init__.py new file mode 100644 index 000000000..e7d0bfe5f --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/__init__.py @@ -0,0 +1 @@ +from .simple_ticking import * diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/constants.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/constants.py new file mode 100644 index 000000000..9f2b035b2 --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/constants.py @@ -0,0 +1 @@ +DEFAULT_PERIOD = "PT2S" diff --git a/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/simple_ticking.py b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/simple_ticking.py new file mode 100644 index 000000000..bc012004d --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/package_with_relative_imports/utils/simple_ticking.py @@ -0,0 +1,6 @@ +from deephaven import time_table +from .constants import DEFAULT_PERIOD + + +def create_simple_ticking(): + return time_table(DEFAULT_PERIOD) diff --git a/plugins/python-remote-file-source/test-node-client/workspace/test_absolute_imports.py b/plugins/python-remote-file-source/test-node-client/workspace/test_absolute_imports.py new file mode 100644 index 000000000..8615ff1be --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/test_absolute_imports.py @@ -0,0 +1,3 @@ +from package_with_absolute_imports import create_simple_ticking + +simple_ticking_absolute = create_simple_ticking() diff --git a/plugins/python-remote-file-source/test-node-client/workspace/test_relative_imports.py b/plugins/python-remote-file-source/test-node-client/workspace/test_relative_imports.py new file mode 100644 index 000000000..c62b3922a --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/workspace/test_relative_imports.py @@ -0,0 +1,3 @@ +from package_with_relative_imports import create_simple_ticking + +simple_ticking = create_simple_ticking() From 2f3b41bf94891fc58df82513e732ed0507f92228 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 12:48:09 -0500 Subject: [PATCH 10/40] Removed unnecessary log based code (#DH-19715) --- .../test-node-client/src/TestLogger.mts | 35 ------------------- .../test-node-client/src/index.mts | 7 ++-- .../test-node-client/src/utils.mts | 22 ------------ 3 files changed, 3 insertions(+), 61 deletions(-) delete mode 100644 plugins/python-remote-file-source/test-node-client/src/TestLogger.mts diff --git a/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts b/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts deleted file mode 100644 index e28236852..000000000 --- a/plugins/python-remote-file-source/test-node-client/src/TestLogger.mts +++ /dev/null @@ -1,35 +0,0 @@ -import type { dh as DhType } from '@deephaven/jsapi-types'; -import { waitForLogMarker } from './utils.mjs'; - -/** - * Test logger that can track log messages between unique marker identifiers. - * This is needed since `onLogMessage` will subscribe to all log messages from - * the start of the server, and tests will need to isolate ones specific to the - * test. - */ -export class TestLogger { - constructor(private session: DhType.IdeSession) { - this.session.onLogMessage(msg => { - if (!this.isTracking) { - return; - } - - this.logItems.push(msg); - }); - } - - isTracking: boolean = false; - logItems: DhType.ide.LogItem[] = []; - - async start(): Promise { - await waitForLogMarker(this.session); - this.isTracking = true; - } - - async stop(): Promise { - await waitForLogMarker(this.session); - this.isTracking = false; - } -} - -export default TestLogger; diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts index de7aa6c68..4cdd8921c 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import assert from 'node:assert'; import path from 'node:path'; -import { initDh, initPlugin, waitForLogMarker } from './utils.mjs'; +import { initDh, initPlugin } from './utils.mjs'; import { PythonModuleMap } from './PythonModuleMap.mjs'; console.log('Node.js version:', process.version); @@ -23,13 +23,12 @@ const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); const { session } = await initDh(SERVER_URL, PSK); const { runCode } = await initPlugin(pythonModuleMap, session); +console.log('Running test_relative_imports.py'); const result = await runCode(TEST_RELATIVE_IMPORTS_SOURCE); assert.strictEqual(result.changes.created[0].title, 'simple_ticking'); +console.log('Running test_absolute_imports.py'); const result2 = await runCode(TEST_ABSOLUTE_IMPORTS_SOURCE); -console.log(result2.error); assert.strictEqual(result2.changes.created[0].title, 'simple_ticking_absolute'); -await waitForLogMarker(session); - process.exit(0); diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index ee3b3f3ee..9db9dcf69 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -46,7 +46,6 @@ export function createModuleSourceRequestHandler( return async ({ detail }: DhType.Event): Promise => { try { const message: JsonRpcRequest = JSON.parse(detail.getDataAsString()); - console.log('Received message from server:', message); if (message.method !== 'fetch_module') { return; } @@ -254,24 +253,3 @@ export async function setConnectionId( return result; } - -/** - * Send a print message with a unique marker and wait for it to appear in the - * log messages. - * @param session The ide session to listen for log messages on. - * @returns A promise that resolves when the marker is found in the log messages. - */ -export function waitForLogMarker(session: DhType.IdeSession): Promise { - // unique marker to wait for in log messages - const marker = ``; - - return new Promise(resolve => { - const unsubscribe = session.onLogMessage(msg => { - if (msg.message === `${marker}\n`) { - resolve(); - unsubscribe(); - } - }); - session.runCode(`print("${marker}")`); - }); -} From 089e697c41e5407b2ea6a24669aecab8863e2e8b Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 30 Oct 2025 16:19:32 -0500 Subject: [PATCH 11/40] vitest based tests (#DH-19715) --- package-lock.json | 2395 ++++++++++++++++- package.json | 1 + .../test-node-client/package.json | 7 +- .../test-node-client/src/constants.mts | 8 + .../test-node-client/src/index.mts | 19 +- .../test-node-client/src/index.spec.mts | 27 + .../test-node-client/src/utils.mts | 14 +- 7 files changed, 2448 insertions(+), 23 deletions(-) create mode 100644 plugins/python-remote-file-source/test-node-client/src/constants.mts create mode 100644 plugins/python-remote-file-source/test-node-client/src/index.spec.mts diff --git a/package-lock.json b/package-lock.json index 3d0acbfc7..25942580d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -310,6 +310,15 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "dev": true, @@ -5539,6 +5548,37 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -6432,6 +6472,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "dev": true, @@ -6485,6 +6534,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/globals": { "version": "29.7.0", "dev": true, @@ -6499,6 +6557,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/reporters": { "version": "29.7.0", "dev": true, @@ -6552,6 +6632,57 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true + }, "node_modules/@jest/source-map": { "version": "29.6.3", "dev": true, @@ -6646,6 +6777,16 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "license": "MIT", @@ -6669,8 +6810,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "license": "MIT" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -7314,6 +7456,18 @@ "version": "3.0.0", "license": "ISC" }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "dev": true, @@ -12268,6 +12422,16 @@ "url": "https://opencollective.com/turf" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/aria-query": { "version": "5.0.4", "dev": true, @@ -12310,6 +12474,15 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "dependencies": { + "@types/deep-eql": "*" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "license": "MIT", @@ -12317,6 +12490,12 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true + }, "node_modules/@types/deep-equal": { "version": "1.0.4", "dev": true, @@ -12916,6 +13095,256 @@ "dev": true, "license": "ISC" }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.8.0", "dev": true, @@ -12927,6 +13356,88 @@ "vite": "^4 || ^5 || ^6" } }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "license": "MIT", @@ -13531,6 +14042,15 @@ "version": "2.0.6", "license": "MIT" }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "dev": true, @@ -14114,6 +14634,15 @@ "node": ">=10" } }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/cacache": { "version": "17.1.4", "dev": true, @@ -14319,6 +14848,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -14355,6 +14900,15 @@ "dev": true, "license": "MIT" }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "4.0.3", "license": "MIT", @@ -15403,8 +15957,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "license": "MIT", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dependencies": { "ms": "^2.1.3" }, @@ -15476,6 +16031,15 @@ } } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-equal": { "version": "2.2.3", "license": "MIT", @@ -16050,8 +16614,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.6.0", - "license": "MIT" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==" }, "node_modules/es-object-atoms": { "version": "1.1.1", @@ -17327,6 +17892,15 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "license": "BSD-2-Clause", @@ -17393,6 +17967,15 @@ "node": ">= 0.8.0" } }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/expect": { "version": "29.7.0", "dev": true, @@ -17408,6 +17991,15 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "dev": true, @@ -22061,6 +22653,12 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true + }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, @@ -22084,6 +22682,15 @@ "lz-string": "bin/bin.js" } }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/make-dir": { "version": "4.0.0", "dev": true, @@ -23870,6 +24477,21 @@ "node": "^18 || >=20" } }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, "node_modules/native-promise-only": { "version": "0.8.1", "license": "MIT" @@ -25538,6 +26160,21 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "engines": { + "node": ">= 14.16" + } + }, "node_modules/pbf": { "version": "3.3.0", "license": "BSD-3-Clause", @@ -28288,6 +28925,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, "node_modules/signal-exit": { "version": "3.0.7", "dev": true, @@ -28628,6 +29271,12 @@ "node": ">=8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, "node_modules/static-eval": { "version": "2.1.1", "license": "MIT", @@ -28635,6 +29284,12 @@ "escodegen": "^2.1.0" } }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "license": "MIT", @@ -28915,6 +29570,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true + }, "node_modules/strong-log-transformer": { "version": "2.1.0", "dev": true, @@ -29541,14 +30214,98 @@ "version": "1.3.3", "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true + }, "node_modules/tinycolor2": { "version": "1.6.0", "license": "MIT" }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, "node_modules/tinyqueue": { "version": "2.0.3", "license": "ISC" }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tmp": { "version": "0.2.3", "dev": true, @@ -30621,6 +31378,40 @@ "version": "1.1.1", "license": "MIT" }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, "node_modules/upath": { "version": "2.0.1", "dev": true, @@ -30889,6 +31680,138 @@ } } }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vt-pbf": { "version": "3.1.3", "license": "MIT", @@ -31158,6 +32081,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wicked-good-xpath": { "version": "1.3.0", "license": "MIT" @@ -35762,7 +36701,263 @@ "devDependencies": { "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", "@types/node": "^24.5.0", - "tsx": "^4.20.5" + "jest": "^30.2.0", + "tsx": "^4.20.5", + "vitest": "^3.2.4" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "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" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" } }, "plugins/python-remote-file-source/test-node-client/node_modules/@deephaven/jsapi-types": { @@ -35771,6 +36966,331 @@ "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==", "dev": true }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, + "dependencies": { + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "dev": true, + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true + }, + "plugins/python-remote-file-source/test-node-client/node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, "plugins/python-remote-file-source/test-node-client/node_modules/@types/node": { "version": "24.7.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", @@ -35780,12 +37300,873 @@ "undici-types": "~7.14.0" } }, + "plugins/python-remote-file-source/test-node-client/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/cjs-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", + "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "dev": true + }, + "plugins/python-remote-file-source/test-node-client/node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, + "dependencies": { + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, + "dependencies": { + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, + "dependencies": { + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, + "dependencies": { + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "plugins/python-remote-file-source/test-node-client/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "plugins/python-remote-file-source/test-node-client/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "plugins/python-remote-file-source/test-node-client/node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "plugins/python-remote-file-source/test-node-client/node_modules/undici-types": { "version": "7.14.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", "dev": true }, + "plugins/python-remote-file-source/test-node-client/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "plugins/simple-pivot/src/js": { "name": "@deephaven/js-plugin-simple-pivot", "version": "0.0.3-dev.2", diff --git a/package.json b/package.json index 52cb38e38..b89b60ab3 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "test": "jest --watch --changedSince origin/main", "test:unit": "jest --config jest.config.unit.cjs", "test:lint": "jest --config jest.config.lint.cjs", + "test:remote-file-source": "npm run test --workspace=@deephaven/python-remote-file-source-test-client --", "test:ci": "run-p test:ci:*", "test:ci:unit": "jest --config jest.config.unit.cjs --ci --cacheDirectory $PWD/.jest-cache", "test:ci:lint": "jest --config jest.config.lint.cjs --ci --cacheDirectory $PWD/.jest-cache", diff --git a/plugins/python-remote-file-source/test-node-client/package.json b/plugins/python-remote-file-source/test-node-client/package.json index e3e1f232f..85a77f680 100644 --- a/plugins/python-remote-file-source/test-node-client/package.json +++ b/plugins/python-remote-file-source/test-node-client/package.json @@ -9,12 +9,15 @@ "license": "Apache-2.0", "type": "module", "scripts": { - "start": "tsx src/index.mts" + "start": "tsx src/index.mts", + "test": "vitest" }, "devDependencies": { "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", "@types/node": "^24.5.0", - "tsx": "^4.20.5" + "jest": "^30.2.0", + "tsx": "^4.20.5", + "vitest": "^3.2.4" }, "dependencies": { "@deephaven/jsapi-nodejs": "1.7.1", diff --git a/plugins/python-remote-file-source/test-node-client/src/constants.mts b/plugins/python-remote-file-source/test-node-client/src/constants.mts new file mode 100644 index 000000000..d2e834bae --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/constants.mts @@ -0,0 +1,8 @@ +import path from 'node:path'; + +export const SERVER_URL = new URL('http://localhost:10000/'); +export const PSK = 'plugins.repo.test' as const; +export const TEST_WORKSPACE_PATH = path.resolve( + import.meta.dirname, + '../workspace' +); diff --git a/plugins/python-remote-file-source/test-node-client/src/index.mts b/plugins/python-remote-file-source/test-node-client/src/index.mts index 4cdd8921c..874ff8487 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.mts @@ -1,22 +1,15 @@ -import fs from 'node:fs'; import assert from 'node:assert'; -import path from 'node:path'; -import { initDh, initPlugin } from './utils.mjs'; +import { PSK, SERVER_URL, TEST_WORKSPACE_PATH } from './constants.mjs'; import { PythonModuleMap } from './PythonModuleMap.mjs'; +import { getWorkspaceFileSource, initDh, initPlugin } from './utils.mjs'; console.log('Node.js version:', process.version); -const SERVER_URL = new URL('http://localhost:10000/'); -const PSK = 'plugins.repo.test' as const; -const TEST_WORKSPACE_PATH = path.resolve(import.meta.dirname, '../workspace'); - -const TEST_RELATIVE_IMPORTS_SOURCE = await fs.promises.readFile( - path.join(TEST_WORKSPACE_PATH, 'test_relative_imports.py'), - 'utf-8' +const TEST_RELATIVE_IMPORTS_SOURCE = await getWorkspaceFileSource( + 'test_relative_imports.py' ); -const TEST_ABSOLUTE_IMPORTS_SOURCE = await fs.promises.readFile( - path.join(TEST_WORKSPACE_PATH, 'test_absolute_imports.py'), - 'utf-8' +const TEST_ABSOLUTE_IMPORTS_SOURCE = await getWorkspaceFileSource( + 'test_absolute_imports.py' ); const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); diff --git a/plugins/python-remote-file-source/test-node-client/src/index.spec.mts b/plugins/python-remote-file-source/test-node-client/src/index.spec.mts new file mode 100644 index 000000000..0d361a02a --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/src/index.spec.mts @@ -0,0 +1,27 @@ +import { beforeEach, describe, expect, it } from 'vitest'; +import type { dh as DhType } from '@deephaven/jsapi-types'; +import { PSK, SERVER_URL, TEST_WORKSPACE_PATH } from './constants.mjs'; +import PythonModuleMap from './PythonModuleMap.mjs'; +import { getWorkspaceFileSource, initDh, initPlugin } from './utils.mjs'; + +describe('Python remote file source plugin tests', () => { + let runCode: (code: string) => Promise; + + beforeEach(async () => { + const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); + const { session } = await initDh(SERVER_URL, PSK); + runCode = (await initPlugin(pythonModuleMap, session)).runCode; + }); + + it('should resolve packages with relative imports', async () => { + const testScript = await getWorkspaceFileSource('test_relative_imports.py'); + const result = await runCode(testScript); + expect(result.changes.created[0].title).toBe('simple_ticking'); + }); + + it('should resolve packages with absolute imports', async () => { + const testScript = await getWorkspaceFileSource('test_absolute_imports.py'); + const result = await runCode(testScript); + expect(result.changes.created[0].title).toBe('simple_ticking_absolute'); + }); +}); diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index 9db9dcf69..0e7944125 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -1,10 +1,10 @@ import fs from 'node:fs'; import path from 'node:path'; -import { nanoid } from 'nanoid'; import { loadDhModules, NodeHttp2gRPCTransport } from '@deephaven/jsapi-nodejs'; import type { dh as DhType } from '@deephaven/jsapi-types'; import { Msg, type JsonRpcRequest, type JsonRpcResponse } from './jsonRpc.mjs'; import type PythonModuleMap from './PythonModuleMap.mjs'; +import { TEST_WORKSPACE_PATH } from './constants.mjs'; export const AUTH_HANDLER_TYPE_PSK = 'io.deephaven.authentication.psk.PskAuthenticationHandler'; @@ -122,6 +122,18 @@ export function getSetExecutionContextScript( return `${PLUGIN_VARIABLE}.set_execution_context(${connectionIdStr}, ${moduleFullnamesStr})`; } +/** + * Get a file relative to the test Python workspace. + * @param relativeFilePath The file path relative to the test workspace. + * @returns The file contents as a string. + */ +export async function getWorkspaceFileSource(relativeFilePath: string) { + return fs.promises.readFile( + path.join(TEST_WORKSPACE_PATH, relativeFilePath), + 'utf-8' + ); +} + /** * Initialize a Deephaven api, client, connection, and session. * @param serverUrl The URL of the Deephaven server. From b0f5f11b4483dc72592f08fc8fa584343ed756ef Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 15:27:00 -0500 Subject: [PATCH 12/40] server status checks (#DH-19715) --- .../test-node-client/src/constants.mts | 29 +++++++ .../test-node-client/src/index.spec.mts | 9 +- .../test-node-client/src/utils.mts | 82 +++++++++++++------ 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/plugins/python-remote-file-source/test-node-client/src/constants.mts b/plugins/python-remote-file-source/test-node-client/src/constants.mts index d2e834bae..197b796e0 100644 --- a/plugins/python-remote-file-source/test-node-client/src/constants.mts +++ b/plugins/python-remote-file-source/test-node-client/src/constants.mts @@ -1,5 +1,34 @@ import path from 'node:path'; +export const AUTH_HANDLER_TYPE_PSK = + 'io.deephaven.authentication.psk.PskAuthenticationHandler'; + +export const CN_ID = '12345' as const; + +export const DH_PYTHON_REMOTE_SOURCE_PLUGIN_NAME = + '@deephaven/js-plugin-python-remote-file-source'; + +// Alias for `dh.Widget.EVENT_MESSAGE` to avoid having to pass in a `dh` instance +// to util functions that only need the event name. +export const DH_WIDGET_EVENT_MESSAGE = 'message' as const; + +export const PLUGIN_VARIABLE = '__deephaven_vscode' as const; + +export const PLUGIN_CLASS = 'DeephavenPythonRemoteFileSourcePlugin' as const; + +export const PLUGIN_QUERY = { + name: PLUGIN_VARIABLE, + type: PLUGIN_CLASS, +}; + +export const DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT = [ + 'try:', + ` ${PLUGIN_VARIABLE}`, + 'except NameError:', + ' from deephaven.python_remote_file_source import PluginObject as DeephavenRemoteFileSourcePlugin', + ` ${PLUGIN_VARIABLE} = DeephavenRemoteFileSourcePlugin()`, +].join('\n'); + export const SERVER_URL = new URL('http://localhost:10000/'); export const PSK = 'plugins.repo.test' as const; export const TEST_WORKSPACE_PATH = path.resolve( diff --git a/plugins/python-remote-file-source/test-node-client/src/index.spec.mts b/plugins/python-remote-file-source/test-node-client/src/index.spec.mts index 0d361a02a..1c92ac17e 100644 --- a/plugins/python-remote-file-source/test-node-client/src/index.spec.mts +++ b/plugins/python-remote-file-source/test-node-client/src/index.spec.mts @@ -2,12 +2,19 @@ import { beforeEach, describe, expect, it } from 'vitest'; import type { dh as DhType } from '@deephaven/jsapi-types'; import { PSK, SERVER_URL, TEST_WORKSPACE_PATH } from './constants.mjs'; import PythonModuleMap from './PythonModuleMap.mjs'; -import { getWorkspaceFileSource, initDh, initPlugin } from './utils.mjs'; +import { + assertServerIsReady, + getWorkspaceFileSource, + initDh, + initPlugin, +} from './utils.mjs'; describe('Python remote file source plugin tests', () => { let runCode: (code: string) => Promise; beforeEach(async () => { + await assertServerIsReady(); + const pythonModuleMap = await PythonModuleMap.create(TEST_WORKSPACE_PATH); const { session } = await initDh(SERVER_URL, PSK); runCode = (await initPlugin(pythonModuleMap, session)).runCode; diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index 0e7944125..46bd01b8a 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -4,33 +4,17 @@ import { loadDhModules, NodeHttp2gRPCTransport } from '@deephaven/jsapi-nodejs'; import type { dh as DhType } from '@deephaven/jsapi-types'; import { Msg, type JsonRpcRequest, type JsonRpcResponse } from './jsonRpc.mjs'; import type PythonModuleMap from './PythonModuleMap.mjs'; -import { TEST_WORKSPACE_PATH } from './constants.mjs'; - -export const AUTH_HANDLER_TYPE_PSK = - 'io.deephaven.authentication.psk.PskAuthenticationHandler'; - -const CN_ID = '12345' as const; - -// Alias for `dh.Widget.EVENT_MESSAGE` to avoid having to pass in a `dh` instance -// to util functions that only need the event name. -export const DH_WIDGET_EVENT_MESSAGE = 'message' as const; - -export const PLUGIN_VARIABLE = '__deephaven_vscode' as const; - -export const PLUGIN_CLASS = 'DeephavenPythonRemoteFileSourcePlugin' as const; - -export const PLUGIN_QUERY = { - name: PLUGIN_VARIABLE, - type: PLUGIN_CLASS, -}; - -export const DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT = [ - 'try:', - ` ${PLUGIN_VARIABLE}`, - 'except NameError:', - ' from deephaven.python_remote_file_source import PluginObject as DeephavenRemoteFileSourcePlugin', - ` ${PLUGIN_VARIABLE} = DeephavenRemoteFileSourcePlugin()`, -].join('\n'); +import { + AUTH_HANDLER_TYPE_PSK, + CN_ID, + DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT, + DH_PYTHON_REMOTE_SOURCE_PLUGIN_NAME, + DH_WIDGET_EVENT_MESSAGE, + PLUGIN_QUERY, + PLUGIN_VARIABLE, + SERVER_URL, + TEST_WORKSPACE_PATH, +} from './constants.mjs'; /** * Create a message handler for the given plugin that responds to fetch_module @@ -178,6 +162,15 @@ export async function initDh( return { dh, client, cn, session }; } +/** + * Initialize a client to the Python remote file source plugin. Returns an + * augmented `runCode` function that will run scripts with the appropropriate + * execution context expected by the plugin. + * @param pythonModuleMap PythonModuleMap instance for resolving Python module + * file source content + * @param session Deephaven session to connect to + * @returns An object containing the augmented `runCode` function. + */ export async function initPlugin( pythonModuleMap: PythonModuleMap, session: DhType.IdeSession @@ -212,6 +205,41 @@ export async function initPlugin( }; } +/** + * Check if a plugin is installed on the given worker. + * @param workerUrl URL of the Core / Core+ worker + * @param pluginName Name of the plugin to check for + * @returns Promise that resolves to true if the plugin is installed, false otherwise + */ +export async function isPluginInstalled(pluginName: string): Promise { + const pluginsManifestUrl = new URL('/js-plugins/manifest.json', SERVER_URL); + + try { + const response = await fetch(pluginsManifestUrl, { method: 'GET' }); + const manifestJson: { plugins: { name: string }[] } = await response.json(); + + return manifestJson.plugins.some(plugin => plugin.name === pluginName); + } catch (err) { + console.error('Error checking for local execution plugin', err); + return false; + } +} + +/** + * Assert that DH server is running and plugin is installed. + */ +export async function assertServerIsReady(): Promise { + try { + await fetch(SERVER_URL, { method: 'HEAD' }); + } catch (err) { + throw new Error(`Deephaven server not reachable at ${SERVER_URL}.`); + } + + if (!(await isPluginInstalled(DH_PYTHON_REMOTE_SOURCE_PLUGIN_NAME))) { + throw new Error('Python remote file source plugin is not installed.'); + } +} + /** * Set the connection id and top level module names in the server execution context. * @param session The ide session to run the code in. From f81fff4654b041f061e151b2f0705ac00acb2a31 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 15:35:09 -0500 Subject: [PATCH 13/40] Vitest config (#DH-19715) --- .../test-node-client/vitest.config.mts | 7 +++++++ vitest.config.mts | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 plugins/python-remote-file-source/test-node-client/vitest.config.mts create mode 100644 vitest.config.mts diff --git a/plugins/python-remote-file-source/test-node-client/vitest.config.mts b/plugins/python-remote-file-source/test-node-client/vitest.config.mts new file mode 100644 index 000000000..0b22dcb2c --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['src/**/*.spec.mts'], + }, +}); diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 000000000..46bd3e861 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + projects: ['plugins/python-remote-file-source/test-node-client'], + }, +}); From 1bc7160ed6946a79e51b3edbbeefc8a7954b3020 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 16:19:58 -0500 Subject: [PATCH 14/40] Removed incorrectly committed file (#DH-19715) --- plugins/example-theme/src/js/dist/index.js | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 plugins/example-theme/src/js/dist/index.js diff --git a/plugins/example-theme/src/js/dist/index.js b/plugins/example-theme/src/js/dist/index.js deleted file mode 100644 index c74d8cb02..000000000 --- a/plugins/example-theme/src/js/dist/index.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -const styleContent = "/* override the inherited base theme by scoping variables to :root */\n:root {\n /*\n ============ PALETTE ===========\n GRAY 50, 75, 100, 200, 300, 400, 500, 600, 700, 800, 900\n\n RED, ORANGE, YELLOW, CHARTREUSE, CELERY, GREEN, SEAFOAM,\n CYAN, BLUE, INDIGO, PURPLE, FUSCIA AND MAGENTA\n 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400\n\n Use any srgb color space value (hex, rgb, hsl, etc) to define a color.\n\n See for reference: \n github repo deephaven/web-client-ui\n /packages/components/src/theme/theme-light/theme-light-palette.css\n */\n\n /* Create a custom gray palette for background colors */\n --dh-color-gray-50: hsl(30, 100%, 99.22%);\n --dh-color-gray-75: hsl(30, 100%, 97.65%);\n --dh-color-gray-100: hsl(27.69, 100%, 94.9%);\n --dh-color-gray-200: hsl(29.19, 78.72%, 90.78%);\n --dh-color-gray-300: hsl(28.33, 58.06%, 87.84%);\n --dh-color-gray-400: hsl(28, 18.99%, 69.02%);\n --dh-color-gray-500: hsl(27.5, 10.34%, 54.51%);\n --dh-color-gray-600: hsl(26.67, 8.57%, 41.18%);\n --dh-color-gray-700: hsl(25, 9.38%, 25.1%);\n --dh-color-gray-800: hsl(34.29, 10.77%, 12.75%);\n --dh-color-gray-900: hsl(0, 0%, 0%);\n\n /* Create a custom seafoam palette */\n --dh-color-seafoam-100: hsl(185, 30%, 92.16%);\n --dh-color-seafoam-200: hsl(186, 31.25%, 87.45%);\n --dh-color-seafoam-300: hsl(186.67, 31.03%, 82.94%);\n --dh-color-seafoam-400: hsl(187.14, 32.81%, 74.9%);\n --dh-color-seafoam-500: hsl(186.43, 32.18%, 65.88%);\n --dh-color-seafoam-600: hsl(186.86, 31.82%, 56.86%);\n --dh-color-seafoam-700: hsl(186.43, 34.43%, 47.84%);\n --dh-color-seafoam-800: hsl(186.19, 49.74%, 38.24%);\n --dh-color-seafoam-900: hsl(185.17, 84.06%, 27.06%);\n --dh-color-seafoam-1000: hsl(185.61, 100%, 20.98%);\n --dh-color-seafoam-1100: hsl(186.21, 100%, 17.06%);\n --dh-color-seafoam-1200: hsl(187.06, 100%, 13.33%);\n --dh-color-seafoam-1300: hsl(187.2, 100%, 9.8%);\n --dh-color-seafoam-1400: hsl(188.33, 100%, 7.06%);\n\n /* Create a custom green palette */\n --dh-color-green-100: hsl(102.35, 39.53%, 91.57%);\n --dh-color-green-200: hsl(102, 41.67%, 85.88%);\n --dh-color-green-300: hsl(101.43, 41.18%, 80%);\n --dh-color-green-400: hsl(100.33, 40.94%, 70.78%);\n --dh-color-green-500: hsl(99.49, 39.7%, 60.98%);\n --dh-color-green-600: hsl(98.13, 38.4%, 50.98%);\n --dh-color-green-700: hsl(96.22, 53.11%, 40.98%);\n --dh-color-green-800: hsl(91.34, 90.54%, 29.02%);\n --dh-color-green-900: hsl(93.72, 100%, 23.73%);\n --dh-color-green-1000: hsl(96.6, 100%, 19.61%);\n --dh-color-green-1100: hsl(99.26, 100%, 15.88%);\n --dh-color-green-1200: hsl(101.9, 100%, 12.35%);\n --dh-color-green-1300: hsl(105.65, 100%, 9.02%);\n --dh-color-green-1400: hsl(109.09, 100%, 6.47%);\n\n /* Create a custom red palette */\n --dh-color-red-100: hsl(10, 100%, 95.29%);\n --dh-color-red-200: hsl(8.78, 100%, 91.96%);\n --dh-color-red-300: hsl(9.15, 100%, 88.43%);\n --dh-color-red-400: hsl(8.47, 100%, 83.33%);\n --dh-color-red-500: hsl(8.28, 100%, 77.25%);\n --dh-color-red-600: hsl(7.03, 96.03%, 70.39%);\n --dh-color-red-700: hsl(5.85, 87.23%, 63.14%);\n --dh-color-red-800: hsl(4.67, 77.59%, 54.51%);\n --dh-color-red-900: hsl(2.14, 86.73%, 44.31%);\n --dh-color-red-1000: hsl(0, 100%, 35.29%);\n --dh-color-red-1100: hsl(0, 100%, 28.63%);\n --dh-color-red-1200: hsl(0, 100%, 22.75%);\n --dh-color-red-1300: hsl(0, 100%, 17.25%);\n --dh-color-red-1400: hsl(0, 100%, 12.94%);\n\n /*\n ============ SEMANTIC VARIABLES ===========\n Assign things like accent colors, apply how background colors\n are mapped, positive/negative colors, etc. \n \n See: \n /packages/components/src/theme/theme-light/theme-light-semantic.css\n */\n\n /*\n Assign the accent colors to use seafoam. We could have assigned colors \n directly to accent-XXX but by first setting our brand color to the \n nearest palette color it allows it to also be exposed as a color option \n in color pickers within the UI.\n */\n\n --dh-color-accent-100: var(--dh-color-seafoam-100);\n --dh-color-accent-200: var(--dh-color-seafoam-200);\n --dh-color-accent-300: var(--dh-color-seafoam-300);\n --dh-color-accent-400: var(--dh-color-seafoam-400);\n --dh-color-accent-500: var(--dh-color-seafoam-500);\n --dh-color-accent-600: var(--dh-color-seafoam-600);\n --dh-color-accent-700: var(--dh-color-seafoam-700);\n --dh-color-accent-800: var(--dh-color-seafoam-800);\n --dh-color-accent-900: var(--dh-color-seafoam-900);\n --dh-color-accent-1000: var(--dh-color-seafoam-1000);\n --dh-color-accent-1100: var(--dh-color-seafoam-1100);\n --dh-color-accent-1200: var(--dh-color-seafoam-1200);\n --dh-color-accent-1300: var(--dh-color-seafoam-1300);\n --dh-color-accent-1400: var(--dh-color-seafoam-1400);\n\n /*\n ============ COMPONENT SPECIFIC SEMANTIC VARIABLES ===========\n Override specific colors to components like grid, plots, code editor, etc.\n\n See: \n /packages/components/src/theme/theme-light/theme-dark-components.css\n /packages/components/src/theme/theme-light/theme-dark-semantic-grid.css\n /packages/components/src/theme/theme-light/theme-dark-semantic-charts.css\n /packages/components/src/theme/theme-light/theme-dark-editor.css\n */\n\n --dh-color-grid-header-bg: var(--dh-color-gray-100);\n --dh-color-grid-row-0-bg: var(--dh-color-gray-200);\n --dh-color-grid-row-1-bg: var(--dh-color-gray-100);\n --dh-color-grid-date: var(--dh-color-black);\n\n /* Chart colorway is special in that it contains a space seperated \n list of colors to assign in order for each series in a chart. \n Consider including at least 10 colors. */\n --dh-color-chart-colorway: var(--dh-color-accent-bg)\n var(--dh-color-visual-green) var(--dh-color-visual-yellow)\n var(--dh-color-visual-purple) var(--dh-color-visual-orange)\n var(--dh-color-visual-red) var(--dh-color-visual-chartreuse)\n var(--dh-color-visual-fuchsia) var(--dh-color-visual-blue)\n var(--dh-color-visual-magenta) var(--dh-color-white);\n}\n\n/*\n============ CUSTOM CLASS OVERRIDES ===========\nExampe of overriding specific class color variables for one off customizations.\nUse sparingly as these are not guaranteed to be stable across releases.\n*/\n\n/* target a specific class in the DOM and override the variables or properties */\n.console-input-wrapper {\n --console-input-bg: var(--dh-color-gray-75);\n padding: 4px;\n}\n"; -const plugin = { - name: "example-theme", - // match the plugin name in the package.json, and the folder name - type: "ThemePlugin", - themes: { - name: "Example Theme", - // A human-readable name for the theme - baseTheme: "light", - // The base theme to extend from, either 'light' or 'dark' - styleContent - // this is a string containing your .css file contents, you could also manually inline css rules here - } -}; -module.exports = plugin; From 9fcd87cb6c8a1b99f101aed939aacfc482a8659e Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 16:22:37 -0500 Subject: [PATCH 15/40] Removed files (#DH-19715) --- .../_assets/plugin_map.png | Bin 52557 -> 0 bytes .../_assets/plugin_settings.png | Bin 34460 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 plugins/python-remote-file-source/_assets/plugin_map.png delete mode 100644 plugins/python-remote-file-source/_assets/plugin_settings.png diff --git a/plugins/python-remote-file-source/_assets/plugin_map.png b/plugins/python-remote-file-source/_assets/plugin_map.png deleted file mode 100644 index e7a9b1379872fb6c6f06911b58fa95a71cefa13d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52557 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 CM^G66 diff --git a/plugins/python-remote-file-source/_assets/plugin_settings.png b/plugins/python-remote-file-source/_assets/plugin_settings.png deleted file mode 100644 index 4a067730017e25dc7b2785df9c2626b0bbd5ab52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34460 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 From e48e00fee9893e0988224c64cc5fac59c088986a Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 16:41:00 -0500 Subject: [PATCH 16/40] Comments (#DH-19715) --- .../python_remote_file_source/json_rpc.py | 14 ++++++++++++ .../python_remote_file_source/logger.py | 4 ++++ .../message_stream.py | 14 ++++++++---- .../module_loader.py | 22 +++++++++++++++---- .../plugin_object.py | 20 ++++++++++++----- .../python_remote_file_source/types.py | 2 +- 6 files changed, 61 insertions(+), 15 deletions(-) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py index 9e678f023..6771335c8 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/json_rpc.py @@ -6,6 +6,11 @@ def create_request_msg(method: str, params: dict) -> JsonRpcRequest: """ Create a JSON-RPC v2 request message + Args: + method: The method to call + params: The parameters to pass to the method + Returns: + JsonRpcRequest: The JSON-RPC request message """ return { "jsonrpc": "2.0", @@ -18,6 +23,11 @@ def create_request_msg(method: str, params: dict) -> JsonRpcRequest: def create_response_msg(id: str, result: Any) -> JsonRpcResponse: """ Create a JSON-RPC v2 response message + Args: + id: The id of the request + result: The result of the request + Returns: + JsonRpcResponse: The JSON-RPC response message """ return {"jsonrpc": "2.0", "id": id, "result": result} @@ -28,6 +38,8 @@ def is_valid_json_rpc_request(msg: Any) -> TypeGuard[JsonRpcRequest]: Args: msg: The message to check + Returns: + bool: True if the message is a valid JSON-RPC request, False otherwise """ return ( isinstance(msg, dict) @@ -43,6 +55,8 @@ def is_valid_json_rpc_response(msg: Any) -> TypeGuard[JsonRpcResponse]: Args: msg: The message to check + Returns: + bool: True if the message is a valid JSON-RPC response, False otherwise """ return ( isinstance(msg, dict) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py index c0a65df13..e5c221a36 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py @@ -1,4 +1,8 @@ class Logger: + """ + Basic scoped logger class with different log levels. + """ + def __init__(self, name: str): self.name = name diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py index 6a99a6e3f..54736df8e 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -23,7 +23,7 @@ class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): A custom MessageStream between the client and the server plugin Attributes: - _client_connection: MessageStream: The connection to the client + id: Optional[str]: The connection id """ id: Optional[str] = None @@ -67,6 +67,7 @@ def send_message(self, message: JsonRpcResponse | str) -> None: Send a message to the client Args: message: The message to send (str or dict) + Returns: None """ if isinstance(message, dict): message = json.dumps(message) @@ -76,6 +77,10 @@ def send_message(self, message: JsonRpcResponse | str) -> None: def on_data(self, payload: bytes, references: list[Any]) -> None: """ Handle a payload from the client. If it is a JSON-RPC v2 response with a matching id, set the result. + Args: + payload: The payload from the client + references: Any references (not used) + Returns: None """ if self._plugin is None: logger.error("PluginObject is None, cannot handle on_data") @@ -122,6 +127,8 @@ def on_data(self, payload: bytes, references: list[Any]) -> None: async def request_data(self, request_msg: JsonRpcRequest) -> JsonRpcResponse: """ Request data from the client asynchronously, waiting for a response. + Args: + request_msg: The JSON-RPC request message to send Returns: Any: The data from the client """ @@ -144,9 +151,8 @@ def request_data_sync( """ Synchronously request data from the client via JSON-RPC, blocking until a response is received. Args: - method: The JSON-RPC method name - params: The parameters to send - timeout: Timeout in seconds + request_msg: The JSON-RPC request message to send + timeout: The timeout in seconds to wait for a response (default: 1.0) Returns: The JSON-RPC response from the client Raises: diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py index ddb0c5ff2..adc400633 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py @@ -5,7 +5,7 @@ from .plugin_object import PluginObject from .json_rpc import create_request_msg from .logger import Logger -from .types import LocalModuleDescriptor, MessageStreamRequestInterface +from .types import RemoteModuleDescriptor, MessageStreamRequestInterface logger = Logger("RemoteMetaPathFinder") @@ -16,15 +16,21 @@ class RemoteModuleLoader: A custom module loader that loads modules from a remote source. """ - _module_descriptor: LocalModuleDescriptor | None + _module_descriptor: RemoteModuleDescriptor | None - def __init__(self, module_descriptor: LocalModuleDescriptor | None): + def __init__(self, module_descriptor: RemoteModuleDescriptor | None): self._module_descriptor = module_descriptor def create_module(self, spec: ModuleSpec): return None def exec_module(self, module: ModuleType): + """ + Execute the module source in the given module. + Args: + module: The module to execute the code in. + Returns: None + """ if self._module_descriptor is None: return @@ -55,13 +61,21 @@ def find_spec( path: Optional[Sequence[str]], target: Optional[ModuleType] = None, ): + """ + Find the module spec for a given module fullname. + Args: + fullname: The full name of the module to find. + path: (not used). + target: (not used). + Returns: The module spec if found, None otherwise. + """ if not self._connection or not self._plugin.is_sourced_by_execution_context( fullname, self._connection.id ): # return None so that other finder/loaders can try return None - module_spec: LocalModuleDescriptor | None = None + module_spec: RemoteModuleDescriptor | None = None try: msg = create_request_msg("fetch_module", {"module_name": fullname}) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py index 3201341e0..aa6a2e7ba 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py @@ -4,15 +4,13 @@ class PluginObject: - execution_context_connection_id: Optional[str] = None + _execution_context_connection_id: Optional[str] = None _top_level_module_fullnames: set[str] = set() """ Plugin object that holds state for the plugin. Attributes: - execution_context_connection_id: Optional[str]: The connection id of the current execution context - _top_level_module_fullnames: set[str]: The set of top level module fullnames that can be sourced by the client """ def __init__(self): @@ -24,7 +22,7 @@ def evict_module_cache(self) -> None: """ for mod_name in list(sys.modules.keys()): if self.is_sourced_by_execution_context( - mod_name, self.execution_context_connection_id + mod_name, self._execution_context_connection_id ): del sys.modules[mod_name] @@ -40,10 +38,15 @@ def is_sourced_by_execution_context( """ Check if a module fullname is included in the registered top-level module names and that the given connection id matches the current execution context. + Args: + module_fullname: The full name of the module to check. + connection_id: The connection id to check. + Returns: + bool: True if the check passes, False otherwise. """ if ( connection_id is None - or connection_id != self.execution_context_connection_id + or connection_id != self._execution_context_connection_id ): return False @@ -64,7 +67,12 @@ def set_execution_context( """ Set the execution context for the object. This includes the set of top level module fullnames that can be sourced by the client. + Args: + connection_id: The connection id for the execution context. + top_level_module_fullnames: The set of top level module fullnames. + Returns: + None """ self.evict_module_cache() - self.execution_context_connection_id = connection_id + self._execution_context_connection_id = connection_id self._top_level_module_fullnames = top_level_module_fullnames diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py index 5ba54aba7..cbc05b42e 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/types.py @@ -23,7 +23,7 @@ class JsonRpcError(TypedDict): JsonRpcResponse = Union[JsonRpcSuccess, JsonRpcError] -class LocalModuleDescriptor(TypedDict): +class RemoteModuleDescriptor(TypedDict): filepath: str source: Optional[str] From f5f4925530b9fb09bf05f05a0e9f3a83db211128 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 16:53:03 -0500 Subject: [PATCH 17/40] Updated references to old name of plugin (#DH-19715) --- plugins/python-remote-file-source/README.md | 2 +- .../src/deephaven/python_remote_file_source/logger.py | 2 +- .../deephaven/python_remote_file_source/message_stream.py | 8 ++++---- .../deephaven/python_remote_file_source/plugin_type.py | 2 +- .../src/js/src/PythonRemoteFileSourcePlugin.ts | 2 +- .../test-node-client/src/utils.mts | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md index 757ab2947..c376f1ccc 100644 --- a/plugins/python-remote-file-source/README.md +++ b/plugins/python-remote-file-source/README.md @@ -1,4 +1,4 @@ -# Deephaven Local Python Execution Plugin +# Deephaven Python Remote File Source Plugin A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py index e5c221a36..6a11f46c8 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py @@ -4,7 +4,7 @@ class Logger: """ def __init__(self, name: str): - self.name = name + self.name = "deephaven.python_remote_file_source." + name def debug(self, *args): print("[DEBUG]", f"[{self.name}]", *args) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py index 54736df8e..d032cce78 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -15,7 +15,7 @@ from .module_loader import RemoteMetaPathFinder from .types import JsonRpcRequest, JsonRpcResponse, MessageStreamRequestInterface -logger = Logger("DeephavenLocalExecPluginMessageStream") +logger = Logger("MessageStream") class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): @@ -32,14 +32,14 @@ class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): _plugin: Optional[PluginObject] = None def __init__(self, obj: PluginObject, client_connection: MesssageStreamBase): - logger.info("Creating DeephavenLocalExecPluginMessageStream") + logger.info("Creating MessageStream") super().__init__() self._plugin = obj self._client_connection = client_connection # Start the message stream. All we do is send a blank message to start. Client will respond with the initial state. # Additional messages can be sent to the client by calling on_data on the client connection at any time after this. - # These additional messages are processed in DeephavenLocalExecPluginView.tsx + # These additional messages are processed in PythonRemoteFileSourcePluginView.tsx self._client_connection.on_data(b"", []) def _deregister_meta_path_finder(self): @@ -60,7 +60,7 @@ def _register_meta_path_finder(self): count = sum( isinstance(finder, RemoteMetaPathFinder) for finder in sys.meta_path ) - logger.info("Registered LocalMetaPathFinder:", count) + logger.info("Registered RemoteMetaPathFinder:", count) def send_message(self, message: JsonRpcResponse | str) -> None: """ diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py index 2dd728017..50dd40ea3 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_type.py @@ -10,7 +10,7 @@ # The object type that will be registered with the plugin system. # The object is bidirectional, meaning it can send messages to and from the client. # A MessageStream is created for each object that is created. This needs to be saved and tied to the object. -# The value returned by name() should match supportedTypes in DeephavenLocalExecPluginPlugin.ts +# The value returned by name() should match supportedTypes in PythonRemoteFileSourcePlugin.ts class PluginType(BidirectionalObjectType): """ Defines the Element type for the Deephaven plugin system. diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts index 1ca3c4ef3..7309e737b 100644 --- a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts @@ -9,7 +9,7 @@ export const PythonRemoteFileSourcePlugin: WidgetPlugin = { // The type of plugin - this will generally be WIDGET_PLUGIN type: PluginType.WIDGET_PLUGIN, // The supported types for the plugin. This should match the value returned by `name` - // in DeephavenLocalExecPluginType in plugin_type.py + // in PluginType in plugin_type.py supportedTypes: 'DeephavenPythonRemoteFileSourcePlugin', // The component to render for the plugin component: PythonRemoteFileSourcePluginView, diff --git a/plugins/python-remote-file-source/test-node-client/src/utils.mts b/plugins/python-remote-file-source/test-node-client/src/utils.mts index 46bd01b8a..8de8f03aa 100644 --- a/plugins/python-remote-file-source/test-node-client/src/utils.mts +++ b/plugins/python-remote-file-source/test-node-client/src/utils.mts @@ -176,7 +176,7 @@ export async function initPlugin( session: DhType.IdeSession ): Promise<{ runCode: (code: string) => Promise }> { await session.runCode(DH_PYTHON_REMOTE_SOURCE_PLUGIN_INIT_SCRIPT); - console.log('Initialized Deephaven VS Code local execution plugin.'); + console.log('Initialized Deephaven Python Remote File Source Plugin.'); const plugin: DhType.Widget = await session.getObject(PLUGIN_QUERY); plugin.addEventListener( @@ -220,7 +220,7 @@ export async function isPluginInstalled(pluginName: string): Promise { return manifestJson.plugins.some(plugin => plugin.name === pluginName); } catch (err) { - console.error('Error checking for local execution plugin', err); + console.error('Error checking for plugin:', pluginName, err); return false; } } From 8fe7ebe5b1428dae600bfbd457b5b8466b1a7a79 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Tue, 7 Oct 2025 17:08:18 -0500 Subject: [PATCH 18/40] removed comment (#DH-19715) --- .../src/deephaven/python_remote_file_source/message_stream.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py index d032cce78..fbd15dd64 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -99,8 +99,7 @@ def on_data(self, payload: bytes, references: list[Any]) -> None: future_response = self._future_responses[msg["id"]] loop = future_response.get_loop() loop.call_soon_threadsafe(future_response.set_result, msg) - # Plugin client can request info to see what top-level modules are - # currently configured. + elif is_valid_json_rpc_request(msg): match msg["method"]: case "request_plugin_info": From 028b0297e4c71b3ab78d0c84c3e4bb143140bcca Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 09:03:08 -0500 Subject: [PATCH 19/40] Changed logger prefix to match plugin_type name (#DH-19715) --- .../src/deephaven/python_remote_file_source/logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py index 6a11f46c8..da9507a1a 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py @@ -4,7 +4,7 @@ class Logger: """ def __init__(self, name: str): - self.name = "deephaven.python_remote_file_source." + name + self.name = "DeephavenPythonRemoteFileSourcePlugin." + name def debug(self, *args): print("[DEBUG]", f"[{self.name}]", *args) From 62da1d96a3fae944a2b62723ce1c5ea30e0c3a6e Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 09:06:19 -0500 Subject: [PATCH 20/40] Changed logger name (#DH-19715) --- .../src/js/src/PythonRemoteFileSourcePluginView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx index 83da28039..7d6261755 100644 --- a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx @@ -21,7 +21,7 @@ const REQUEST_PLUGIN_INFO_MSG = { } as const; const log = Log.module( - '@deephaven/js-plugin-python-remote-file-source/DeephavenPythonRemoteFileSourcePluginView' + '@deephaven/js-plugin-python-remote-file-source/PythonRemoteFileSourcePluginView' ); export function PythonRemoteFileSourcePluginView( From b58bcd28f6c90f1eba7034bda2410e64cb8c241f Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 09:45:48 -0500 Subject: [PATCH 21/40] Pull package name from package.json (#DH-19715) --- .../src/js/src/PythonRemoteFileSourcePlugin.ts | 3 ++- .../src/js/src/PythonRemoteFileSourcePluginView.tsx | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts index 7309e737b..f1b1ea5e4 100644 --- a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePlugin.ts @@ -1,11 +1,12 @@ import { type WidgetPlugin, PluginType } from '@deephaven/plugin'; import { vsGraph } from '@deephaven/icons'; import { PythonRemoteFileSourcePluginView } from './PythonRemoteFileSourcePluginView'; +import pkg from '../package.json'; // Register the plugin with Deephaven export const PythonRemoteFileSourcePlugin: WidgetPlugin = { // The name of the plugin - name: '@deephaven/js-plugin-python-remote-file-source', + name: pkg.name, // The type of plugin - this will generally be WIDGET_PLUGIN type: PluginType.WIDGET_PLUGIN, // The supported types for the plugin. This should match the value returned by `name` diff --git a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx index 7d6261755..421ef69c6 100644 --- a/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx +++ b/plugins/python-remote-file-source/src/js/src/PythonRemoteFileSourcePluginView.tsx @@ -13,6 +13,7 @@ import { Icon, ListView, } from '@deephaven/components'; +import pkg from '../package.json'; const REQUEST_PLUGIN_INFO_MSG = { jsonrpc: '2.0', @@ -20,9 +21,7 @@ const REQUEST_PLUGIN_INFO_MSG = { method: 'request_plugin_info', } as const; -const log = Log.module( - '@deephaven/js-plugin-python-remote-file-source/PythonRemoteFileSourcePluginView' -); +const log = Log.module(`${pkg.name}/PythonRemoteFileSourcePluginView`); export function PythonRemoteFileSourcePluginView( props: WidgetComponentProps @@ -48,6 +47,8 @@ export function PythonRemoteFileSourcePluginView( useEffect(() => { async function init() { + log.info('Initializing widget'); + // Fetch the widget from the server const fetchedWidget = (await fetch()) as DhType.Widget; setWidget(fetchedWidget); From 7f23cada7d41afaee7050372c59423bb404b75ab Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 12:04:49 -0500 Subject: [PATCH 22/40] Made changes based on code review feedback. --- plugins/python-remote-file-source/README.md | 10 +++++----- plugins/python-remote-file-source/setup.cfg | 4 ++-- .../python_remote_file_source/message_stream.py | 15 +++------------ .../python_remote_file_source/module_loader.py | 2 +- .../python_remote_file_source/plugin_object.py | 15 +++++++-------- .../python-remote-file-source/src/js/package.json | 2 +- 6 files changed, 19 insertions(+), 29 deletions(-) diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md index c376f1ccc..6e4288b9d 100644 --- a/plugins/python-remote-file-source/README.md +++ b/plugins/python-remote-file-source/README.md @@ -1,6 +1,6 @@ # Deephaven Python Remote File Source Plugin -A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven core / core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. +A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven Core / Core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. ## Plugin Structure @@ -8,13 +8,13 @@ The `src` directory contains the Python and JavaScript code for the plugin. Within the `src` directory, the `deephaven/python_remote_file_source` directory contains the Python code, and the `js` directory contains the JavaScript code. The Python files have the following structure: -`plugin_object.py` defines a simple Python class that can send messages to the client. This object can be modified to have other plugin functionality or replaced with a different object entirely, depending on the plugin's needs. -`plugin_type.py` defines the Python type for the plugin (which is used for registration) and a simple message stream. These can be modified to handle different objects or messages. An initial message is sent from the Python side to the client, then additional messages can be sent back and forth. +`plugin_object.py` defines a simple Python class that can send messages to the client. +`plugin_type.py` defines the Python type for the plugin (which is used for registration) and a simple message stream. An initial message is sent from the Python side to the client, then additional messages can be sent back and forth. `register.py` registers the plugin with Deephaven. This file will not need to be modified for most plugins at the initial stages, but will need to be if the package is renamed or JavaScript files are moved. The JavaScript files have the following structure: `PythonRemoteFileSourcePlugin.ts` registers the plugin with Deephaven. This contains the client equivalent of the type in `plugin_type.py` and these should be kept in sync. -`PythonRemoteFileSourcePluginView.tsx` defines the plugin panel and message handling. This is where messages are received when sent from the Python side of the plugin. This file is a good starting point for adding more complex plugin functionality. +`PythonRemoteFileSourcePluginView.tsx` defines the plugin panel and message handling. This is where messages are received when sent from the Python side of the plugin. Additionally, the `test` directory contains Python tests for the plugin. It's recommended to use `tox` to run the tests, and the `tox.ini` file is included in the project. @@ -48,4 +48,4 @@ from deephaven.python_remote_file_source_plugin import ( obj = DeephavenRemoteFileSourcePlugin() ``` -A panel should appear. +A panel should appear for the plugin object showing the current configuration of the plugin. Any top-level module names that have been configured for the plugin to source remotely should show in a searchable list view. diff --git a/plugins/python-remote-file-source/setup.cfg b/plugins/python-remote-file-source/setup.cfg index e2ec0877f..d11c8ffe1 100644 --- a/plugins/python-remote-file-source/setup.cfg +++ b/plugins/python-remote-file-source/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = deephaven-plugin-python-remote-file-source -description = Deephaven plugin for sourcing Python files from a remote location +description = A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. long_description = file: README.md long_description_content_type = text/markdown version = 0.0.1.dev0 @@ -15,7 +15,7 @@ classifiers = Environment :: Plugins Topic :: Scientific/Engineering :: Visualization Development Status :: 3 - Alpha -keywords = deephaven, plugin, graph +keywords = deephaven, plugin author = Deephaven Data Labs author_email = support@deephaven.io platforms = any diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py index fbd15dd64..280b704d8 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -29,7 +29,7 @@ class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): id: Optional[str] = None _future_responses: dict[str, asyncio.Future[JsonRpcResponse]] = {} _meta_path_finder: Optional[RemoteMetaPathFinder] = None - _plugin: Optional[PluginObject] = None + _plugin: PluginObject def __init__(self, obj: PluginObject, client_connection: MesssageStreamBase): logger.info("Creating MessageStream") @@ -50,10 +50,6 @@ def _deregister_meta_path_finder(self): self._meta_path_finder = None def _register_meta_path_finder(self): - if self._plugin is None: - logger.error("PluginObject is None, cannot register meta path finder") - return - self._meta_path_finder = RemoteMetaPathFinder(self, self._plugin) sys.meta_path.insert(0, self._meta_path_finder) @@ -82,10 +78,6 @@ def on_data(self, payload: bytes, references: list[Any]) -> None: references: Any references (not used) Returns: None """ - if self._plugin is None: - logger.error("PluginObject is None, cannot handle on_data") - return - decoded_payload = io.BytesIO(payload).read().decode() try: @@ -145,13 +137,13 @@ async def request_data(self, request_msg: JsonRpcRequest) -> JsonRpcResponse: return result def request_data_sync( - self, request_msg: JsonRpcRequest, timeout: float = 1.0 + self, request_msg: JsonRpcRequest, timeout: float = 5.0 ) -> JsonRpcResponse: """ Synchronously request data from the client via JSON-RPC, blocking until a response is received. Args: request_msg: The JSON-RPC request message to send - timeout: The timeout in seconds to wait for a response (default: 1.0) + timeout: The timeout in seconds to wait for a response (default: 5.0) Returns: The JSON-RPC response from the client Raises: @@ -185,4 +177,3 @@ def on_close(self) -> None: """ logger.info("Closing connection", self.id) self._deregister_meta_path_finder() - self._plugin = None diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py index adc400633..4a09cfd38 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py @@ -69,7 +69,7 @@ def find_spec( target: (not used). Returns: The module spec if found, None otherwise. """ - if not self._connection or not self._plugin.is_sourced_by_execution_context( + if not self._connection or not self._plugin.is_sourced_by_plugin( fullname, self._connection.id ): # return None so that other finder/loaders can try diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py index aa6a2e7ba..fa3f1200e 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/plugin_object.py @@ -21,9 +21,7 @@ def evict_module_cache(self) -> None: Evict any cached modules that were loaded from the `RemoteModuleLoader`. """ for mod_name in list(sys.modules.keys()): - if self.is_sourced_by_execution_context( - mod_name, self._execution_context_connection_id - ): + if self.is_sourced_by_plugin(mod_name): del sys.modules[mod_name] def get_top_level_module_fullnames(self) -> set[str]: @@ -32,12 +30,13 @@ def get_top_level_module_fullnames(self) -> set[str]: """ return self._top_level_module_fullnames - def is_sourced_by_execution_context( - self, module_fullname: str, connection_id: Optional[str] + def is_sourced_by_plugin( + self, module_fullname: str, connection_id: Optional[str] = None ) -> bool: """ Check if a module fullname is included in the registered top-level module - names and that the given connection id matches the current execution context. + names. Optionally check if a given connection id matches the current + connection id for the current execution context. Args: module_fullname: The full name of the module to check. connection_id: The connection id to check. @@ -45,8 +44,8 @@ def is_sourced_by_execution_context( bool: True if the check passes, False otherwise. """ if ( - connection_id is None - or connection_id != self._execution_context_connection_id + connection_id is not None + and connection_id != self._execution_context_connection_id ): return False diff --git a/plugins/python-remote-file-source/src/js/package.json b/plugins/python-remote-file-source/src/js/package.json index 0a123f00f..5c33f41dc 100644 --- a/plugins/python-remote-file-source/src/js/package.json +++ b/plugins/python-remote-file-source/src/js/package.json @@ -1,7 +1,7 @@ { "name": "@deephaven/js-plugin-python-remote-file-source", "version": "0.0.1", - "description": "Deephaven plugin for sourcing Python files from a remote location", + "description": "Deephaven plugin for importing Python modules from a remote location", "keywords": [ "Deephaven", "plugin" From d88f8828711faa6e762b59f26434cc7f99bcbb6b Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 13:59:06 -0500 Subject: [PATCH 23/40] Removed custom Logger and using logging package instead (#DH-19715) --- .../python_remote_file_source/logger.py | 19 ------------------- .../message_stream.py | 15 +++++++-------- .../module_loader.py | 14 ++++++++------ 3 files changed, 15 insertions(+), 33 deletions(-) delete mode 100644 plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py deleted file mode 100644 index da9507a1a..000000000 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/logger.py +++ /dev/null @@ -1,19 +0,0 @@ -class Logger: - """ - Basic scoped logger class with different log levels. - """ - - def __init__(self, name: str): - self.name = "DeephavenPythonRemoteFileSourcePlugin." + name - - def debug(self, *args): - print("[DEBUG]", f"[{self.name}]", *args) - - def info(self, *args): - print("[INFO]", f"[{self.name}]", *args) - - def warning(self, *args): - print("[WARNING]", f"[{self.name}]", *args) - - def error(self, *args): - print("[ERROR]", f"[{self.name}]", *args) diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py index 280b704d8..2a8a4569b 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/message_stream.py @@ -1,4 +1,5 @@ import asyncio +import logging import sys import io import json @@ -11,11 +12,10 @@ is_valid_json_rpc_request, is_valid_json_rpc_response, ) -from .logger import Logger from .module_loader import RemoteMetaPathFinder from .types import JsonRpcRequest, JsonRpcResponse, MessageStreamRequestInterface -logger = Logger("MessageStream") +logger = logging.getLogger(__name__) class MessageStream(MesssageStreamBase, MessageStreamRequestInterface): @@ -56,7 +56,7 @@ def _register_meta_path_finder(self): count = sum( isinstance(finder, RemoteMetaPathFinder) for finder in sys.meta_path ) - logger.info("Registered RemoteMetaPathFinder:", count) + logger.info(f"Registered RemoteMetaPathFinder: {count}") def send_message(self, message: JsonRpcResponse | str) -> None: """ @@ -97,15 +97,14 @@ def on_data(self, payload: bytes, references: list[Any]) -> None: case "request_plugin_info": full_names = list(self._plugin.get_top_level_module_fullnames()) logger.info( - "Sending plugin info to client. Remote module count:", - len(full_names), + f"Sending plugin info to client. Remote module count: {len(full_names)}", ) self.send_message( create_response_msg(msg["id"], {"full_names": full_names}) ) case "set_connection_id": self.id = msg.get("id") - logger.info("Set connection id:", self.id) + logger.info(f"Set connection id: {self.id}") self._deregister_meta_path_finder() self._register_meta_path_finder() @@ -154,7 +153,7 @@ async def do_request(): try: return await asyncio.wait_for(self.request_data(request_msg), timeout) except Exception as ex: - logger.error("Error during request_data_sync:", ex) + logger.error("Error during request_data_sync:", exc_info=True) del self._future_responses[request_msg["id"]] raise @@ -175,5 +174,5 @@ def on_close(self) -> None: """ Close the connection """ - logger.info("Closing connection", self.id) + logger.info(f"Closing connection {self.id}") self._deregister_meta_path_finder() diff --git a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py index 4a09cfd38..71146ac66 100644 --- a/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py +++ b/plugins/python-remote-file-source/src/deephaven/python_remote_file_source/module_loader.py @@ -1,14 +1,14 @@ from importlib.machinery import ModuleSpec +import logging from types import ModuleType from typing import Optional, Sequence from .plugin_object import PluginObject from .json_rpc import create_request_msg -from .logger import Logger from .types import RemoteModuleDescriptor, MessageStreamRequestInterface -logger = Logger("RemoteMetaPathFinder") +logger = logging.getLogger(__name__) class RemoteModuleLoader: @@ -81,18 +81,20 @@ def find_spec( msg = create_request_msg("fetch_module", {"module_name": fullname}) response = self._connection.request_data_sync(msg) except Exception as err: - logger.error("Error finding external module spec:", fullname, err) + logger.error( + f"Error finding external module spec: {fullname}", exc_info=True + ) raise module_spec = response.get("result") if module_spec is None: - logger.info("Module spec not found:", fullname) + logger.info(f"Module spec not found: {fullname}") return logger.info( - "Fetched module spec:", + "Fetched module spec: %s source=%s", fullname, - "source" if module_spec.get("source") else "None", + "True" if module_spec.get("source") else "None", ) origin = module_spec.get("filepath") if module_spec else None From a10497fb989d20bafc3686a7fb4e59cb62633ab2 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 16:06:08 -0500 Subject: [PATCH 24/40] Removed unused nanoid (#DH-19715) --- package-lock.json | 193 +++++++----------- .../src/js/package.json | 2 +- .../test-node-client/package.json | 3 +- 3 files changed, 73 insertions(+), 125 deletions(-) diff --git a/package-lock.json b/package-lock.json index 25942580d..403c67d0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2117,6 +2117,13 @@ "redux": "^4.2.0" } }, + "node_modules/@deephaven/auth-plugins/node_modules/redux-thunk": { + "version": "2.4.1", + "license": "MIT", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/@deephaven/babel-preset": { "version": "0.72.0", "dev": true, @@ -3404,6 +3411,13 @@ "redux": "^4.2.0" } }, + "node_modules/@deephaven/dashboard/node_modules/redux-thunk": { + "version": "2.4.1", + "license": "MIT", + "peerDependencies": { + "redux": "^4" + } + }, "node_modules/@deephaven/eslint-config": { "version": "0.72.0", "dev": true, @@ -4332,9 +4346,9 @@ } }, "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.2", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", - "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==" }, "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/log": { "version": "1.5.3", @@ -32756,6 +32770,15 @@ "resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.3.9.tgz", "integrity": "sha512-drcRiJVencliC8LnRwk4MmeQDNNBg5GzmOoLFihO3/k0CUK0VF/N+2nc7iFozwaNG0btSB9vAhYuJLjqHMtRrQ==" }, + "plugins/ag-grid/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "license": "MIT", + "peerDependencies": { + "redux": "^4" + } + }, "plugins/ag-grid/src/js/node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -33456,6 +33479,13 @@ "node": ">=16" } }, + "plugins/matplotlib/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "license": "MIT", + "peerDependencies": { + "redux": "^4" + } + }, "plugins/matplotlib/src/js/node_modules/typescript": { "version": "4.9.5", "dev": true, @@ -35788,6 +35818,14 @@ "node": ">=18.0.0" } }, + "plugins/plotly-express/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, "plugins/plotly-express/src/js/node_modules/rehype-mathjax": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/rehype-mathjax/-/rehype-mathjax-4.0.3.tgz", @@ -35830,7 +35868,6 @@ } }, "plugins/python-remote-file-source/src/js": { - "name": "@deephaven/js-plugin-python-remote-file-source", "version": "0.0.1", "license": "Apache-2.0", "dependencies": { @@ -35850,7 +35887,7 @@ "@vitejs/plugin-react-swc": "^3.0.0", "react": "^17.0.2", "typescript": "^4.5.4", - "vite": "~4.1.4" + "vite": "^5.4.6" }, "peerDependencies": { "react": "^17.0.2", @@ -36154,9 +36191,9 @@ } }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.2", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", - "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==" }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-bootstrap/node_modules/@deephaven/react-hooks": { "version": "0.85.35", @@ -36271,9 +36308,9 @@ } }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/jsapi-utils/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.2", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", - "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==" }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/log": { "version": "0.85.19", @@ -36467,9 +36504,9 @@ } }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.2", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", - "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==" + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==" }, "plugins/python-remote-file-source/src/js/node_modules/@deephaven/plugin/node_modules/@deephaven/react-hooks": { "version": "0.85.35", @@ -36570,64 +36607,11 @@ "node": ">=16" } }, - "plugins/python-remote-file-source/src/js/node_modules/esbuild": { - "version": "0.16.17", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", - "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.16.17", - "@esbuild/android-arm64": "0.16.17", - "@esbuild/android-x64": "0.16.17", - "@esbuild/darwin-arm64": "0.16.17", - "@esbuild/darwin-x64": "0.16.17", - "@esbuild/freebsd-arm64": "0.16.17", - "@esbuild/freebsd-x64": "0.16.17", - "@esbuild/linux-arm": "0.16.17", - "@esbuild/linux-arm64": "0.16.17", - "@esbuild/linux-ia32": "0.16.17", - "@esbuild/linux-loong64": "0.16.17", - "@esbuild/linux-mips64el": "0.16.17", - "@esbuild/linux-ppc64": "0.16.17", - "@esbuild/linux-riscv64": "0.16.17", - "@esbuild/linux-s390x": "0.16.17", - "@esbuild/linux-x64": "0.16.17", - "@esbuild/netbsd-x64": "0.16.17", - "@esbuild/openbsd-x64": "0.16.17", - "@esbuild/sunos-x64": "0.16.17", - "@esbuild/win32-arm64": "0.16.17", - "@esbuild/win32-ia32": "0.16.17", - "@esbuild/win32-x64": "0.16.17" - } - }, "plugins/python-remote-file-source/src/js/node_modules/monaco-editor": { "version": "0.41.0", "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz", "integrity": "sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==" }, - "plugins/python-remote-file-source/src/js/node_modules/rollup": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", - "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", - "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "plugins/python-remote-file-source/src/js/node_modules/typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", @@ -36641,62 +36625,11 @@ "node": ">=4.2.0" } }, - "plugins/python-remote-file-source/src/js/node_modules/vite": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.1.5.tgz", - "integrity": "sha512-zJ0RiVkf61kpd7O+VtU6r766xgnTaIknP/lR6sJTZq3HtVJ3HGnTo5DaJhTUtYoTyS/CQwZ6yEVdc/lrmQT7dQ==", - "dev": true, - "dependencies": { - "esbuild": "^0.16.14", - "postcss": "^8.4.21", - "resolve": "^1.22.1", - "rollup": "^3.10.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, "plugins/python-remote-file-source/test-node-client": { - "name": "@deephaven/python-remote-file-source-test-client", "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "@deephaven/jsapi-nodejs": "1.7.1", - "nanoid": "^5.0.7" + "@deephaven/jsapi-nodejs": "1.7.1" }, "devDependencies": { "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", @@ -36961,9 +36894,9 @@ } }, "plugins/python-remote-file-source/test-node-client/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.2", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.2.tgz", - "integrity": "sha512-A8BuS1Eh7/2L3o5ySyyLkicYMrKx5lefhQYnLzb7eExd2i/STICGEG/ayoLsFWS9AJusnRg+zQNwPb+nLar8Fw==", + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==", "dev": true }, "plugins/python-remote-file-source/test-node-client/node_modules/@jest/console": { @@ -39029,6 +38962,14 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz", "integrity": "sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==" }, + "plugins/simple-pivot/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, "plugins/simple-pivot/src/js/node_modules/rollup": { "version": "3.29.5", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", @@ -40542,6 +40483,14 @@ "node": ">=18.0.0" } }, + "plugins/ui/src/js/node_modules/redux-thunk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz", + "integrity": "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==", + "peerDependencies": { + "redux": "^4" + } + }, "plugins/ui/src/js/node_modules/typescript": { "version": "4.9.5", "dev": true, diff --git a/plugins/python-remote-file-source/src/js/package.json b/plugins/python-remote-file-source/src/js/package.json index 5c33f41dc..ea2c1fd80 100644 --- a/plugins/python-remote-file-source/src/js/package.json +++ b/plugins/python-remote-file-source/src/js/package.json @@ -20,7 +20,7 @@ "@types/react-dom": "^17.0.2", "react": "^17.0.2", "typescript": "^4.5.4", - "vite": "~4.1.4" + "vite": "^5.4.6" }, "peerDependencies": { "react": "^17.0.2", diff --git a/plugins/python-remote-file-source/test-node-client/package.json b/plugins/python-remote-file-source/test-node-client/package.json index 85a77f680..77a35d364 100644 --- a/plugins/python-remote-file-source/test-node-client/package.json +++ b/plugins/python-remote-file-source/test-node-client/package.json @@ -20,7 +20,6 @@ "vitest": "^3.2.4" }, "dependencies": { - "@deephaven/jsapi-nodejs": "1.7.1", - "nanoid": "^5.0.7" + "@deephaven/jsapi-nodejs": "1.7.1" } } From dc7e6ff54e8a0dfa4b781497e587995547f625e8 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 16:06:20 -0500 Subject: [PATCH 25/40] Changed vite.config.ts to .js (#DH-19715) --- .../python-remote-file-source/src/js/.eslintrc.js | 13 ------------- .../src/js/{vite.config.js => vite.config.ts} | 3 ++- 2 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 plugins/python-remote-file-source/src/js/.eslintrc.js rename plugins/python-remote-file-source/src/js/{vite.config.js => vite.config.ts} (91%) diff --git a/plugins/python-remote-file-source/src/js/.eslintrc.js b/plugins/python-remote-file-source/src/js/.eslintrc.js deleted file mode 100644 index aad277126..000000000 --- a/plugins/python-remote-file-source/src/js/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = { - root: true, - extends: ['@deephaven/eslint-config'], - overrides: [ - { - files: ['**/*.@(ts|tsx)'], - parserOptions: { - project: ['./tsconfig.json'], - tsconfigRootDir: __dirname, - }, - }, - ], -}; diff --git a/plugins/python-remote-file-source/src/js/vite.config.js b/plugins/python-remote-file-source/src/js/vite.config.ts similarity index 91% rename from plugins/python-remote-file-source/src/js/vite.config.js rename to plugins/python-remote-file-source/src/js/vite.config.ts index a5d534830..6f5ac6cb6 100644 --- a/plugins/python-remote-file-source/src/js/vite.config.js +++ b/plugins/python-remote-file-source/src/js/vite.config.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react-swc'; @@ -23,7 +24,7 @@ export default defineConfig(({ mode }) => ({ '@deephaven/jsapi-bootstrap', '@deephaven/jsapi-types', '@deephaven/log', - '@deephaven/plugin' + '@deephaven/plugin', ], }, }, From 77fff3c5ab4e4fa71865004ef5e0cc96111b8872 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 16:39:56 -0500 Subject: [PATCH 26/40] removed .nvmrc (#DH-19715) --- plugins/python-remote-file-source/src/js/.nvmrc | 1 - 1 file changed, 1 deletion(-) delete mode 100644 plugins/python-remote-file-source/src/js/.nvmrc diff --git a/plugins/python-remote-file-source/src/js/.nvmrc b/plugins/python-remote-file-source/src/js/.nvmrc deleted file mode 100644 index a2ad731bb..000000000 --- a/plugins/python-remote-file-source/src/js/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v18.20.4 \ No newline at end of file From 5780afb27811b0d5f16dd4c2031b24fb13ba23a7 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Wed, 8 Oct 2025 18:41:54 -0500 Subject: [PATCH 27/40] Removed nodejs test project from package.json and restored package-lock in attempt to fix e2e tests (#DH-19715) --- package-lock.json | 2957 +-------------------------------------------- package.json | 3 +- 2 files changed, 12 insertions(+), 2948 deletions(-) diff --git a/package-lock.json b/package-lock.json index 403c67d0d..333702e06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,7 @@ "name": "deephaven-plugins", "version": "0.1.0", "workspaces": [ - "./plugins/*/src/js/", - "./plugins/python-remote-file-source/test-node-client" + "./plugins/*/src/js/" ], "devDependencies": { "@deephaven/babel-preset": "^0.72.0", @@ -310,15 +309,6 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.25.9", "dev": true, @@ -4331,50 +4321,6 @@ "react": "^17.x" } }, - "node_modules/@deephaven/jsapi-nodejs": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-nodejs/-/jsapi-nodejs-1.7.1.tgz", - "integrity": "sha512-AyqzrILtvAeST08ewOxtvqULcIJhmmkHraXrNpnoxMY5VGDupVk7omz1wH0dRmTfa6MikBRht9t7UI5J1t+Ecw==", - "dependencies": { - "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", - "@deephaven/log": "^1.5.3", - "@deephaven/utils": "^1.7.1", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.3", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", - "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==" - }, - "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/log": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.5.3.tgz", - "integrity": "sha512-1GSRW64QKkkQFfzrgtRcKDVeOAyJisZfsy0BR2Ob7cNCl64xBlE6Q3J3W9+H96okYcbErZa8dsekdLDbrwmxLA==", - "dependencies": { - "event-target-shim": "^6.0.2", - "jszip": "^3.10.1", - "safe-stable-stringify": "^2.5.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@deephaven/jsapi-nodejs/node_modules/@deephaven/utils": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-1.7.1.tgz", - "integrity": "sha512-42QJK5a/yRox8iZQm+iR4t0jVrYJdPL+qZs/s3sD+ruU+N6iQ7A1DjKIFoDsfkViQ8ot1hS32s+Sj8RF3Cd+aA==", - "dependencies": { - "@deephaven/log": "^1.5.3", - "nanoid": "^5.0.7" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/@deephaven/jsapi-types": { "version": "0.40.0", "license": "Apache-2.0", @@ -4918,10 +4864,6 @@ "prettier": "^3.0.0" } }, - "node_modules/@deephaven/python-remote-file-source-test-client": { - "resolved": "plugins/python-remote-file-source/test-node-client", - "link": true - }, "node_modules/@deephaven/react-hooks": { "version": "0.106.2", "resolved": "https://registry.npmjs.org/@deephaven/react-hooks/-/react-hooks-0.106.2.tgz", @@ -5562,37 +5504,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@emnapi/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", - "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.1.0", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", - "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", - "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.19.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", @@ -5847,22 +5758,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", - "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/netbsd-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", @@ -5878,22 +5773,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", - "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/openbsd-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", @@ -5909,22 +5788,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", - "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@esbuild/sunos-x64": { "version": "0.16.17", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", @@ -6486,15 +6349,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@jest/diff-sequences": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", - "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jest/environment": { "version": "29.7.0", "dev": true, @@ -6548,15 +6402,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/get-type": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", - "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jest/globals": { "version": "29.7.0", "dev": true, @@ -6571,28 +6416,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/pattern": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", - "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-regex-util": "30.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/pattern/node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, "node_modules/@jest/reporters": { "version": "29.7.0", "dev": true, @@ -6646,57 +6469,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/snapshot-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", - "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "natural-compare": "^1.4.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/snapshot-utils/node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/snapshot-utils/node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, - "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "node_modules/@jest/snapshot-utils/node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true - }, "node_modules/@jest/source-map": { "version": "29.6.3", "dev": true, @@ -6791,16 +6563,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "license": "MIT", @@ -6824,9 +6586,8 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + "version": "1.5.0", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -7470,18 +7231,6 @@ "version": "3.0.0", "license": "ISC" }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", - "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@tybys/wasm-util": "^0.10.0" - } - }, "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { "version": "5.1.1-v1", "dev": true, @@ -12436,16 +12185,6 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/aria-query": { "version": "5.0.4", "dev": true, @@ -12488,15 +12227,6 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/chai": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", - "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", - "dev": true, - "dependencies": { - "@types/deep-eql": "*" - } - }, "node_modules/@types/debug": { "version": "4.1.12", "license": "MIT", @@ -12504,12 +12234,6 @@ "@types/ms": "*" } }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true - }, "node_modules/@types/deep-equal": { "version": "1.0.4", "dev": true, @@ -13109,256 +12833,6 @@ "dev": true, "license": "ISC" }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", - "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", - "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", - "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", - "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", - "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", - "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", - "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", - "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", - "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", - "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", - "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", - "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", - "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", - "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", - "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", - "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^0.2.11" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", - "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", - "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", - "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.8.0", "dev": true, @@ -13370,88 +12844,6 @@ "vite": "^4 || ^5 || ^6" } }, - "node_modules/@vitest/expect": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", - "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", - "dev": true, - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", - "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", - "dev": true, - "dependencies": { - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", - "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", - "dev": true, - "dependencies": { - "@vitest/utils": "3.2.4", - "pathe": "^2.0.3", - "strip-literal": "^3.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", - "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "magic-string": "^0.30.17", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", - "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", - "dev": true, - "dependencies": { - "tinyspy": "^4.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", - "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", - "dev": true, - "dependencies": { - "@vitest/pretty-format": "3.2.4", - "loupe": "^3.1.4", - "tinyrainbow": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "license": "MIT", @@ -14056,15 +13448,6 @@ "version": "2.0.6", "license": "MIT" }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/ast-types-flow": { "version": "0.0.8", "dev": true, @@ -14648,15 +14031,6 @@ "node": ">=10" } }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/cacache": { "version": "17.1.4", "dev": true, @@ -14862,22 +14236,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chai": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", - "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", - "dev": true, - "dependencies": { - "assertion-error": "^2.0.1", - "check-error": "^2.1.1", - "deep-eql": "^5.0.1", - "loupe": "^3.1.0", - "pathval": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/chalk": { "version": "4.1.2", "dev": true, @@ -14914,15 +14272,6 @@ "dev": true, "license": "MIT" }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, - "engines": { - "node": ">= 16" - } - }, "node_modules/chokidar": { "version": "4.0.3", "license": "MIT", @@ -15971,9 +15320,8 @@ } }, "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "version": "4.4.0", + "license": "MIT", "dependencies": { "ms": "^2.1.3" }, @@ -16045,15 +15393,6 @@ } } }, - "node_modules/deep-eql": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", - "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-equal": { "version": "2.2.3", "license": "MIT", @@ -16628,9 +15967,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==" + "version": "1.6.0", + "license": "MIT", + "peer": true }, "node_modules/es-object-atoms": { "version": "1.1.1", @@ -17906,15 +17245,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "license": "BSD-2-Clause", @@ -17981,15 +17311,6 @@ "node": ">= 0.8.0" } }, - "node_modules/exit-x": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", - "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/expect": { "version": "29.7.0", "dev": true, @@ -18005,15 +17326,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expect-type": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", - "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/exponential-backoff": { "version": "3.1.2", "dev": true, @@ -18766,6 +18078,7 @@ "version": "4.10.0", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -22667,12 +21980,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loupe": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", - "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", - "dev": true - }, "node_modules/lru-cache": { "version": "5.1.1", "dev": true, @@ -22696,15 +22003,6 @@ "lz-string": "bin/bin.js" } }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/make-dir": { "version": "4.0.0", "dev": true, @@ -24491,21 +23789,6 @@ "node": "^18 || >=20" } }, - "node_modules/napi-postinstall": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", - "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", - "dev": true, - "bin": { - "napi-postinstall": "lib/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/napi-postinstall" - } - }, "node_modules/native-promise-only": { "version": "0.8.1", "license": "MIT" @@ -26174,21 +25457,6 @@ "node": ">=8" } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true - }, - "node_modules/pathval": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", - "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", - "dev": true, - "engines": { - "node": ">= 14.16" - } - }, "node_modules/pbf": { "version": "3.3.0", "license": "BSD-3-Clause", @@ -28220,6 +27488,7 @@ "version": "1.0.0", "dev": true, "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -28612,6 +27881,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, "engines": { "node": ">=10" } @@ -28939,12 +28209,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, "node_modules/signal-exit": { "version": "3.0.7", "dev": true, @@ -29285,12 +28549,6 @@ "node": ">=8" } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, "node_modules/static-eval": { "version": "2.1.1", "license": "MIT", @@ -29298,12 +28556,6 @@ "escodegen": "^2.1.0" } }, - "node_modules/std-env": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", - "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", - "dev": true - }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "license": "MIT", @@ -29584,24 +28836,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", - "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", - "dev": true, - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/strip-literal/node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true - }, "node_modules/strong-log-transformer": { "version": "2.1.0", "dev": true, @@ -30228,98 +29462,14 @@ "version": "1.3.3", "license": "MIT" }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true - }, "node_modules/tinycolor2": { "version": "1.6.0", "license": "MIT" }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinypool": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", - "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", - "dev": true, - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, "node_modules/tinyqueue": { "version": "2.0.3", "license": "ISC" }, - "node_modules/tinyrainbow": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", - "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", - "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/tmp": { "version": "0.2.3", "dev": true, @@ -30482,434 +29632,6 @@ "dev": true, "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.20.6", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", - "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", - "dev": true, - "dependencies": { - "esbuild": "~0.25.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", - "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", - "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", - "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", - "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", - "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", - "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", - "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", - "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", - "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", - "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", - "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", - "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", - "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", - "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", - "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", - "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", - "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", - "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", - "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", - "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", - "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", - "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", - "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.25.10", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", - "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.10", - "@esbuild/android-arm": "0.25.10", - "@esbuild/android-arm64": "0.25.10", - "@esbuild/android-x64": "0.25.10", - "@esbuild/darwin-arm64": "0.25.10", - "@esbuild/darwin-x64": "0.25.10", - "@esbuild/freebsd-arm64": "0.25.10", - "@esbuild/freebsd-x64": "0.25.10", - "@esbuild/linux-arm": "0.25.10", - "@esbuild/linux-arm64": "0.25.10", - "@esbuild/linux-ia32": "0.25.10", - "@esbuild/linux-loong64": "0.25.10", - "@esbuild/linux-mips64el": "0.25.10", - "@esbuild/linux-ppc64": "0.25.10", - "@esbuild/linux-riscv64": "0.25.10", - "@esbuild/linux-s390x": "0.25.10", - "@esbuild/linux-x64": "0.25.10", - "@esbuild/netbsd-arm64": "0.25.10", - "@esbuild/netbsd-x64": "0.25.10", - "@esbuild/openbsd-arm64": "0.25.10", - "@esbuild/openbsd-x64": "0.25.10", - "@esbuild/openharmony-arm64": "0.25.10", - "@esbuild/sunos-x64": "0.25.10", - "@esbuild/win32-arm64": "0.25.10", - "@esbuild/win32-ia32": "0.25.10", - "@esbuild/win32-x64": "0.25.10" - } - }, "node_modules/tuf-js": { "version": "1.1.7", "dev": true, @@ -31392,40 +30114,6 @@ "version": "1.1.1", "license": "MIT" }, - "node_modules/unrs-resolver": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", - "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "napi-postinstall": "^0.3.0" - }, - "funding": { - "url": "https://opencollective.com/unrs-resolver" - }, - "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.11.1", - "@unrs/resolver-binding-android-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-arm64": "1.11.1", - "@unrs/resolver-binding-darwin-x64": "1.11.1", - "@unrs/resolver-binding-freebsd-x64": "1.11.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", - "@unrs/resolver-binding-linux-x64-musl": "1.11.1", - "@unrs/resolver-binding-wasm32-wasi": "1.11.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" - } - }, "node_modules/upath": { "version": "2.0.1", "dev": true, @@ -31694,138 +30382,6 @@ } } }, - "node_modules/vite-node": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", - "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.4.1", - "es-module-lexer": "^1.7.0", - "pathe": "^2.0.3", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", - "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", - "dev": true, - "dependencies": { - "@types/chai": "^5.2.2", - "@vitest/expect": "3.2.4", - "@vitest/mocker": "3.2.4", - "@vitest/pretty-format": "^3.2.4", - "@vitest/runner": "3.2.4", - "@vitest/snapshot": "3.2.4", - "@vitest/spy": "3.2.4", - "@vitest/utils": "3.2.4", - "chai": "^5.2.0", - "debug": "^4.4.1", - "expect-type": "^1.2.1", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "picomatch": "^4.0.2", - "std-env": "^3.9.0", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.14", - "tinypool": "^1.1.1", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", - "vite-node": "3.2.4", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.2.4", - "@vitest/ui": "3.2.4", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", - "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", - "dev": true, - "dependencies": { - "@vitest/spy": "3.2.4", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.17" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/vt-pbf": { "version": "3.1.3", "license": "MIT", @@ -32095,22 +30651,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wicked-good-xpath": { "version": "1.3.0", "license": "MIT" @@ -36625,1481 +35165,6 @@ "node": ">=4.2.0" } }, - "plugins/python-remote-file-source/test-node-client": { - "version": "1.0.0", - "license": "Apache-2.0", - "dependencies": { - "@deephaven/jsapi-nodejs": "1.7.1" - }, - "devDependencies": { - "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", - "@types/node": "^24.5.0", - "jest": "^30.2.0", - "tsx": "^4.20.5", - "vitest": "^3.2.4" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "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" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.28.4" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/plugin-syntax-typescript": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", - "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@deephaven/jsapi-types": { - "version": "1.0.0-dev0.40.3", - "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", - "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==", - "dev": true - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/console": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", - "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/core": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", - "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", - "dev": true, - "dependencies": { - "@jest/console": "30.2.0", - "@jest/pattern": "30.0.1", - "@jest/reporters": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-changed-files": "30.2.0", - "jest-config": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-resolve-dependencies": "30.2.0", - "jest-runner": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "jest-watcher": "30.2.0", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/environment": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", - "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", - "dev": true, - "dependencies": { - "expect": "30.2.0", - "jest-snapshot": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/expect-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", - "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/fake-timers": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", - "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "@sinonjs/fake-timers": "^13.0.0", - "@types/node": "*", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/globals": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", - "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", - "dev": true, - "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/types": "30.2.0", - "jest-mock": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/reporters": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", - "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "@types/node": "*", - "chalk": "^4.1.2", - "collect-v8-coverage": "^1.0.2", - "exit-x": "^0.2.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^5.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "slash": "^3.0.0", - "string-length": "^4.0.2", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/schemas": { - "version": "30.0.5", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", - "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.34.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/source-map": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", - "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "callsites": "^3.1.0", - "graceful-fs": "^4.2.11" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/test-result": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", - "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", - "dev": true, - "dependencies": { - "@jest/console": "30.2.0", - "@jest/types": "30.2.0", - "@types/istanbul-lib-coverage": "^2.0.6", - "collect-v8-coverage": "^1.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/test-sequencer": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", - "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", - "dev": true, - "dependencies": { - "@jest/test-result": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/transform": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", - "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.27.4", - "@jest/types": "30.2.0", - "@jridgewell/trace-mapping": "^0.3.25", - "babel-plugin-istanbul": "^7.0.1", - "chalk": "^4.1.2", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "micromatch": "^4.0.8", - "pirates": "^4.0.7", - "slash": "^3.0.0", - "write-file-atomic": "^5.0.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jest/types": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", - "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, - "dependencies": { - "@jest/pattern": "30.0.1", - "@jest/schemas": "30.0.5", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/node": "*", - "@types/yargs": "^17.0.33", - "chalk": "^4.1.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@pkgr/core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", - "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/pkgr" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@sinclair/typebox": { - "version": "0.34.41", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", - "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/@types/node": { - "version": "24.7.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", - "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", - "dev": true, - "dependencies": { - "undici-types": "~7.14.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/babel-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", - "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", - "dev": true, - "dependencies": { - "@jest/transform": "30.2.0", - "@types/babel__core": "^7.20.5", - "babel-plugin-istanbul": "^7.0.1", - "babel-preset-jest": "30.2.0", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "slash": "^3.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/babel-plugin-istanbul": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", - "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", - "dev": true, - "workspaces": [ - "test/babel-8" - ], - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-instrument": "^6.0.2", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/babel-plugin-jest-hoist": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", - "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", - "dev": true, - "dependencies": { - "@types/babel__core": "^7.20.5" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/babel-preset-current-node-syntax": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", - "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0 || ^8.0.0-0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/babel-preset-jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", - "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "30.2.0", - "babel-preset-current-node-syntax": "^1.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.11.0 || ^8.0.0-beta.1" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/ci-info": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", - "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/cjs-module-lexer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", - "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", - "dev": true - }, - "plugins/python-remote-file-source/test-node-client/node_modules/dedent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", - "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", - "dev": true, - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/expect": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", - "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", - "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", - "dev": true, - "dependencies": { - "@jest/core": "30.2.0", - "@jest/types": "30.2.0", - "import-local": "^3.2.0", - "jest-cli": "30.2.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-changed-files": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", - "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", - "dev": true, - "dependencies": { - "execa": "^5.1.1", - "jest-util": "30.2.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-circus": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", - "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", - "dev": true, - "dependencies": { - "@jest/environment": "30.2.0", - "@jest/expect": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "co": "^4.6.0", - "dedent": "^1.6.0", - "is-generator-fn": "^2.1.0", - "jest-each": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-runtime": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "p-limit": "^3.1.0", - "pretty-format": "30.2.0", - "pure-rand": "^7.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-cli": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", - "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", - "dev": true, - "dependencies": { - "@jest/core": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "exit-x": "^0.2.2", - "import-local": "^3.2.0", - "jest-config": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "yargs": "^17.7.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-config": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", - "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.27.4", - "@jest/get-type": "30.1.0", - "@jest/pattern": "30.0.1", - "@jest/test-sequencer": "30.2.0", - "@jest/types": "30.2.0", - "babel-jest": "30.2.0", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "deepmerge": "^4.3.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-circus": "30.2.0", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-runner": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "micromatch": "^4.0.8", - "parse-json": "^5.2.0", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "esbuild-register": ">=3.4.0", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "esbuild-register": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-diff": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", - "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, - "dependencies": { - "@jest/diff-sequences": "30.0.1", - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-docblock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", - "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", - "dev": true, - "dependencies": { - "detect-newline": "^3.1.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-each": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", - "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "chalk": "^4.1.2", - "jest-util": "30.2.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-environment-node": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", - "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", - "dev": true, - "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-mock": "30.2.0", - "jest-util": "30.2.0", - "jest-validate": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-haste-map": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", - "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "anymatch": "^3.1.3", - "fb-watchman": "^2.0.2", - "graceful-fs": "^4.2.11", - "jest-regex-util": "30.0.1", - "jest-util": "30.2.0", - "jest-worker": "30.2.0", - "micromatch": "^4.0.8", - "walker": "^1.0.8" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.3" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-leak-detector": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", - "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-matcher-utils": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", - "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0", - "chalk": "^4.1.2", - "jest-diff": "30.2.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-message-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", - "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@jest/types": "30.2.0", - "@types/stack-utils": "^2.0.3", - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "micromatch": "^4.0.8", - "pretty-format": "30.2.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.6" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-mock": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", - "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "jest-util": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-regex-util": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", - "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-resolve": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", - "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-pnp-resolver": "^1.2.3", - "jest-util": "30.2.0", - "jest-validate": "30.2.0", - "slash": "^3.0.0", - "unrs-resolver": "^1.7.11" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-resolve-dependencies": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", - "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", - "dev": true, - "dependencies": { - "jest-regex-util": "30.0.1", - "jest-snapshot": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-runner": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", - "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", - "dev": true, - "dependencies": { - "@jest/console": "30.2.0", - "@jest/environment": "30.2.0", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "emittery": "^0.13.1", - "exit-x": "^0.2.2", - "graceful-fs": "^4.2.11", - "jest-docblock": "30.2.0", - "jest-environment-node": "30.2.0", - "jest-haste-map": "30.2.0", - "jest-leak-detector": "30.2.0", - "jest-message-util": "30.2.0", - "jest-resolve": "30.2.0", - "jest-runtime": "30.2.0", - "jest-util": "30.2.0", - "jest-watcher": "30.2.0", - "jest-worker": "30.2.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-runtime": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", - "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", - "dev": true, - "dependencies": { - "@jest/environment": "30.2.0", - "@jest/fake-timers": "30.2.0", - "@jest/globals": "30.2.0", - "@jest/source-map": "30.0.1", - "@jest/test-result": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "cjs-module-lexer": "^2.1.0", - "collect-v8-coverage": "^1.0.2", - "glob": "^10.3.10", - "graceful-fs": "^4.2.11", - "jest-haste-map": "30.2.0", - "jest-message-util": "30.2.0", - "jest-mock": "30.2.0", - "jest-regex-util": "30.0.1", - "jest-resolve": "30.2.0", - "jest-snapshot": "30.2.0", - "jest-util": "30.2.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-snapshot": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", - "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.27.4", - "@babel/generator": "^7.27.5", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/plugin-syntax-typescript": "^7.27.1", - "@babel/types": "^7.27.3", - "@jest/expect-utils": "30.2.0", - "@jest/get-type": "30.1.0", - "@jest/snapshot-utils": "30.2.0", - "@jest/transform": "30.2.0", - "@jest/types": "30.2.0", - "babel-preset-current-node-syntax": "^1.2.0", - "chalk": "^4.1.2", - "expect": "30.2.0", - "graceful-fs": "^4.2.11", - "jest-diff": "30.2.0", - "jest-matcher-utils": "30.2.0", - "jest-message-util": "30.2.0", - "jest-util": "30.2.0", - "pretty-format": "30.2.0", - "semver": "^7.7.2", - "synckit": "^0.11.8" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-util": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", - "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, - "dependencies": { - "@jest/types": "30.2.0", - "@types/node": "*", - "chalk": "^4.1.2", - "ci-info": "^4.2.0", - "graceful-fs": "^4.2.11", - "picomatch": "^4.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-validate": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", - "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", - "dev": true, - "dependencies": { - "@jest/get-type": "30.1.0", - "@jest/types": "30.2.0", - "camelcase": "^6.3.0", - "chalk": "^4.1.2", - "leven": "^3.1.0", - "pretty-format": "30.2.0" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-watcher": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", - "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", - "dev": true, - "dependencies": { - "@jest/test-result": "30.2.0", - "@jest/types": "30.2.0", - "@types/node": "*", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "emittery": "^0.13.1", - "jest-util": "30.2.0", - "string-length": "^4.0.2" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/jest-worker": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", - "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@ungap/structured-clone": "^1.3.0", - "jest-util": "30.2.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.1.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/pretty-format": { - "version": "30.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", - "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, - "dependencies": { - "@jest/schemas": "30.0.5", - "ansi-styles": "^5.2.0", - "react-is": "^18.3.1" - }, - "engines": { - "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/pure-rand": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "plugins/python-remote-file-source/test-node-client/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "plugins/python-remote-file-source/test-node-client/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.2.9" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/synckit" - } - }, - "plugins/python-remote-file-source/test-node-client/node_modules/undici-types": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", - "dev": true - }, - "plugins/python-remote-file-source/test-node-client/node_modules/write-file-atomic": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", - "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "plugins/simple-pivot/src/js": { "name": "@deephaven/js-plugin-simple-pivot", "version": "0.0.3-dev.2", diff --git a/package.json b/package.json index b89b60ab3..fc16af9eb 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,7 @@ "private": true, "version": "0.1.0", "workspaces": [ - "./plugins/*/src/js/", - "./plugins/python-remote-file-source/test-node-client" + "./plugins/*/src/js/" ], "scripts": { "docker": "docker compose up deephaven-plugins --build", From 14e913553bb98f53fde70ef4e40f3e5caf481022 Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 9 Oct 2025 09:23:33 -0500 Subject: [PATCH 28/40] Changed vite config to .mts (#DH-19715) --- .../src/js/{vite.config.ts => vite.config.mts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/python-remote-file-source/src/js/{vite.config.ts => vite.config.mts} (100%) diff --git a/plugins/python-remote-file-source/src/js/vite.config.ts b/plugins/python-remote-file-source/src/js/vite.config.mts similarity index 100% rename from plugins/python-remote-file-source/src/js/vite.config.ts rename to plugins/python-remote-file-source/src/js/vite.config.mts From 9ce227ffe22fa052d9f1d3785094d6c13ffa4f4f Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 9 Oct 2025 09:50:05 -0500 Subject: [PATCH 29/40] Updated docs + scripts for isolated NodeJS package (#DH-19715) --- package.json | 2 +- plugins/python-remote-file-source/README.md | 44 +- .../test-node-client/.nvmrc | 1 + .../test-node-client/package-lock.json | 6174 +++++++++++++++++ tools/test_remote_file_source.sh | 6 + 5 files changed, 6225 insertions(+), 2 deletions(-) create mode 100644 plugins/python-remote-file-source/test-node-client/.nvmrc create mode 100644 plugins/python-remote-file-source/test-node-client/package-lock.json create mode 100755 tools/test_remote_file_source.sh diff --git a/package.json b/package.json index fc16af9eb..05c870ba3 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "test": "jest --watch --changedSince origin/main", "test:unit": "jest --config jest.config.unit.cjs", "test:lint": "jest --config jest.config.lint.cjs", - "test:remote-file-source": "npm run test --workspace=@deephaven/python-remote-file-source-test-client --", + "test:remote-file-source": "./tools/test_remote_file_source.sh", "test:ci": "run-p test:ci:*", "test:ci:unit": "jest --config jest.config.unit.cjs --ci --cacheDirectory $PWD/.jest-cache", "test:ci:lint": "jest --config jest.config.lint.cjs --ci --cacheDirectory $PWD/.jest-cache", diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md index 6e4288b9d..e35340864 100644 --- a/plugins/python-remote-file-source/README.md +++ b/plugins/python-remote-file-source/README.md @@ -21,7 +21,25 @@ It's recommended to use `tox` to run the tests, and the `tox.ini` file is includ ## Building the Plugin -Use the [`plugin_builder.py`](../../README.md#using-plugin_builderpy) from the root directory to build the plugin. +1. Install dependencies +```sh +# Install js dependencies +nvm install +npm install + +# Setup python venv and install dependencies +python -m venv .venv +source .venv/bin/activate +pip install --upgrade -r requirements.txt +pip install click watchdog deephaven-server +``` + +2. Build the python-remote-file-source plugin +```sh +python tools/plugin_builder.py python-remote-file-source +``` + +See [`plugin_builder.py`](../../README.md#using-plugin_builderpy) docs for additional options. ## Installing the Plugin @@ -49,3 +67,27 @@ obj = DeephavenRemoteFileSourcePlugin() ``` A panel should appear for the plugin object showing the current configuration of the plugin. Any top-level module names that have been configured for the plugin to source remotely should show in a searchable list view. + +## Testing the Plugin + + +1. Build the plugin (see [Building the Plugin](#building-the-plugin)). +2. Start the server: + + ```sh + python tools/plugin_builder.py \ + python-remote-file-source \ + --server \ + --server-arg \ + --jvm-args="-Dauthentication.psk=plugins.repo.test -Dprocess.info.system-info.enabled=false" + ``` +> Note that the `-Dprocess.info.system-info.enabled=false` is only required for M1 / M2 Mac. + +3. Before running tests for the first time, install dependencies for the test client: + ```sh + cd plugins/python-remote-file-source/test-node-client + nvm install + npm install + cd - + ``` + diff --git a/plugins/python-remote-file-source/test-node-client/.nvmrc b/plugins/python-remote-file-source/test-node-client/.nvmrc new file mode 100644 index 000000000..c004e356d --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/.nvmrc @@ -0,0 +1 @@ +v22.20.0 diff --git a/plugins/python-remote-file-source/test-node-client/package-lock.json b/plugins/python-remote-file-source/test-node-client/package-lock.json new file mode 100644 index 000000000..1ac28ee4e --- /dev/null +++ b/plugins/python-remote-file-source/test-node-client/package-lock.json @@ -0,0 +1,6174 @@ +{ + "name": "@deephaven/python-remote-file-source-test-client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@deephaven/python-remote-file-source-test-client", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/jsapi-nodejs": "1.7.1" + }, + "devDependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.40.2", + "@types/node": "^24.5.0", + "jest": "^30.2.0", + "tsx": "^4.20.5", + "vitest": "^3.2.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "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/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@deephaven/jsapi-nodejs": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-nodejs/-/jsapi-nodejs-1.7.1.tgz", + "integrity": "sha512-AyqzrILtvAeST08ewOxtvqULcIJhmmkHraXrNpnoxMY5VGDupVk7omz1wH0dRmTfa6MikBRht9t7UI5J1t+Ecw==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/jsapi-types": "^1.0.0-dev0.39.4", + "@deephaven/log": "^1.5.3", + "@deephaven/utils": "^1.7.1", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@deephaven/jsapi-types": { + "version": "1.0.0-dev0.40.3", + "resolved": "https://registry.npmjs.org/@deephaven/jsapi-types/-/jsapi-types-1.0.0-dev0.40.3.tgz", + "integrity": "sha512-gHNpFuxfYPrbceGSiri9kaq1xUWMZIB/PCufAGP8c3JV/UTe4UJZla1MHG/T4OoASZqAPBLf22ryHDlVxEjVyA==", + "license": "Apache-2.0" + }, + "node_modules/@deephaven/log": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@deephaven/log/-/log-1.5.3.tgz", + "integrity": "sha512-1GSRW64QKkkQFfzrgtRcKDVeOAyJisZfsy0BR2Ob7cNCl64xBlE6Q3J3W9+H96okYcbErZa8dsekdLDbrwmxLA==", + "license": "Apache-2.0", + "dependencies": { + "event-target-shim": "^6.0.2", + "jszip": "^3.10.1", + "safe-stable-stringify": "^2.5.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@deephaven/utils": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@deephaven/utils/-/utils-1.7.1.tgz", + "integrity": "sha512-42QJK5a/yRox8iZQm+iR4t0jVrYJdPL+qZs/s3sD+ruU+N6iQ7A1DjKIFoDsfkViQ8ot1hS32s+Sj8RF3Cd+aA==", + "license": "Apache-2.0", + "dependencies": { + "@deephaven/log": "^1.5.3", + "nanoid": "^5.0.7" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", + "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/core": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", + "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/pattern": "30.0.1", + "@jest/reporters": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-changed-files": "30.2.0", + "jest-config": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-resolve-dependencies": "30.2.0", + "jest-runner": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "jest-watcher": "30.2.0", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/diff-sequences": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", + "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", + "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "30.2.0", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", + "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", + "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@sinonjs/fake-timers": "^13.0.0", + "@types/node": "*", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/get-type": { + "version": "30.1.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", + "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", + "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/types": "30.2.0", + "jest-mock": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", + "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", + "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "@types/node": "*", + "chalk": "^4.1.2", + "collect-v8-coverage": "^1.0.2", + "exit-x": "^0.2.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^5.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "slash": "^3.0.0", + "string-length": "^4.0.2", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "30.0.5", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", + "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/snapshot-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", + "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", + "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "callsites": "^3.1.0", + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", + "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/types": "30.2.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "collect-v8-coverage": "^1.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", + "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", + "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/types": "30.2.0", + "@jridgewell/trace-mapping": "^0.3.25", + "babel-plugin-istanbul": "^7.0.1", + "chalk": "^4.1.2", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "micromatch": "^4.0.8", + "pirates": "^4.0.7", + "slash": "^3.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/types": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", + "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.0.1", + "@jest/schemas": "30.0.5", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.34.41", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", + "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "24.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", + "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", + "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "30.2.0", + "@types/babel__core": "^7.20.5", + "babel-plugin-istanbul": "^7.0.1", + "babel-preset-jest": "30.2.0", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "slash": "^3.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", + "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/babel__core": "^7.20.5" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", + "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0 || ^8.0.0-beta.1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.15.tgz", + "integrity": "sha512-qsJ8/X+UypqxHXN75M7dF88jNK37dLBRW7LeUzCPz+TNs37G8cfWy9nWzS+LS//g600zrt2le9KuXt0rWfDz5Q==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001749", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz", + "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz", + "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.233", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.233.tgz", + "integrity": "sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/event-target-shim": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-6.0.2.tgz", + "integrity": "sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/exit-x": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", + "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", + "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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, + "license": "MIT", + "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", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-tsconfig": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.12.0.tgz", + "integrity": "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", + "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/types": "30.2.0", + "import-local": "^3.2.0", + "jest-cli": "30.2.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", + "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.1.1", + "jest-util": "30.2.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-circus": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", + "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/expect": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "co": "^4.6.0", + "dedent": "^1.6.0", + "is-generator-fn": "^2.1.0", + "jest-each": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-runtime": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "p-limit": "^3.1.0", + "pretty-format": "30.2.0", + "pure-rand": "^7.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-cli": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", + "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "exit-x": "^0.2.2", + "import-local": "^3.2.0", + "jest-config": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "yargs": "^17.7.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", + "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@jest/get-type": "30.1.0", + "@jest/pattern": "30.0.1", + "@jest/test-sequencer": "30.2.0", + "@jest/types": "30.2.0", + "babel-jest": "30.2.0", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "deepmerge": "^4.3.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-circus": "30.2.0", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-runner": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "micromatch": "^4.0.8", + "parse-json": "^5.2.0", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "esbuild-register": ">=3.4.0", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "esbuild-register": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", + "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.0.1", + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", + "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.1.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-each": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", + "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "chalk": "^4.1.2", + "jest-util": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", + "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-mock": "30.2.0", + "jest-util": "30.2.0", + "jest-validate": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", + "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "anymatch": "^3.1.3", + "fb-watchman": "^2.0.2", + "graceful-fs": "^4.2.11", + "jest-regex-util": "30.0.1", + "jest-util": "30.2.0", + "jest-worker": "30.2.0", + "micromatch": "^4.0.8", + "walker": "^1.0.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.3" + } + }, + "node_modules/jest-leak-detector": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", + "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", + "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "chalk": "^4.1.2", + "jest-diff": "30.2.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", + "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.2.0", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "micromatch": "^4.0.8", + "pretty-format": "30.2.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-mock": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", + "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "jest-util": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", + "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", + "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-pnp-resolver": "^1.2.3", + "jest-util": "30.2.0", + "jest-validate": "30.2.0", + "slash": "^3.0.0", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", + "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "30.0.1", + "jest-snapshot": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runner": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", + "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "30.2.0", + "@jest/environment": "30.2.0", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "exit-x": "^0.2.2", + "graceful-fs": "^4.2.11", + "jest-docblock": "30.2.0", + "jest-environment-node": "30.2.0", + "jest-haste-map": "30.2.0", + "jest-leak-detector": "30.2.0", + "jest-message-util": "30.2.0", + "jest-resolve": "30.2.0", + "jest-runtime": "30.2.0", + "jest-util": "30.2.0", + "jest-watcher": "30.2.0", + "jest-worker": "30.2.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", + "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "30.2.0", + "@jest/fake-timers": "30.2.0", + "@jest/globals": "30.2.0", + "@jest/source-map": "30.0.1", + "@jest/test-result": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "cjs-module-lexer": "^2.1.0", + "collect-v8-coverage": "^1.0.2", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "jest-haste-map": "30.2.0", + "jest-message-util": "30.2.0", + "jest-mock": "30.2.0", + "jest-regex-util": "30.0.1", + "jest-resolve": "30.2.0", + "jest-snapshot": "30.2.0", + "jest-util": "30.2.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", + "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.4", + "@babel/generator": "^7.27.5", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/types": "^7.27.3", + "@jest/expect-utils": "30.2.0", + "@jest/get-type": "30.1.0", + "@jest/snapshot-utils": "30.2.0", + "@jest/transform": "30.2.0", + "@jest/types": "30.2.0", + "babel-preset-current-node-syntax": "^1.2.0", + "chalk": "^4.1.2", + "expect": "30.2.0", + "graceful-fs": "^4.2.11", + "jest-diff": "30.2.0", + "jest-matcher-utils": "30.2.0", + "jest-message-util": "30.2.0", + "jest-util": "30.2.0", + "pretty-format": "30.2.0", + "semver": "^7.7.2", + "synckit": "^0.11.8" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", + "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.2.0", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", + "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.1.0", + "@jest/types": "30.2.0", + "camelcase": "^6.3.0", + "chalk": "^4.1.2", + "leven": "^3.1.0", + "pretty-format": "30.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", + "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "30.2.0", + "@jest/types": "30.2.0", + "@types/node": "*", + "ansi-escapes": "^4.3.2", + "chalk": "^4.1.2", + "emittery": "^0.13.1", + "jest-util": "30.2.0", + "string-length": "^4.0.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", + "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@ungap/structured-clone": "^1.3.0", + "jest-util": "30.2.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.1.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pretty-format": { + "version": "30.2.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", + "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "30.0.5", + "ansi-styles": "^5.2.0", + "react-is": "^18.3.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vite": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/tools/test_remote_file_source.sh b/tools/test_remote_file_source.sh new file mode 100755 index 000000000..a5d8b331c --- /dev/null +++ b/tools/test_remote_file_source.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Run tests for Python remote file source plugin using a NodeJS test client. +pushd plugins/python-remote-file-source/test-node-client +npm run test +popd \ No newline at end of file From 12997f2518f9ca974a4157c455c761a84d0ba8de Mon Sep 17 00:00:00 2001 From: Brian Ingles Date: Thu, 9 Oct 2025 13:06:36 -0500 Subject: [PATCH 30/40] Docs for json RPC messages (#DH-19715) --- plugins/python-remote-file-source/README.md | 85 +++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/plugins/python-remote-file-source/README.md b/plugins/python-remote-file-source/README.md index e35340864..335446afe 100644 --- a/plugins/python-remote-file-source/README.md +++ b/plugins/python-remote-file-source/README.md @@ -2,6 +2,91 @@ A Deephaven bi-directional plugin to allow sourcing Python imports from a remote file source. It consists of a Python plugin installed and then instantiated in a Deephaven Core / Core+ worker. When a client connects to the plugin, a custom Python `sys.meta_path` finder and loader are registered that will send messages to the client to request content for loading modules. +## Plugin Messages +Bi-directional communication between the server plugin and a client uses JSON-RPC. + +### JSON-RPC Messages + +The plugin uses the following JSON-RPC v2 messages for communication between the Python server and the client: + +#### Request: `request_plugin_info` +**Direction:** Client → Server + +Returns a list of top-level module names available for remote import. + +**Example:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "method": "request_plugin_info", + "params": {} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "result": { + "full_names": ["module1", "module2", ...] + } +} +``` + +#### Request: `set_connection_id` +**Direction:** Client → Server + +Sets the connection id on the MessageStream and tells the MessageStream it can register a `RemoteMetaPathFinder` to source Python imports for scripts run with a matching execution context connection id. + +**Example:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "method": "set_connection_id", + "params": {"id": ""} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "result": null +} +``` + +#### Request: `fetch_module` +**Direction:** Server → Client + +Requests the source code and file path for a Python module from the client. Used by the server to fetch remote modules for import. + +**Example:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "method": "fetch_module", + "params": {"module_name": "some.module.name"} +} +``` + +**Response:** +```json +{ + "jsonrpc": "2.0", + "id": "", + "result": { + "filepath": "/path/to/module.py", + "source": "" + } +} +``` +If the module spec is not found `result` will be `None`. The `filepath` property will contain a filesystem path or `