From b698a5654947fe54f0f3b1ca2b1c3737567002f9 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Mon, 20 Jan 2025 10:55:53 -0800 Subject: [PATCH] Websockets for plugin runtime communication (#156) --- .prettierrc.cjs | 14 +- package-lock.json | 514 +++--------------- packages/plugin-runtime-types/package.json | 2 +- .../src/bindings/events.ts | 22 +- .../src/plugins/AuthenticationPlugin.ts | 4 +- .../src/plugins/Context.ts | 32 +- .../src/plugins/FilterPlugin.ts | 7 +- .../src/plugins/HttpRequestActionPlugin.ts | 2 +- .../src/plugins/ImporterPlugin.ts | 35 +- .../src/plugins/TemplateFunctionPlugin.ts | 12 +- .../src/plugins/ThemePlugin.ts | 6 +- .../plugin-runtime-types/src/themes/index.ts | 2 +- packages/plugin-runtime/.gitignore | 3 - packages/plugin-runtime/package-lock.json | 10 + packages/plugin-runtime/package.json | 12 +- packages/plugin-runtime/src/EventChannel.ts | 17 +- packages/plugin-runtime/src/PluginHandle.ts | 2 +- .../plugin-runtime/src/gen/plugins/runtime.ts | 126 ----- packages/plugin-runtime/src/index.ts | 84 +-- packages/plugin-runtime/src/index.worker.ts | 213 ++++---- .../plugin-runtime/src/interceptStdout.ts | 37 ++ packages/plugin-runtime/tsconfig.json | 1 + src-tauri/Cargo.lock | 153 ++---- src-tauri/src/lib.rs | 28 +- .../vendored/plugins/auth-jwt/build/index.js | 91 ++-- .../plugins/exporter-curl/build/index.js | 12 +- .../plugins/filter-jsonpath/build/index.js | 20 +- .../plugins/filter-xpath/build/index.js | 26 +- .../plugins/importer-curl/build/index.js | 17 +- .../plugins/importer-insomnia/build/index.js | 17 +- .../plugins/importer-openapi/build/index.js | 41 +- .../plugins/importer-postman/build/index.js | 17 +- .../plugins/importer-yaak/build/index.js | 17 +- src-tauri/yaak-grpc/Cargo.toml | 28 +- src-tauri/yaak-grpc/src/lib.rs | 2 +- src-tauri/yaak-grpc/src/manager.rs | 6 +- src-tauri/yaak-grpc/src/transport.rs | 3 +- src-tauri/yaak-plugins/Cargo.toml | 9 +- src-tauri/yaak-plugins/bindings/events.ts | 22 +- src-tauri/yaak-plugins/build.rs | 6 - src-tauri/yaak-plugins/src/error.rs | 9 +- src-tauri/yaak-plugins/src/events.rs | 28 +- src-tauri/yaak-plugins/src/lib.rs | 2 +- src-tauri/yaak-plugins/src/manager.rs | 49 +- src-tauri/yaak-plugins/src/nodejs.rs | 4 +- src-tauri/yaak-plugins/src/plugin_handle.rs | 16 +- src-tauri/yaak-plugins/src/server.rs | 99 ---- src-tauri/yaak-plugins/src/server_ws.rs | 132 +++++ src-tauri/yaak-sync/bindings/sync.ts | 4 +- src-web/components/UrlParameterEditor.tsx | 2 +- src-web/components/WindowControls.tsx | 1 - src-web/components/core/Dropdown.tsx | 4 +- src-web/components/core/Toast.tsx | 2 +- src-web/hooks/useActiveCookieJar.ts | 2 +- 54 files changed, 841 insertions(+), 1185 deletions(-) delete mode 100644 packages/plugin-runtime/.gitignore create mode 100644 packages/plugin-runtime/package-lock.json delete mode 100644 packages/plugin-runtime/src/gen/plugins/runtime.ts create mode 100644 packages/plugin-runtime/src/interceptStdout.ts delete mode 100644 src-tauri/yaak-plugins/build.rs delete mode 100644 src-tauri/yaak-plugins/src/server.rs create mode 100644 src-tauri/yaak-plugins/src/server_ws.rs diff --git a/.prettierrc.cjs b/.prettierrc.cjs index 00193890..86a16de2 100644 --- a/.prettierrc.cjs +++ b/.prettierrc.cjs @@ -1,8 +1,8 @@ -module.exports = { - "trailingComma": "all", - "tabWidth": 2, - "semi": true, - "singleQuote": true, - "printWidth": 100, - "bracketSpacing": true +export default { + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "printWidth": 100, + "bracketSpacing": true } diff --git a/package-lock.json b/package-lock.json index 7240db8a..d1598323 100644 --- a/package-lock.json +++ b/package-lock.json @@ -420,13 +420,6 @@ "node": ">=6.9.0" } }, - "node_modules/@bufbuild/protobuf": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.2.0.tgz", - "integrity": "sha512-+imAQkHf7U/Rwvu0wk1XWgsP3WnpCWmK7B48f0XqSNzgk64+grljTKC7pnO/xBiEMUziF7vKRfbBnOQhg126qQ==", - "dev": true, - "license": "(Apache-2.0 AND BSD-3-Clause)" - }, "node_modules/@changesets/changelog-github": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", @@ -1197,104 +1190,6 @@ "integrity": "sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==", "license": "MIT" }, - "node_modules/@grpc/grpc-js": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.1.tgz", - "integrity": "sha512-VYrLinJNeW3idIZHTy7BsVL7bsPF9+l89WDYTDV8o1QYJzkf3BSoPXdfaz4c8DyeY12LGSaS8m8BgbT8W66h6Q==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "license": "Apache-2.0", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@grpc/proto-loader/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==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@grpc/proto-loader/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==", - "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/@grpc/proto-loader/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/@grpc/proto-loader/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "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/@grpc/proto-loader/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==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -1495,16 +1390,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/@lezer/common": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.2.tgz", @@ -1612,8 +1497,8 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "devOptional": true, "license": "BSD-3-Clause", + "optional": true, "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -1633,8 +1518,8 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "semver": "^6.0.0" }, @@ -1649,8 +1534,8 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "devOptional": true, "license": "ISC", + "optional": true, "bin": { "semver": "bin/semver.js" } @@ -1700,70 +1585,6 @@ "node": ">=14" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" - }, "node_modules/@react-dnd/asap": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", @@ -3247,13 +3068,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/intercept-stdout": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@types/intercept-stdout/-/intercept-stdout-0.1.3.tgz", - "integrity": "sha512-5qWSvqohM5rRKsF58LBWJeyu+lUlZwYKSnTcnXGfvFyMYIjvhpfniQRJNiyE/Gcru3jwVr2pHedsKTGLtzZqNA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/js-cookie": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-2.2.7.tgz", @@ -3387,6 +3201,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yauzl": { "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", @@ -3667,14 +3491,8 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "devOptional": true, - "license": "ISC" - }, - "node_modules/abort-controller-x": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/abort-controller-x/-/abort-controller-x-0.4.3.tgz", - "integrity": "sha512-VtUwTNU8fpMwvWGn4xE93ywbogTYsuT+AUxAXOeelbXuQVIwNmC5YLeho9sH4vZ4ITW8414TTAOG1nW6uIVHCA==", - "license": "MIT" + "license": "ISC", + "optional": true }, "node_modules/acorn": { "version": "8.14.0", @@ -3850,16 +3668,16 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -4664,19 +4482,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/case-anything": { - "version": "2.1.13", - "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", - "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -4784,8 +4589,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "devOptional": true, "license": "ISC", + "optional": true, "engines": { "node": ">=10" } @@ -5052,8 +4857,8 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "devOptional": true, "license": "ISC", + "optional": true, "bin": { "color-support": "bin.js" } @@ -5103,8 +4908,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/convert-hrtime": { "version": "5.0.0", @@ -5704,8 +5509,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/dequal": { "version": "2.0.3", @@ -5720,8 +5525,8 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, "engines": { "node": ">=8" } @@ -5845,29 +5650,6 @@ "node": ">=10" } }, - "node_modules/dprint-node": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", - "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^1.0.3" - } - }, - "node_modules/dprint-node/node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/duplexer3": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", @@ -6198,6 +5980,7 @@ "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" @@ -7166,8 +6949,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "minipass": "^3.0.0" }, @@ -7179,8 +6962,8 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -7192,8 +6975,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -7278,8 +7061,8 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -7612,20 +7395,6 @@ "graphql": "^15.5.0 || ^16.0.0 || ^17.0.0-alpha.2" } }, - "node_modules/grpc-tools": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/grpc-tools/-/grpc-tools-1.12.4.tgz", - "integrity": "sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.5" - }, - "bin": { - "grpc_tools_node_protoc": "bin/protoc.js", - "grpc_tools_node_protoc_plugin": "bin/protoc_plugin.js" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -7705,8 +7474,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/hasown": { "version": "2.0.2", @@ -7967,15 +7736,6 @@ "css-in-js-utils": "^3.1.0" } }, - "node_modules/intercept-stdout": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/intercept-stdout/-/intercept-stdout-0.1.2.tgz", - "integrity": "sha512-Umb41Ryp5FzLurfCRAWx+jjNAk8jsw2RTk2XPIwus+86h/Y2Eb4DfOWof/mZ6FBww8SoO45rJSlg25054/Di9w==", - "license": "MIT", - "dependencies": { - "lodash.toarray": "^3.0.0" - } - }, "node_modules/internal-ip": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-8.0.0.tgz", @@ -8976,53 +8736,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash._arraycopy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", - "integrity": "sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==", - "license": "MIT" - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==", - "license": "MIT" - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==", - "license": "MIT" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "license": "MIT" - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", - "license": "MIT" - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==", - "license": "MIT" - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==", - "license": "MIT", - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -9030,23 +8743,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.toarray": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-3.0.2.tgz", - "integrity": "sha512-ptkjUqvuHjTuMJJxiktJpZhxM5l60bEkfntJx+NFzdQd1bZVxfpTF1bhFYFqBrT4F0wZ1qx9KbVmHJV3Rfc7Tw==", - "license": "MIT", - "dependencies": { - "lodash._arraycopy": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash.keys": "^3.0.0" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "license": "Apache-2.0" - }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -10181,8 +9877,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -10195,8 +9891,8 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "yallist": "^4.0.0" }, @@ -10208,15 +9904,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "devOptional": true, "license": "MIT", + "optional": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -10328,26 +10024,6 @@ "dev": true, "license": "MIT" }, - "node_modules/nice-grpc": { - "version": "2.1.10", - "resolved": "https://registry.npmjs.org/nice-grpc/-/nice-grpc-2.1.10.tgz", - "integrity": "sha512-Nujs/4wWJvE5OSxWPp3M5H+zHJAgsWMo38bMNfKQP1VDeCChp7MiKTkhJBV5JZvrBIkPhYQCLIbfvVqEoSuTuA==", - "license": "MIT", - "dependencies": { - "@grpc/grpc-js": "^1.10.8", - "abort-controller-x": "^0.4.0", - "nice-grpc-common": "^2.0.2" - } - }, - "node_modules/nice-grpc-common": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/nice-grpc-common/-/nice-grpc-common-2.0.2.tgz", - "integrity": "sha512-7RNWbls5kAL1QVUOXvBsv1uO0wPQK3lHv+cY1gwkTzirnG1Nop4cBJZubpgziNbaVc/bl9QJcyvsf/NQxa3rjQ==", - "license": "MIT", - "dependencies": { - "ts-error": "^1.0.6" - } - }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -10410,8 +10086,8 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "abbrev": "1" }, @@ -10711,8 +10387,8 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -11620,30 +11296,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -12318,8 +11970,8 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -13203,8 +12855,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -13692,8 +13344,8 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -13769,8 +13421,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/term-size": { "version": "1.2.0", @@ -14065,54 +13717,12 @@ "integrity": "sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==", "license": "Unlicense" }, - "node_modules/ts-error": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/ts-error/-/ts-error-1.0.6.tgz", - "integrity": "sha512-tLJxacIQUM82IR7JO1UUkKlYuUTmoY9HBJAmNWFzheSlDS5SPMcNIepejHJa4BpPQLAcbRhRf3GDJzyj6rbKvA==", - "license": "MIT" - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "license": "Apache-2.0" }, - "node_modules/ts-poet": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.9.0.tgz", - "integrity": "sha512-roe6W6MeZmCjRmppyfOURklO5tQFQ6Sg7swURKkwYJvV7dbGCrK28um5+51iW3twdPRKtwarqFAVMU6G1mvnuQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "dprint-node": "^1.0.8" - } - }, - "node_modules/ts-proto": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.2.3.tgz", - "integrity": "sha512-sI9qyTcMg7syJjk0CvkRVxZyAuCbpweO2Kq5Dz/JXaRwpaB9ujMHdFF06raXj5nLxDknzV5cUIcdCuUThPXuYg==", - "dev": true, - "license": "ISC", - "dependencies": { - "@bufbuild/protobuf": "^2.0.0", - "case-anything": "^2.1.13", - "ts-poet": "^6.7.0", - "ts-proto-descriptors": "2.0.0" - }, - "bin": { - "protoc-gen-ts_proto": "protoc-gen-ts_proto" - } - }, - "node_modules/ts-proto-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.0.0.tgz", - "integrity": "sha512-wHcTH3xIv11jxgkX5OyCSFfw27agpInAd6yh89hKG6zqIXnjW9SYqSER2CVQxdPj4czeOhGagNvZBEbJPy7qkw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@bufbuild/protobuf": "^2.0.0" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -15433,8 +15043,8 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -15795,20 +15405,15 @@ "packages/plugin-runtime": { "name": "@yaakapp-internal/plugin-runtime", "dependencies": { - "intercept-stdout": "^0.1.2", - "long": "^5.2.3", - "nice-grpc": "^2.1.9", - "protobufjs": "^7.4.0" + "ws": "^8.18.0" }, "devDependencies": { - "@types/intercept-stdout": "^0.1.3", - "grpc-tools": "^1.12.4", - "ts-proto": "^2.2.0" + "@types/ws": "^8.5.13" } }, "packages/plugin-runtime-types": { "name": "@yaakapp/api", - "version": "0.3.2", + "version": "0.3.3", "dependencies": { "@types/node": "^22.5.4" }, @@ -15818,6 +15423,27 @@ "typescript": "^5.6.2" } }, + "packages/plugin-runtime/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "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 + } + } + }, "plugin-runtime": { "name": "@yaakapp-internal/plugin-runtime", "extraneous": true, diff --git a/packages/plugin-runtime-types/package.json b/packages/plugin-runtime-types/package.json index 5278bfe3..d3e30774 100644 --- a/packages/plugin-runtime-types/package.json +++ b/packages/plugin-runtime-types/package.json @@ -1,6 +1,6 @@ { "name": "@yaakapp/api", - "version": "0.3.2", + "version": "0.3.3", "main": "lib/index.js", "typings": "./lib/index.d.ts", "files": [ diff --git a/packages/plugin-runtime-types/src/bindings/events.ts b/packages/plugin-runtime-types/src/bindings/events.ts index 5ec1a780..5b043002 100644 --- a/packages/plugin-runtime-types/src/bindings/events.ts +++ b/packages/plugin-runtime-types/src/bindings/events.ts @@ -1,15 +1,15 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Environment } from "./models"; -import type { Folder } from "./models"; -import type { GrpcRequest } from "./models"; -import type { HttpRequest } from "./models"; -import type { HttpResponse } from "./models"; -import type { JsonValue } from "./serde_json/JsonValue"; -import type { Workspace } from "./models"; +import type { Environment } from "./models.js"; +import type { Folder } from "./models.js"; +import type { GrpcRequest } from "./models.js"; +import type { HttpRequest } from "./models.js"; +import type { HttpResponse } from "./models.js"; +import type { JsonValue } from "./serde_json/JsonValue.js"; +import type { Workspace } from "./models.js"; export type BootRequest = { dir: string, watch: boolean, }; -export type BootResponse = { name: string, version: string, capabilities: Array, }; +export type BootResponse = { name: string, version: string, }; export type CallHttpAuthenticationRequest = { config: { [key in string]?: JsonValue }, method: string, url: string, headers: Array, }; @@ -38,6 +38,8 @@ export type EditorLanguage = "text" | "javascript" | "json" | "html" | "xml" | " export type EmptyPayload = {}; +export type ErrorResponse = { error: string, }; + export type ExportHttpRequestRequest = { httpRequest: HttpRequest, }; export type ExportHttpRequestResponse = { content: string, }; @@ -242,9 +244,9 @@ export type ImportResources = { workspaces: Array, environments: Arra export type ImportResponse = { resources: ImportResources, }; -export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, }; +export type InternalEvent = { id: string, pluginRefId: string, pluginName: string, replyId: string | null, windowContext: WindowContext, payload: InternalEventPayload, }; -export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } & EmptyPayload | { "type": "reload_response" } & EmptyPayload | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_request" } & EmptyPayload | { "type": "get_http_authentication_response" } & GetHttpAuthenticationResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyPayload; +export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } & EmptyPayload | { "type": "reload_response" } & EmptyPayload | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_request" } & EmptyPayload | { "type": "get_http_authentication_response" } & GetHttpAuthenticationResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; export type PromptTextRequest = { id: string, title: string, label: string, description?: string, defaultValue?: string, placeholder?: string, /** diff --git a/packages/plugin-runtime-types/src/plugins/AuthenticationPlugin.ts b/packages/plugin-runtime-types/src/plugins/AuthenticationPlugin.ts index 7bdf824f..68eb10b4 100644 --- a/packages/plugin-runtime-types/src/plugins/AuthenticationPlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/AuthenticationPlugin.ts @@ -2,8 +2,8 @@ import { CallHttpAuthenticationRequest, CallHttpAuthenticationResponse, GetHttpAuthenticationResponse, -} from '..'; -import type { Context } from './Context'; +} from '../bindings/events'; +import { Context } from './Context'; export type AuthenticationPlugin = Omit & { onApply( diff --git a/packages/plugin-runtime-types/src/plugins/Context.ts b/packages/plugin-runtime-types/src/plugins/Context.ts index 251d0164..4ba64441 100644 --- a/packages/plugin-runtime-types/src/plugins/Context.ts +++ b/packages/plugin-runtime-types/src/plugins/Context.ts @@ -12,27 +12,37 @@ import type { ShowToastRequest, TemplateRenderRequest, TemplateRenderResponse, -} from '..'; +} from "../bindings/events.ts"; -export type Context = { +export interface Context { clipboard: { - copyText(text: string): void; + copyText(text: string): Promise; }; toast: { - show(args: ShowToastRequest): void; + show(args: ShowToastRequest): Promise; }; prompt: { - text(args: PromptTextRequest): Promise; + text(args: PromptTextRequest): Promise; }; httpRequest: { - send(args: SendHttpRequestRequest): Promise; - getById(args: GetHttpRequestByIdRequest): Promise; - render(args: RenderHttpRequestRequest): Promise; + send( + args: SendHttpRequestRequest, + ): Promise; + getById( + args: GetHttpRequestByIdRequest, + ): Promise; + render( + args: RenderHttpRequestRequest, + ): Promise; }; httpResponse: { - find(args: FindHttpResponsesRequest): Promise; + find( + args: FindHttpResponsesRequest, + ): Promise; }; templates: { - render(args: TemplateRenderRequest): Promise; + render( + args: TemplateRenderRequest, + ): Promise; }; -}; +} diff --git a/packages/plugin-runtime-types/src/plugins/FilterPlugin.ts b/packages/plugin-runtime-types/src/plugins/FilterPlugin.ts index 7e57a196..57a1af07 100644 --- a/packages/plugin-runtime-types/src/plugins/FilterPlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/FilterPlugin.ts @@ -1,13 +1,12 @@ import type { Context } from './Context'; -export type FilterPluginResponse = string[]; +export type FilterPluginResponse = { filtered: string }; export type FilterPlugin = { name: string; description?: string; - canFilter(ctx: Context, args: { mimeType: string }): Promise; onFilter( ctx: Context, - args: { payload: string; mimeType: string }, - ): Promise; + args: { payload: string; filter: string; mimeType: string }, + ): Promise | FilterPluginResponse; }; diff --git a/packages/plugin-runtime-types/src/plugins/HttpRequestActionPlugin.ts b/packages/plugin-runtime-types/src/plugins/HttpRequestActionPlugin.ts index 06b62586..bc8693db 100644 --- a/packages/plugin-runtime-types/src/plugins/HttpRequestActionPlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/HttpRequestActionPlugin.ts @@ -1,4 +1,4 @@ -import type { CallHttpRequestActionArgs, HttpRequestAction } from '..'; +import type { CallHttpRequestActionArgs, HttpRequestAction } from '../bindings/events'; import type { Context } from './Context'; export type HttpRequestActionPlugin = HttpRequestAction & { diff --git a/packages/plugin-runtime-types/src/plugins/ImporterPlugin.ts b/packages/plugin-runtime-types/src/plugins/ImporterPlugin.ts index 23775ed8..940beb1c 100644 --- a/packages/plugin-runtime-types/src/plugins/ImporterPlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/ImporterPlugin.ts @@ -1,13 +1,30 @@ -import type { Environment, Folder, GrpcRequest, HttpRequest, Workspace } from '..'; -import type { AtLeast } from '../helpers'; -import type { Context } from './Context'; +import { + Environment, + Folder, + GrpcRequest, + HttpRequest, + Workspace, +} from "../bindings/models"; +import type { AtLeast } from "../helpers"; +import type { Context } from "./Context"; -export type ImportPluginResponse = null | { - workspaces: AtLeast[]; - environments: AtLeast[]; - folders: AtLeast[]; - httpRequests: AtLeast[]; - grpcRequests: AtLeast[]; +type ImportPluginResponse = null | { + resources: { + workspaces: AtLeast[]; + environments: AtLeast< + Environment, + "name" | "id" | "model" | "workspaceId" + >[]; + folders: AtLeast[]; + httpRequests: AtLeast< + HttpRequest, + "name" | "id" | "model" | "workspaceId" + >[]; + grpcRequests: AtLeast< + GrpcRequest, + "name" | "id" | "model" | "workspaceId" + >[]; + }; }; export type ImporterPlugin = { diff --git a/packages/plugin-runtime-types/src/plugins/TemplateFunctionPlugin.ts b/packages/plugin-runtime-types/src/plugins/TemplateFunctionPlugin.ts index ed15f6e2..13fe985d 100644 --- a/packages/plugin-runtime-types/src/plugins/TemplateFunctionPlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/TemplateFunctionPlugin.ts @@ -1,6 +1,12 @@ -import type { CallTemplateFunctionArgs, TemplateFunction } from '..'; -import type { Context } from './Context'; +import { + CallTemplateFunctionArgs, + TemplateFunction, +} from "../bindings/events"; +import { Context } from "./Context"; export type TemplateFunctionPlugin = TemplateFunction & { - onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise; + onRender( + ctx: Context, + args: CallTemplateFunctionArgs, + ): Promise; }; diff --git a/packages/plugin-runtime-types/src/plugins/ThemePlugin.ts b/packages/plugin-runtime-types/src/plugins/ThemePlugin.ts index 342f36fd..7ab2d685 100644 --- a/packages/plugin-runtime-types/src/plugins/ThemePlugin.ts +++ b/packages/plugin-runtime-types/src/plugins/ThemePlugin.ts @@ -1,8 +1,8 @@ -import type { Theme } from '../themes'; -import type { Context } from './Context'; +import { Index } from "../themes"; +import { Context } from "./Context"; export type ThemePlugin = { name: string; description?: string; - getTheme(ctx: Context, fileContents: string): Promise; + getTheme(ctx: Context, fileContents: string): Promise; }; diff --git a/packages/plugin-runtime-types/src/themes/index.ts b/packages/plugin-runtime-types/src/themes/index.ts index 40412dc7..00fdc325 100644 --- a/packages/plugin-runtime-types/src/themes/index.ts +++ b/packages/plugin-runtime-types/src/themes/index.ts @@ -24,7 +24,7 @@ export type Colors = { danger?: string; }; -export type Theme = Colors & { +export type Index = Colors & { id: string; name: string; components?: Partial<{ diff --git a/packages/plugin-runtime/.gitignore b/packages/plugin-runtime/.gitignore deleted file mode 100644 index 4f578ccb..00000000 --- a/packages/plugin-runtime/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build -node_modules -*.blob diff --git a/packages/plugin-runtime/package-lock.json b/packages/plugin-runtime/package-lock.json new file mode 100644 index 00000000..a17683ee --- /dev/null +++ b/packages/plugin-runtime/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "@yaakapp-internal/plugin-runtime", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@yaakapp-internal/plugin-runtime" + } + } +} diff --git a/packages/plugin-runtime/package.json b/packages/plugin-runtime/package.json index 0d44286b..f3d80c5b 100644 --- a/packages/plugin-runtime/package.json +++ b/packages/plugin-runtime/package.json @@ -5,17 +5,13 @@ "build": "run-p build:*", "build:main": "esbuild src/index.ts --bundle --platform=node --outfile=../../src-tauri/vendored/plugin-runtime/index.cjs", "build:worker": "esbuild src/index.worker.ts --bundle --platform=node --outfile=../../src-tauri/vendored/plugin-runtime/index.worker.cjs", - "build:proto": "grpc_tools_node_protoc --ts_proto_out=src/gen --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false --proto_path=../../proto ../../proto/plugins/*.proto" + "build:__main": "esbuild src/index.ts --bundle --platform=node --outfile=../../src-tauri/target/debug/vendored/plugin-runtime/index.cjs", + "build:__worker": "esbuild src/index.ts --bundle --platform=node --outfile=../../src-tauri/target/debug/vendored/plugin-runtime/index.worker.cjs" }, "dependencies": { - "intercept-stdout": "^0.1.2", - "long": "^5.2.3", - "nice-grpc": "^2.1.9", - "protobufjs": "^7.4.0" + "ws": "^8.18.0" }, "devDependencies": { - "@types/intercept-stdout": "^0.1.3", - "grpc-tools": "^1.12.4", - "ts-proto": "^2.2.0" + "@types/ws": "^8.5.13" } } diff --git a/packages/plugin-runtime/src/EventChannel.ts b/packages/plugin-runtime/src/EventChannel.ts index 9286ab2f..4275b6a0 100644 --- a/packages/plugin-runtime/src/EventChannel.ts +++ b/packages/plugin-runtime/src/EventChannel.ts @@ -1,21 +1,14 @@ -import type { InternalEvent } from '@yaakapp/api'; -import EventEmitter from 'node:events'; -import type { EventStreamEvent } from './gen/plugins/runtime'; +import type { InternalEvent } from "@yaakapp/api"; +import EventEmitter from "node:events"; export class EventChannel { emitter: EventEmitter = new EventEmitter(); emit(e: InternalEvent) { - this.emitter.emit('__plugin_event__', { event: JSON.stringify(e) }); + this.emitter.emit("__plugin_event__", e); } - async *listen(): AsyncGenerator { - while (true) { - yield new Promise((resolve) => { - this.emitter.once('__plugin_event__', (event: EventStreamEvent) => { - resolve(event); - }); - }); - } + listen(cb: (e: InternalEvent) => void) { + this.emitter.on("__plugin_event__", cb); } } diff --git a/packages/plugin-runtime/src/PluginHandle.ts b/packages/plugin-runtime/src/PluginHandle.ts index 7c4ae52b..b585c40b 100644 --- a/packages/plugin-runtime/src/PluginHandle.ts +++ b/packages/plugin-runtime/src/PluginHandle.ts @@ -1,4 +1,4 @@ -import type { BootRequest, InternalEvent } from '@yaakapp-internal/plugins'; +import type { BootRequest, InternalEvent } from '@yaakapp/api'; import path from 'node:path'; import { Worker } from 'node:worker_threads'; import type { EventChannel } from './EventChannel'; diff --git a/packages/plugin-runtime/src/gen/plugins/runtime.ts b/packages/plugin-runtime/src/gen/plugins/runtime.ts deleted file mode 100644 index dc89d1e6..00000000 --- a/packages/plugin-runtime/src/gen/plugins/runtime.ts +++ /dev/null @@ -1,126 +0,0 @@ -// Code generated by protoc-gen-ts_proto. DO NOT EDIT. -// versions: -// protoc-gen-ts_proto v2.2.3 -// protoc v3.19.1 -// source: plugins/runtime.proto - -/* eslint-disable */ -import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { type CallContext, type CallOptions } from "nice-grpc-common"; - -export const protobufPackage = "yaak.plugins.runtime"; - -export interface EventStreamEvent { - event: string; -} - -function createBaseEventStreamEvent(): EventStreamEvent { - return { event: "" }; -} - -export const EventStreamEvent: MessageFns = { - encode(message: EventStreamEvent, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { - if (message.event !== "") { - writer.uint32(10).string(message.event); - } - return writer; - }, - - decode(input: BinaryReader | Uint8Array, length?: number): EventStreamEvent { - const reader = input instanceof BinaryReader ? input : new BinaryReader(input); - let end = length === undefined ? reader.len : reader.pos + length; - const message = createBaseEventStreamEvent(); - while (reader.pos < end) { - const tag = reader.uint32(); - switch (tag >>> 3) { - case 1: { - if (tag !== 10) { - break; - } - - message.event = reader.string(); - continue; - } - } - if ((tag & 7) === 4 || tag === 0) { - break; - } - reader.skip(tag & 7); - } - return message; - }, - - fromJSON(object: any): EventStreamEvent { - return { event: isSet(object.event) ? globalThis.String(object.event) : "" }; - }, - - toJSON(message: EventStreamEvent): unknown { - const obj: any = {}; - if (message.event !== "") { - obj.event = message.event; - } - return obj; - }, - - create(base?: DeepPartial): EventStreamEvent { - return EventStreamEvent.fromPartial(base ?? {}); - }, - fromPartial(object: DeepPartial): EventStreamEvent { - const message = createBaseEventStreamEvent(); - message.event = object.event ?? ""; - return message; - }, -}; - -export type PluginRuntimeDefinition = typeof PluginRuntimeDefinition; -export const PluginRuntimeDefinition = { - name: "PluginRuntime", - fullName: "yaak.plugins.runtime.PluginRuntime", - methods: { - eventStream: { - name: "EventStream", - requestType: EventStreamEvent, - requestStream: true, - responseType: EventStreamEvent, - responseStream: true, - options: {}, - }, - }, -} as const; - -export interface PluginRuntimeServiceImplementation { - eventStream( - request: AsyncIterable, - context: CallContext & CallContextExt, - ): ServerStreamingMethodResult>; -} - -export interface PluginRuntimeClient { - eventStream( - request: AsyncIterable>, - options?: CallOptions & CallOptionsExt, - ): AsyncIterable; -} - -type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined; - -export type DeepPartial = T extends Builtin ? T - : T extends globalThis.Array ? globalThis.Array> - : T extends ReadonlyArray ? ReadonlyArray> - : T extends {} ? { [K in keyof T]?: DeepPartial } - : Partial; - -function isSet(value: any): boolean { - return value !== null && value !== undefined; -} - -export type ServerStreamingMethodResult = { [Symbol.asyncIterator](): AsyncIterator }; - -export interface MessageFns { - encode(message: T, writer?: BinaryWriter): BinaryWriter; - decode(input: BinaryReader | Uint8Array, length?: number): T; - fromJSON(object: any): T; - toJSON(message: T): unknown; - create(base?: DeepPartial): T; - fromPartial(object: DeepPartial): T; -} diff --git a/packages/plugin-runtime/src/index.ts b/packages/plugin-runtime/src/index.ts index 754e1acc..229a7564 100644 --- a/packages/plugin-runtime/src/index.ts +++ b/packages/plugin-runtime/src/index.ts @@ -1,52 +1,52 @@ import type { InternalEvent } from '@yaakapp/api'; -import { createChannel, createClient, Status } from 'nice-grpc'; import { EventChannel } from './EventChannel'; -import type { PluginRuntimeClient} from './gen/plugins/runtime'; -import { PluginRuntimeDefinition } from './gen/plugins/runtime'; import { PluginHandle } from './PluginHandle'; +import WebSocket from 'ws'; -const port = process.env.PORT || '50051'; - -const channel = createChannel(`localhost:${port}`, undefined, { - 'grpc.max_receive_message_length': Number.MAX_SAFE_INTEGER, - 'grpc.max_send_message_length': Number.MAX_SAFE_INTEGER, -}); -const client: PluginRuntimeClient = createClient(PluginRuntimeDefinition, channel); +const port = process.env.YAAK_PLUGIN_SERVER_PORT || '9442'; const events = new EventChannel(); const plugins: Record = {}; -(async () => { +const ws = new WebSocket(`ws://localhost:${port}`); + +ws.on('message', async (e: Buffer) => { try { - for await (const e of client.eventStream(events.listen())) { - const pluginEvent: InternalEvent = JSON.parse(e.event); - // Handle special event to bootstrap plugin - if (pluginEvent.payload.type === 'boot_request') { - const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.payload, events); - plugins[pluginEvent.pluginRefId] = plugin; - } - - // Once booted, forward all events to the plugin worker - const plugin = plugins[pluginEvent.pluginRefId]; - if (!plugin) { - console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId); - continue; - } - - if (pluginEvent.payload.type === 'terminate_request') { - await plugin.terminate(); - console.log('Terminated plugin worker', pluginEvent.pluginRefId); - delete plugins[pluginEvent.pluginRefId]; - } - - plugin.sendToWorker(pluginEvent); - } - console.log('Stream ended'); - } catch (err: any) { - if (err.code === Status.CANCELLED) { - console.log('Stream was cancelled by server'); - } else { - console.log('Client stream errored', err); - } + await handleIncoming(e.toString()); + } catch (err) { + console.log('Failed to handle incoming plugin event', err); } -})(); +}); +ws.on('open', (e) => console.log('Plugin runtime connected to websocket', e)); +ws.on('error', (e) => console.error('Plugin runtime websocket error', e)); +ws.on('close', (e) => console.log('Plugin runtime websocket closed', e)); + +// Listen for incoming events from plugins +events.listen((e) => { + const eventStr = JSON.stringify(e); + ws.send(eventStr); +}); + +async function handleIncoming(msg: string) { + const pluginEvent: InternalEvent = JSON.parse(msg); + // Handle special event to bootstrap plugin + if (pluginEvent.payload.type === 'boot_request') { + const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.payload, events); + plugins[pluginEvent.pluginRefId] = plugin; + } + + // Once booted, forward all events to the plugin worker + const plugin = plugins[pluginEvent.pluginRefId]; + if (!plugin) { + console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId); + return; + } + + if (pluginEvent.payload.type === 'terminate_request') { + await plugin.terminate(); + console.log('Terminated plugin worker', pluginEvent.pluginRefId); + delete plugins[pluginEvent.pluginRefId]; + } + + plugin.sendToWorker(pluginEvent); +} diff --git a/packages/plugin-runtime/src/index.worker.ts b/packages/plugin-runtime/src/index.worker.ts index 2a7a860b..17444d3e 100644 --- a/packages/plugin-runtime/src/index.worker.ts +++ b/packages/plugin-runtime/src/index.worker.ts @@ -1,27 +1,25 @@ import type { BootRequest, + Context, FindHttpResponsesResponse, GetHttpRequestByIdResponse, HttpRequestAction, - ImportResponse, InternalEvent, InternalEventPayload, + PluginDefinition, PromptTextResponse, RenderHttpRequestResponse, SendHttpRequestResponse, TemplateFunction, TemplateRenderResponse, WindowContext, -} from '@yaakapp-internal/plugins'; -import type { Context } from '@yaakapp/api'; -import type { HttpRequestActionPlugin } from '@yaakapp/api/lib/plugins/HttpRequestActionPlugin'; -import type { TemplateFunctionPlugin } from '@yaakapp/api/lib/plugins/TemplateFunctionPlugin'; -import interceptStdout from 'intercept-stdout'; +} from '@yaakapp/api'; import * as console from 'node:console'; import type { Stats } from 'node:fs'; import { readFileSync, statSync, watch } from 'node:fs'; import path from 'node:path'; import * as util from 'node:util'; +import { interceptStdout } from './interceptStdout'; import { parentPort, workerData } from 'node:worker_threads'; export interface PluginWorkerData { @@ -29,40 +27,32 @@ export interface PluginWorkerData { pluginRefId: string; } -async function initialize() { +function initialize(workerData: PluginWorkerData) { const { bootRequest: { dir: pluginDir, watch: enableWatch }, pluginRefId, }: PluginWorkerData = workerData; + const pathPkg = path.join(pluginDir, 'package.json'); - const pathMod = path.posix.join(pluginDir, 'build', 'index.js'); - async function importModule() { - const id = require.resolve(pathMod); - delete require.cache[id]; - return require(id); - } - const pkg = JSON.parse(readFileSync(pathPkg, 'utf8')); prefixStdout(`[plugin][${pkg.name}] %s`); - let mod = await importModule(); - - const capabilities: string[] = []; - if (typeof mod.pluginHookExport === 'function') capabilities.push('export'); - if (typeof mod.pluginHookImport === 'function') capabilities.push('import'); - if (typeof mod.pluginHookResponseFilter === 'function') capabilities.push('filter'); - - console.log('Plugin initialized', pkg.name, { capabilities, enableWatch }); - function buildEventToSend( windowContext: WindowContext, payload: InternalEventPayload, replyId: string | null = null, ): InternalEvent { - return { pluginRefId, id: genId(), replyId, payload, windowContext }; + return { + pluginRefId, + pluginName: path.basename(pluginDir), + id: genId(), + replyId, + payload, + windowContext, + }; } function sendEmpty(windowContext: WindowContext, replyId: string | null = null): string { @@ -86,7 +76,7 @@ async function initialize() { parentPort!.postMessage(event); } - async function sendAndWaitForReply>( + function sendAndWaitForReply>( windowContext: WindowContext, payload: InternalEventPayload, ): Promise { @@ -94,7 +84,7 @@ async function initialize() { const eventToSend = buildEventToSend(windowContext, payload, null); // 2. Spawn listener in background - const promise = new Promise(async (resolve) => { + const promise = new Promise((resolve) => { const cb = (event: InternalEvent) => { if (event.replyId === eventToSend.id) { parentPort!.off('message', cb); // Unlisten, now that we're done @@ -111,31 +101,33 @@ async function initialize() { return promise as unknown as Promise; } - async function reloadModule() { - mod = await importModule(); - } - - // Reload plugin if JS or package.json changes + // Reload plugin if the JS or package.json changes const windowContextNone: WindowContext = { type: 'none' }; - const cb = async () => { - await reloadModule(); + const fileChangeCallback = async () => { + await importModule(); return sendPayload(windowContextNone, { type: 'reload_response' }, null); }; if (enableWatch) { - watchFile(pathMod, cb); - watchFile(pathPkg, cb); + watchFile(pathMod, fileChangeCallback); + watchFile(pathPkg, fileChangeCallback); } const newCtx = (event: InternalEvent): Context => ({ clipboard: { async copyText(text) { - await sendAndWaitForReply(event.windowContext, { type: 'copy_text_request', text }); + await sendAndWaitForReply(event.windowContext, { + type: 'copy_text_request', + text, + }); }, }, toast: { async show(args) { - await sendAndWaitForReply(event.windowContext, { type: 'show_toast_request', ...args }); + await sendAndWaitForReply(event.windowContext, { + type: 'show_toast_request', + ...args, + }); }, }, prompt: { @@ -149,7 +141,10 @@ async function initialize() { }, httpResponse: { async find(args) { - const payload = { type: 'find_http_responses_request', ...args } as const; + const payload = { + type: 'find_http_responses_request', + ...args, + } as const; const { httpResponses } = await sendAndWaitForReply( event.windowContext, payload, @@ -159,7 +154,10 @@ async function initialize() { }, httpRequest: { async getById(args) { - const payload = { type: 'get_http_request_by_id_request', ...args } as const; + const payload = { + type: 'get_http_request_by_id_request', + ...args, + } as const; const { httpRequest } = await sendAndWaitForReply( event.windowContext, payload, @@ -167,7 +165,10 @@ async function initialize() { return httpRequest; }, async send(args) { - const payload = { type: 'send_http_request_request', ...args } as const; + const payload = { + type: 'send_http_request_request', + ...args, + } as const; const { httpResponse } = await sendAndWaitForReply( event.windowContext, payload, @@ -175,7 +176,10 @@ async function initialize() { return httpResponse; }, async render(args) { - const payload = { type: 'render_http_request_request', ...args } as const; + const payload = { + type: 'render_http_request_request', + ...args, + } as const; const { httpRequest } = await sendAndWaitForReply( event.windowContext, payload, @@ -187,7 +191,7 @@ async function initialize() { /** * Invoke Yaak's template engine to render a value. If the value is a nested type * (eg. object), it will be recursively rendered. - * */ + */ async render(args) { const payload = { type: 'template_render_request', ...args } as const; const result = await sendAndWaitForReply( @@ -199,17 +203,35 @@ async function initialize() { }, }); + let plug: PluginDefinition | null = null; + + function importModule() { + const id = require.resolve(pathMod); + delete require.cache[id]; + plug = require(id).plugin; + } + importModule(); + + if (pkg.name?.includes('yaak-faker')) { + sendPayload( + { type: 'none' }, + { type: 'error_response', error: 'Failed to initialize Faker plugin' }, + null, + ); + return; + } + // Message comes into the plugin to be processed parentPort!.on('message', async (event: InternalEvent) => { - const { windowContext, payload, id: replyId } = event; const ctx = newCtx(event); + const { windowContext, payload, id: replyId } = event; try { if (payload.type === 'boot_request') { + // console.log('Plugin initialized', pkg.name, { capabilities, enableWatch }); const payload: InternalEventPayload = { type: 'boot_response', name: pkg.name, version: pkg.version, - capabilities, }; sendPayload(windowContext, payload, replyId); return; @@ -223,12 +245,15 @@ async function initialize() { return; } - if (payload.type === 'import_request' && typeof mod.pluginHookImport === 'function') { - const reply: ImportResponse | null = await mod.pluginHookImport(ctx, payload.content); + if (payload.type === 'import_request' && typeof plug?.importer?.onImport === 'function') { + const reply = await plug.importer.onImport(ctx, { + text: payload.content, + }); if (reply != null) { const replyPayload: InternalEventPayload = { type: 'import_response', - resources: reply?.resources, + // deno-lint-ignore no-explicit-any + resources: reply.resources as any, }; sendPayload(windowContext, replyPayload, replyId); return; @@ -237,27 +262,15 @@ async function initialize() { } } - if ( - payload.type === 'export_http_request_request' && - typeof mod.pluginHookExport === 'function' - ) { - const reply: string = await mod.pluginHookExport(ctx, payload.httpRequest); - const replyPayload: InternalEventPayload = { - type: 'export_http_request_response', - content: reply, - }; - sendPayload(windowContext, replyPayload, replyId); - return; - } - - if (payload.type === 'filter_request' && typeof mod.pluginHookResponseFilter === 'function') { - const reply: string = await mod.pluginHookResponseFilter(ctx, { + if (payload.type === 'filter_request' && typeof plug?.filter?.onFilter === 'function') { + const reply = await plug.filter.onFilter(ctx, { filter: payload.filter, - body: payload.content, + payload: payload.content, + mimeType: payload.type, }); const replyPayload: InternalEventPayload = { type: 'filter_response', - content: reply, + content: reply.filtered, }; sendPayload(windowContext, replyPayload, replyId); return; @@ -265,15 +278,13 @@ async function initialize() { if ( payload.type === 'get_http_request_actions_request' && - Array.isArray(mod.plugin?.httpRequestActions) + Array.isArray(plug?.httpRequestActions) ) { - const reply: HttpRequestAction[] = mod.plugin.httpRequestActions.map( - (a: HttpRequestActionPlugin) => ({ - ...a, - // Add everything except onSelect - onSelect: undefined, - }), - ); + const reply: HttpRequestAction[] = plug.httpRequestActions.map((a) => ({ + ...a, + // Add everything except onSelect + onSelect: undefined, + })); const replyPayload: InternalEventPayload = { type: 'get_http_request_actions_response', pluginRefId, @@ -285,15 +296,13 @@ async function initialize() { if ( payload.type === 'get_template_functions_request' && - Array.isArray(mod.plugin?.templateFunctions) + Array.isArray(plug?.templateFunctions) ) { - const reply: TemplateFunction[] = mod.plugin.templateFunctions.map( - (a: TemplateFunctionPlugin) => ({ - ...a, - // Add everything except render - onRender: undefined, - }), - ); + const reply: TemplateFunction[] = plug.templateFunctions.map((a) => ({ + ...a, + // Add everything except render + onRender: undefined, + })); const replyPayload: InternalEventPayload = { type: 'get_template_functions_response', pluginRefId, @@ -303,21 +312,19 @@ async function initialize() { return; } - if (payload.type === 'get_http_authentication_request' && mod.plugin?.authentication) { - const auth = mod.plugin.authentication; + if (payload.type === 'get_http_authentication_request' && plug?.authentication) { + const { onApply: _, ...auth } = plug.authentication; const replyPayload: InternalEventPayload = { ...auth, type: 'get_http_authentication_response', - - // Remove unneeded attrs - onApply: undefined, }; + sendPayload(windowContext, replyPayload, replyId); return; } - if (payload.type === 'call_http_authentication_request' && mod.plugin?.authentication) { - const auth = mod.plugin.authentication; + if (payload.type === 'call_http_authentication_request' && plug?.authentication) { + const auth = plug.authentication; if (typeof auth?.onApply === 'function') { const result = await auth.onApply(ctx, payload); sendPayload( @@ -334,11 +341,9 @@ async function initialize() { if ( payload.type === 'call_http_request_action_request' && - Array.isArray(mod.plugin?.httpRequestActions) + Array.isArray(plug?.httpRequestActions) ) { - const action = mod.plugin.httpRequestActions.find( - (a: HttpRequestActionPlugin) => a.key === payload.key, - ); + const action = plug.httpRequestActions.find((a) => a.key === payload.key); if (typeof action?.onSelect === 'function') { await action.onSelect(ctx, payload.args); sendEmpty(windowContext, replyId); @@ -348,11 +353,9 @@ async function initialize() { if ( payload.type === 'call_template_function_request' && - Array.isArray(mod.plugin?.templateFunctions) + Array.isArray(plug?.templateFunctions) ) { - const action = mod.plugin.templateFunctions.find( - (a: TemplateFunctionPlugin) => a.name === payload.name, - ); + const action = plug.templateFunctions.find((a) => a.name === payload.name); if (typeof action?.onRender === 'function') { const result = await action.onRender(ctx, payload.args); sendPayload( @@ -368,10 +371,18 @@ async function initialize() { } if (payload.type === 'reload_request') { - await reloadModule(); + await importModule(); } } catch (err) { console.log('Plugin call threw exception', payload.type, err); + sendPayload( + windowContext, + { + type: 'error_response', + error: `${err}`, + }, + replyId, + ); // TODO: Return errors to server } @@ -380,9 +391,7 @@ async function initialize() { }); } -initialize().catch((err) => { - console.log('failed to boot plugin', err); -}); +initialize(workerData); function genId(len = 5): string { const alphabet = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; @@ -397,7 +406,7 @@ function prefixStdout(s: string) { if (!s.includes('%s')) { throw new Error('Console prefix must contain a "%s" replacer'); } - interceptStdout((text) => { + interceptStdout((text: string) => { const lines = text.split(/\n/); let newText = ''; for (let i = 0; i < lines.length; i++) { @@ -413,11 +422,11 @@ const watchedFiles: Record = {}; /** * Watch a file and trigger callback on change. * - * We also track the stat for each file because fs.watch will + * We also track the stat for each file because fs.watch() will * trigger a "change" event when the access date changes */ function watchFile(filepath: string, cb: (filepath: string) => void) { - watch(filepath, (_event, _name) => { + watch(filepath, () => { const stat = statSync(filepath); if (stat.mtimeMs !== watchedFiles[filepath]?.mtimeMs) { cb(filepath); diff --git a/packages/plugin-runtime/src/interceptStdout.ts b/packages/plugin-runtime/src/interceptStdout.ts new file mode 100644 index 00000000..0f130b21 --- /dev/null +++ b/packages/plugin-runtime/src/interceptStdout.ts @@ -0,0 +1,37 @@ +import process from "node:process"; + +export function interceptStdout( + intercept: (text: string) => string, +) { + const old_stdout_write = process.stdout.write; + const old_stderr_write = process.stderr.write; + + process.stdout.write = (function (write) { + return function (text: string) { + arguments[0] = interceptor(text, intercept); + // deno-lint-ignore no-explicit-any + write.apply(process.stdout, arguments as any); + return true; + }; + })(process.stdout.write); + + process.stderr.write = (function (write) { + return function (text: string) { + arguments[0] = interceptor(text, intercept); + // deno-lint-ignore no-explicit-any + write.apply(process.stderr, arguments as any); + return true; + }; + })(process.stderr.write); + + // puts back to original + return function unhook() { + process.stdout.write = old_stdout_write; + process.stderr.write = old_stderr_write; + }; +} + +function interceptor(text: string, fn: (text: string) => string) { + return fn(text).replace(/\n$/, "") + + (fn(text) && /\n$/.test(text) ? "\n" : ""); +} diff --git a/packages/plugin-runtime/tsconfig.json b/packages/plugin-runtime/tsconfig.json index d27c4e4c..88d9a9c0 100644 --- a/packages/plugin-runtime/tsconfig.json +++ b/packages/plugin-runtime/tsconfig.json @@ -8,6 +8,7 @@ "lib": ["es2021"], "noImplicitAny": false, "moduleResolution": "node16", + "resolveJsonModule": true, "sourceMap": true, "outDir": "build", "baseUrl": ".", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index a11e2d22..78c1250a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -311,9 +311,9 @@ dependencies = [ [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -322,9 +322,9 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", @@ -394,9 +394,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", @@ -413,17 +413,17 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 1.0.1", - "tower 0.4.13", + "sync_wrapper", + "tower 0.5.2", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -434,7 +434,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper", "tower-layer", "tower-service", ] @@ -651,9 +651,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1142,6 +1142,12 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "data-encoding" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" + [[package]] name = "datetime" version = "0.5.2" @@ -1549,12 +1555,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.35" @@ -2290,9 +2290,9 @@ dependencies = [ [[package]] name = "hyper-timeout" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" dependencies = [ "hyper", "hyper-util", @@ -2933,12 +2933,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "nanoid" version = "0.4.0" @@ -3148,7 +3142,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.87", @@ -3613,16 +3607,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.3.0", -] - [[package]] name = "phf" version = "0.8.0" @@ -3889,16 +3873,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn 2.0.87", -] - [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3976,27 +3950,6 @@ dependencies = [ "prost-derive", ] -[[package]] -name = "prost-build" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb182580f71dd070f88d01ce3de9f4da5021db7115d2e1c3605a754153b77c1" -dependencies = [ - "bytes", - "heck 0.5.0", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.87", - "tempfile", -] - [[package]] name = "prost-derive" version = "0.13.4" @@ -4382,7 +4335,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", @@ -4646,9 +4599,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -5477,12 +5430,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.1" @@ -6228,6 +6175,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4bf6fecd69fcdede0ec680aaf474cdab988f9de6bc73d3758f0160e3b7025a" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -6341,19 +6300,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tonic-build" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568392c5a2bd0020723e3f387891176aabafe36fd9fcd074ad309dfa0c8eb964" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 2.0.87", -] - [[package]] name = "tonic-reflection" version = "0.12.3" @@ -6396,7 +6342,7 @@ dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 1.0.1", + "sync_wrapper", "tokio", "tower-layer", "tower-service", @@ -6498,6 +6444,24 @@ dependencies = [ "termcolor", ] +[[package]] +name = "tungstenite" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413083a99c579593656008130e29255e54dcaae495be556cc26888f211648c24" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 2.0.7", + "utf-8", +] + [[package]] name = "typeid" version = "1.0.0" @@ -7636,9 +7600,9 @@ name = "yaak-plugins" version = "0.1.0" dependencies = [ "dunce", + "futures-util", "log", "path-slash", - "prost", "rand 0.8.5", "regex", "serde", @@ -7647,8 +7611,7 @@ dependencies = [ "tauri-plugin-shell", "thiserror 2.0.7", "tokio", - "tonic", - "tonic-build", + "tokio-tungstenite", "ts-rs", "yaak-models", ] diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e73a70fd..720289a1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -32,7 +32,7 @@ use tauri_plugin_clipboard_manager::ClipboardExt; use tauri_plugin_log::fern::colors::ColoredLevelConfig; use tauri_plugin_log::{Builder, Target, TargetKind}; use tauri_plugin_opener::OpenerExt; -use tauri_plugin_window_state::{AppHandleExt, StateFlags, WindowExt}; +use tauri_plugin_window_state::{AppHandleExt, StateFlags}; use tokio::fs::read_to_string; use tokio::sync::Mutex; use tokio::task::block_in_place; @@ -63,11 +63,12 @@ use yaak_models::queries::{ upsert_workspace_meta, BatchUpsertResult, UpdateSource, }; use yaak_plugins::events::{ - BootResponse, CallHttpAuthenticationRequest, CallHttpRequestActionRequest, FilterResponse, - FindHttpResponsesResponse, GetHttpAuthenticationResponse, GetHttpRequestActionsResponse, - GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, HttpHeader, Icon, InternalEvent, - InternalEventPayload, PromptTextResponse, RenderHttpRequestResponse, RenderPurpose, - SendHttpRequestResponse, ShowToastRequest, TemplateRenderResponse, WindowContext, + BootResponse, CallHttpAuthenticationRequest, CallHttpRequestActionRequest, Color, + FilterResponse, FindHttpResponsesResponse, GetHttpAuthenticationResponse, + GetHttpRequestActionsResponse, GetHttpRequestByIdResponse, GetTemplateFunctionsResponse, + HttpHeader, Icon, InternalEvent, InternalEventPayload, PromptTextResponse, + RenderHttpRequestResponse, RenderPurpose, SendHttpRequestResponse, ShowToastRequest, + TemplateRenderResponse, WindowContext, }; use yaak_plugins::manager::PluginManager; use yaak_plugins::plugin_handle::PluginHandle; @@ -2268,6 +2269,21 @@ async fn handle_plugin_event( render_json_value(req.data, &base_environment, environment.as_ref(), &cb).await; Some(InternalEventPayload::TemplateRenderResponse(TemplateRenderResponse { data })) } + InternalEventPayload::ErrorResponse(resp) => { + let window = get_window_from_window_context(app_handle, &window_context) + .expect("Failed to find window for plugin reload"); + let toast_event = plugin_handle.build_event_to_send( + WindowContext::from_window(&window), + &InternalEventPayload::ShowToastRequest(ShowToastRequest { + message: resp.error, + color: Some(Color::Danger), + ..Default::default() + }), + None, + ); + Box::pin(handle_plugin_event(app_handle, &toast_event, plugin_handle)).await; + None + } InternalEventPayload::ReloadResponse(_) => { let window = get_window_from_window_context(app_handle, &window_context) .expect("Failed to find window for plugin reload"); diff --git a/src-tauri/vendored/plugins/auth-jwt/build/index.js b/src-tauri/vendored/plugins/auth-jwt/build/index.js index 346c207f..53c98111 100644 --- a/src-tauri/vendored/plugins/auth-jwt/build/index.js +++ b/src-tauri/vendored/plugins/auth-jwt/build/index.js @@ -34,34 +34,34 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru var require_safe_buffer = __commonJS({ "../../node_modules/safe-buffer/index.js"(exports2, module2) { var buffer = require("buffer"); - var Buffer2 = buffer.Buffer; + var Buffer3 = buffer.Buffer; function copyProps(src, dst) { for (var key in src) { dst[key] = src[key]; } } - if (Buffer2.from && Buffer2.alloc && Buffer2.allocUnsafe && Buffer2.allocUnsafeSlow) { + if (Buffer3.from && Buffer3.alloc && Buffer3.allocUnsafe && Buffer3.allocUnsafeSlow) { module2.exports = buffer; } else { copyProps(buffer, exports2); exports2.Buffer = SafeBuffer; } function SafeBuffer(arg, encodingOrOffset, length) { - return Buffer2(arg, encodingOrOffset, length); + return Buffer3(arg, encodingOrOffset, length); } - SafeBuffer.prototype = Object.create(Buffer2.prototype); - copyProps(Buffer2, SafeBuffer); + SafeBuffer.prototype = Object.create(Buffer3.prototype); + copyProps(Buffer3, SafeBuffer); SafeBuffer.from = function(arg, encodingOrOffset, length) { if (typeof arg === "number") { throw new TypeError("Argument must not be a number"); } - return Buffer2(arg, encodingOrOffset, length); + return Buffer3(arg, encodingOrOffset, length); }; SafeBuffer.alloc = function(size, fill, encoding) { if (typeof size !== "number") { throw new TypeError("Argument must be a number"); } - var buf = Buffer2(size); + var buf = Buffer3(size); if (fill !== void 0) { if (typeof encoding === "string") { buf.fill(fill, encoding); @@ -77,7 +77,7 @@ var require_safe_buffer = __commonJS({ if (typeof size !== "number") { throw new TypeError("Argument must be a number"); } - return Buffer2(size); + return Buffer3(size); }; SafeBuffer.allocUnsafeSlow = function(size) { if (typeof size !== "number") { @@ -91,7 +91,7 @@ var require_safe_buffer = __commonJS({ // ../../node_modules/jws/lib/data-stream.js var require_data_stream = __commonJS({ "../../node_modules/jws/lib/data-stream.js"(exports2, module2) { - var Buffer2 = require_safe_buffer().Buffer; + var Buffer3 = require_safe_buffer().Buffer; var Stream = require("stream"); var util = require("util"); function DataStream(data) { @@ -99,11 +99,11 @@ var require_data_stream = __commonJS({ this.writable = true; this.readable = true; if (!data) { - this.buffer = Buffer2.alloc(0); + this.buffer = Buffer3.alloc(0); return this; } if (typeof data.pipe === "function") { - this.buffer = Buffer2.alloc(0); + this.buffer = Buffer3.alloc(0); data.pipe(this); return this; } @@ -121,7 +121,7 @@ var require_data_stream = __commonJS({ } util.inherits(DataStream, Stream); DataStream.prototype.write = function write(data) { - this.buffer = Buffer2.concat([this.buffer, Buffer2.from(data)]); + this.buffer = Buffer3.concat([this.buffer, Buffer3.from(data)]); this.emit("data", data); }; DataStream.prototype.end = function end(data) { @@ -140,11 +140,11 @@ var require_data_stream = __commonJS({ var require_buffer_equal_constant_time = __commonJS({ "../../node_modules/buffer-equal-constant-time/index.js"(exports2, module2) { "use strict"; - var Buffer2 = require("buffer").Buffer; + var Buffer3 = require("buffer").Buffer; var SlowBuffer = require("buffer").SlowBuffer; module2.exports = bufferEq; function bufferEq(a, b) { - if (!Buffer2.isBuffer(a) || !Buffer2.isBuffer(b)) { + if (!Buffer3.isBuffer(a) || !Buffer3.isBuffer(b)) { return false; } if (a.length !== b.length) { @@ -157,14 +157,14 @@ var require_buffer_equal_constant_time = __commonJS({ return c === 0; } bufferEq.install = function() { - Buffer2.prototype.equal = SlowBuffer.prototype.equal = function equal(that) { + Buffer3.prototype.equal = SlowBuffer.prototype.equal = function equal(that) { return bufferEq(this, that); }; }; - var origBufEqual = Buffer2.prototype.equal; + var origBufEqual = Buffer3.prototype.equal; var origSlowBufEqual = SlowBuffer.prototype.equal; bufferEq.restore = function() { - Buffer2.prototype.equal = origBufEqual; + Buffer3.prototype.equal = origBufEqual; SlowBuffer.prototype.equal = origSlowBufEqual; }; } @@ -198,7 +198,7 @@ var require_param_bytes_for_alg = __commonJS({ var require_ecdsa_sig_formatter = __commonJS({ "../../node_modules/ecdsa-sig-formatter/src/ecdsa-sig-formatter.js"(exports2, module2) { "use strict"; - var Buffer2 = require_safe_buffer().Buffer; + var Buffer3 = require_safe_buffer().Buffer; var getParamBytesForAlg = require_param_bytes_for_alg(); var MAX_OCTET = 128; var CLASS_UNIVERSAL = 0; @@ -211,10 +211,10 @@ var require_ecdsa_sig_formatter = __commonJS({ return base64.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); } function signatureAsBuffer(signature) { - if (Buffer2.isBuffer(signature)) { + if (Buffer3.isBuffer(signature)) { return signature; } else if ("string" === typeof signature) { - return Buffer2.from(signature, "base64"); + return Buffer3.from(signature, "base64"); } throw new TypeError("ECDSA signature must be a Base64 string or a Buffer"); } @@ -262,7 +262,7 @@ var require_ecdsa_sig_formatter = __commonJS({ throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain'); } var rPadding = paramBytes - rLength, sPadding = paramBytes - sLength; - var dst = Buffer2.allocUnsafe(rPadding + rLength + sPadding + sLength); + var dst = Buffer3.allocUnsafe(rPadding + rLength + sPadding + sLength); for (offset = 0; offset < rPadding; ++offset) { dst[offset] = 0; } @@ -300,7 +300,7 @@ var require_ecdsa_sig_formatter = __commonJS({ var sLength = paramBytes - sPadding; var rsBytes = 1 + 1 + rLength + 1 + 1 + sLength; var shortLength = rsBytes < MAX_OCTET; - var dst = Buffer2.allocUnsafe((shortLength ? 2 : 3) + rsBytes); + var dst = Buffer3.allocUnsafe((shortLength ? 2 : 3) + rsBytes); var offset = 0; dst[offset++] = ENCODED_TAG_SEQ; if (shortLength) { @@ -338,7 +338,7 @@ var require_ecdsa_sig_formatter = __commonJS({ var require_jwa = __commonJS({ "../../node_modules/jwa/index.js"(exports2, module2) { var bufferEqual = require_buffer_equal_constant_time(); - var Buffer2 = require_safe_buffer().Buffer; + var Buffer3 = require_safe_buffer().Buffer; var crypto = require("crypto"); var formatEcdsa = require_ecdsa_sig_formatter(); var util = require("util"); @@ -352,7 +352,7 @@ var require_jwa = __commonJS({ MSG_INVALID_SECRET += "or a KeyObject"; } function checkIsPublicKey(key) { - if (Buffer2.isBuffer(key)) { + if (Buffer3.isBuffer(key)) { return; } if (typeof key === "string") { @@ -375,7 +375,7 @@ var require_jwa = __commonJS({ } } function checkIsPrivateKey(key) { - if (Buffer2.isBuffer(key)) { + if (Buffer3.isBuffer(key)) { return; } if (typeof key === "string") { @@ -387,7 +387,7 @@ var require_jwa = __commonJS({ throw typeError(MSG_INVALID_SIGNER_KEY); } function checkIsSecretKey(key) { - if (Buffer2.isBuffer(key)) { + if (Buffer3.isBuffer(key)) { return; } if (typeof key === "string") { @@ -425,7 +425,7 @@ var require_jwa = __commonJS({ return new TypeError(errMsg); } function bufferOrString(obj) { - return Buffer2.isBuffer(obj) || typeof obj === "string"; + return Buffer3.isBuffer(obj) || typeof obj === "string"; } function normalizeInput(thing) { if (!bufferOrString(thing)) @@ -444,7 +444,7 @@ var require_jwa = __commonJS({ function createHmacVerifier(bits) { return function verify(thing, signature, secret) { var computedSig = createHmacSigner(bits)(thing, secret); - return bufferEqual(Buffer2.from(signature), Buffer2.from(computedSig)); + return bufferEqual(Buffer3.from(signature), Buffer3.from(computedSig)); }; } function createKeySigner(bits) { @@ -550,11 +550,11 @@ var require_jwa = __commonJS({ // ../../node_modules/jws/lib/tostring.js var require_tostring = __commonJS({ "../../node_modules/jws/lib/tostring.js"(exports2, module2) { - var Buffer2 = require("buffer").Buffer; + var Buffer3 = require("buffer").Buffer; module2.exports = function toString(obj) { if (typeof obj === "string") return obj; - if (typeof obj === "number" || Buffer2.isBuffer(obj)) + if (typeof obj === "number" || Buffer3.isBuffer(obj)) return obj.toString(); return JSON.stringify(obj); }; @@ -564,14 +564,14 @@ var require_tostring = __commonJS({ // ../../node_modules/jws/lib/sign-stream.js var require_sign_stream = __commonJS({ "../../node_modules/jws/lib/sign-stream.js"(exports2, module2) { - var Buffer2 = require_safe_buffer().Buffer; + var Buffer3 = require_safe_buffer().Buffer; var DataStream = require_data_stream(); var jwa = require_jwa(); var Stream = require("stream"); var toString = require_tostring(); var util = require("util"); function base64url(string, encoding) { - return Buffer2.from(string, encoding).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); + return Buffer3.from(string, encoding).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); } function jwsSecuredInput(header, payload, encoding) { encoding = encoding || "utf8"; @@ -634,7 +634,7 @@ var require_sign_stream = __commonJS({ // ../../node_modules/jws/lib/verify-stream.js var require_verify_stream = __commonJS({ "../../node_modules/jws/lib/verify-stream.js"(exports2, module2) { - var Buffer2 = require_safe_buffer().Buffer; + var Buffer3 = require_safe_buffer().Buffer; var DataStream = require_data_stream(); var jwa = require_jwa(); var Stream = require("stream"); @@ -655,7 +655,7 @@ var require_verify_stream = __commonJS({ } function headerFromJWS(jwsSig) { var encodedHeader = jwsSig.split(".", 1)[0]; - return safeJsonParse(Buffer2.from(encodedHeader, "base64").toString("binary")); + return safeJsonParse(Buffer3.from(encodedHeader, "base64").toString("binary")); } function securedInputFromJWS(jwsSig) { return jwsSig.split(".", 2).join("."); @@ -666,7 +666,7 @@ var require_verify_stream = __commonJS({ function payloadFromJWS(jwsSig, encoding) { encoding = encoding || "utf8"; var payload = jwsSig.split(".")[1]; - return Buffer2.from(payload, "base64").toString(encoding); + return Buffer3.from(payload, "base64").toString(encoding); } function isValidJws(string) { return JWS_REGEX.test(string) && !!headerFromJWS(string); @@ -3793,6 +3793,7 @@ __export(src_exports, { }); module.exports = __toCommonJS(src_exports); var import_jsonwebtoken = __toESM(require_jsonwebtoken()); +var import_node_buffer = __toESM(require("node:buffer")); var algorithms = [ "HS256", "HS384", @@ -3805,7 +3806,8 @@ var algorithms = [ "PS512", "ES256", "ES384", - "ES512" + "ES512", + "none" ]; var defaultAlgorithm = algorithms[0]; var plugin = { @@ -3818,31 +3820,34 @@ var plugin = { type: "select", name: "algorithm", label: "Algorithm", + hideLabel: true, defaultValue: defaultAlgorithm, - options: algorithms.map((value) => ({ name: value, value })) + options: algorithms.map((value) => ({ name: value === "none" ? "None" : value, value })) }, { - type: "text", + type: "editor", name: "secret", - label: "Secret", - optional: true + label: "Secret or Private Key", + optional: true, + hideGutter: true }, { type: "checkbox", name: "secretBase64", - label: "Secret Base64 Encoded" + label: "Secret is base64 encoded" }, { type: "editor", name: "payload", label: "Payload", language: "json", - optional: true + defaultValue: '{\n "foo": "bar"\n}', + placeholder: "{ }" } ], async onApply(_ctx, args) { const { algorithm, secret: _secret, secretBase64, payload } = args.config; - const secret = secretBase64 ? Buffer.from(`${_secret}`, "base64") : `${_secret}`; + const secret = secretBase64 ? import_node_buffer.default.from(`${_secret}`, "base64") : `${_secret}`; const token = import_jsonwebtoken.default.sign(`${payload}`, secret, { algorithm }); const value = `Bearer ${token}`; return { setHeaders: [{ name: "Authorization", value }] }; diff --git a/src-tauri/vendored/plugins/exporter-curl/build/index.js b/src-tauri/vendored/plugins/exporter-curl/build/index.js index d517e296..e2e52e30 100644 --- a/src-tauri/vendored/plugins/exporter-curl/build/index.js +++ b/src-tauri/vendored/plugins/exporter-curl/build/index.js @@ -20,8 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru // src/index.ts var src_exports = {}; __export(src_exports, { - plugin: () => plugin, - pluginHookExport: () => pluginHookExport + convertToCurl: () => convertToCurl, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var NEWLINE = "\\\n "; @@ -32,13 +32,13 @@ var plugin = { icon: "copy", async onSelect(ctx, args) { const rendered_request = await ctx.httpRequest.render({ httpRequest: args.httpRequest, purpose: "preview" }); - const data = await pluginHookExport(ctx, rendered_request); + const data = await convertToCurl(rendered_request); ctx.clipboard.copyText(data); ctx.toast.show({ message: "Curl copied to clipboard", icon: "copy" }); } }] }; -async function pluginHookExport(_ctx, request) { +async function convertToCurl(request) { const xs = ["curl"]; if (request.method) xs.push("-X", request.method); if (request.url) xs.push(quote(request.url)); @@ -104,6 +104,6 @@ function maybeParseJSON(v, fallback) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - plugin, - pluginHookExport + convertToCurl, + plugin }); diff --git a/src-tauri/vendored/plugins/filter-jsonpath/build/index.js b/src-tauri/vendored/plugins/filter-jsonpath/build/index.js index 1ccc3d2b..81e219a3 100644 --- a/src-tauri/vendored/plugins/filter-jsonpath/build/index.js +++ b/src-tauri/vendored/plugins/filter-jsonpath/build/index.js @@ -30,7 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookResponseFilter: () => pluginHookResponseFilter + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); @@ -499,12 +499,18 @@ JSONPath.prototype.safeVm = import_vm.default; var SafeScript = import_vm.default.Script; // src/index.ts -function pluginHookResponseFilter(_ctx, args) { - const parsed = JSON.parse(args.body); - const filtered = JSONPath({ path: args.filter, json: parsed }); - return JSON.stringify(filtered, null, 2); -} +var plugin = { + filter: { + name: "JSONPath", + description: "Filter JSONPath", + onFilter(_ctx, args) { + const parsed = JSON.parse(args.payload); + const filtered = JSONPath({ path: args.filter, json: parsed }); + return { filtered: JSON.stringify(filtered, null, 2) }; + } + } +}; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookResponseFilter + plugin }); diff --git a/src-tauri/vendored/plugins/filter-xpath/build/index.js b/src-tauri/vendored/plugins/filter-xpath/build/index.js index 783259c2..095c8ae6 100644 --- a/src-tauri/vendored/plugins/filter-xpath/build/index.js +++ b/src-tauri/vendored/plugins/filter-xpath/build/index.js @@ -8346,21 +8346,27 @@ var require_xpath = __commonJS({ // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookResponseFilter: () => pluginHookResponseFilter + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var import_xmldom = __toESM(require_lib()); var import_xpath = __toESM(require_xpath()); -function pluginHookResponseFilter(_ctx, { filter, body }) { - const doc = new import_xmldom.DOMParser().parseFromString(body, "text/xml"); - const result = import_xpath.default.select(filter, doc, false); - if (Array.isArray(result)) { - return result.map((r) => String(r)).join("\n"); - } else { - return String(result); +var plugin = { + filter: { + name: "XPath", + description: "Filter XPath", + onFilter(_ctx, args) { + const doc = new import_xmldom.DOMParser().parseFromString(args.payload, "text/xml"); + const result = import_xpath.default.select(args.filter, doc, false); + if (Array.isArray(result)) { + return { filtered: result.map((r) => String(r)).join("\n") }; + } else { + return { filtered: String(result) }; + } + } } -} +}; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookResponseFilter + plugin }); diff --git a/src-tauri/vendored/plugins/importer-curl/build/index.js b/src-tauri/vendored/plugins/importer-curl/build/index.js index 7ad523af..247d1503 100644 --- a/src-tauri/vendored/plugins/importer-curl/build/index.js +++ b/src-tauri/vendored/plugins/importer-curl/build/index.js @@ -260,7 +260,8 @@ var require_shell_quote = __commonJS({ // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookImport: () => pluginHookImport + convertCurl: () => convertCurl, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var import_shell_quote = __toESM(require_shell_quote()); @@ -290,7 +291,16 @@ var SUPPORTED_FLAGS = [ DATA_FLAGS ].flatMap((v) => v); var BOOLEAN_FLAGS = ["G", "get", "digest"]; -function pluginHookImport(_ctx, rawData) { +var plugin = { + importer: { + name: "cURL", + description: "Import cURL commands", + onImport(_ctx, args) { + return convertCurl(args.text); + } + } +}; +function convertCurl(rawData) { if (!rawData.match(/^\s*curl /)) { return null; } @@ -570,5 +580,6 @@ function generateId(model) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookImport + convertCurl, + plugin }); diff --git a/src-tauri/vendored/plugins/importer-insomnia/build/index.js b/src-tauri/vendored/plugins/importer-insomnia/build/index.js index 6a4dcd59..0208e18c 100644 --- a/src-tauri/vendored/plugins/importer-insomnia/build/index.js +++ b/src-tauri/vendored/plugins/importer-insomnia/build/index.js @@ -7208,11 +7208,21 @@ var require_dist = __commonJS({ // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookImport: () => pluginHookImport + convertInsomnia: () => convertInsomnia, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var import_yaml = __toESM(require_dist()); -function pluginHookImport(ctx, contents) { +var plugin = { + importer: { + name: "Insomnia", + description: "Import Insomnia workspaces", + onImport(_ctx, args) { + return convertInsomnia(args.text); + } + } +}; +function convertInsomnia(contents) { let parsed; try { parsed = JSON.parse(contents); @@ -7439,5 +7449,6 @@ function deleteUndefinedAttrs(obj) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookImport + convertInsomnia, + plugin }); diff --git a/src-tauri/vendored/plugins/importer-openapi/build/index.js b/src-tauri/vendored/plugins/importer-openapi/build/index.js index dc2f3b3f..3e4b11ba 100644 --- a/src-tauri/vendored/plugins/importer-openapi/build/index.js +++ b/src-tauri/vendored/plugins/importer-openapi/build/index.js @@ -113483,30 +113483,30 @@ var require_json_schema_faker = __commonJS({ }); }; exports5.filter = function(plugins, method, file) { - return plugins.filter(function(plugin) { - return !!getResult(plugin, method, file); + return plugins.filter(function(plugin2) { + return !!getResult(plugin2, method, file); }); }; exports5.sort = function(plugins) { - plugins.forEach(function(plugin) { - plugin.order = plugin.order || Number.MAX_SAFE_INTEGER; + plugins.forEach(function(plugin2) { + plugin2.order = plugin2.order || Number.MAX_SAFE_INTEGER; }); return plugins.sort(function(a, b) { return a.order - b.order; }); }; exports5.run = function(plugins, method, file) { - var plugin, lastError, index = 0; + var plugin2, lastError, index = 0; return new Promise(function(resolve2, reject) { runNextPlugin(); function runNextPlugin() { - plugin = plugins[index++]; - if (!plugin) { + plugin2 = plugins[index++]; + if (!plugin2) { return reject(lastError); } try { - debug(" %s", plugin.name); - var result = getResult(plugin, method, file, callback); + debug(" %s", plugin2.name); + var result = getResult(plugin2, method, file, callback); if (result && typeof result.then === "function") { result.then(onSuccess, onError); } else if (result !== void 0) { @@ -113526,7 +113526,7 @@ var require_json_schema_faker = __commonJS({ function onSuccess(result) { debug(" success"); resolve2({ - plugin, + plugin: plugin2, result }); } @@ -145850,7 +145850,8 @@ var require_openapi_to_postmanv2 = __commonJS({ // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookImport: () => pluginHookImport2 + convertOpenApi: () => convertOpenApi, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var import_openapi_to_postmanv2 = __toESM(require_openapi_to_postmanv2()); @@ -145859,7 +145860,7 @@ var import_openapi_to_postmanv2 = __toESM(require_openapi_to_postmanv2()); var POSTMAN_2_1_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"; var POSTMAN_2_0_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"; var VALID_SCHEMAS = [POSTMAN_2_0_0_SCHEMA, POSTMAN_2_1_0_SCHEMA]; -function pluginHookImport(_ctx, contents) { +function convertPostman(contents) { const root = parseJSONToRecord(contents); if (root == null) return; const info = toRecord(root.info); @@ -146150,7 +146151,16 @@ function generateId(model) { } // src/index.ts -async function pluginHookImport2(ctx, contents) { +var plugin = { + importer: { + name: "OpenAPI", + description: "Import OpenAPI collections", + onImport(_ctx, args) { + return convertOpenApi(args.text); + } + } +}; +async function convertOpenApi(contents) { let postmanCollection; try { postmanCollection = await new Promise((resolve, reject) => { @@ -146164,11 +146174,12 @@ async function pluginHookImport2(ctx, contents) { } catch (err) { return void 0; } - return pluginHookImport(ctx, JSON.stringify(postmanCollection)); + return convertPostman(JSON.stringify(postmanCollection)); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookImport + convertOpenApi, + plugin }); /*! Bundled license information: diff --git a/src-tauri/vendored/plugins/importer-postman/build/index.js b/src-tauri/vendored/plugins/importer-postman/build/index.js index 75c52214..1ff86f2f 100644 --- a/src-tauri/vendored/plugins/importer-postman/build/index.js +++ b/src-tauri/vendored/plugins/importer-postman/build/index.js @@ -20,13 +20,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookImport: () => pluginHookImport + convertPostman: () => convertPostman, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); var POSTMAN_2_1_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"; var POSTMAN_2_0_0_SCHEMA = "https://schema.getpostman.com/json/collection/v2.0.0/collection.json"; var VALID_SCHEMAS = [POSTMAN_2_0_0_SCHEMA, POSTMAN_2_1_0_SCHEMA]; -function pluginHookImport(_ctx, contents) { +var plugin = { + importer: { + name: "Postman", + description: "Import postman collections", + onImport(_ctx, args) { + return convertPostman(args.text); + } + } +}; +function convertPostman(contents) { const root = parseJSONToRecord(contents); if (root == null) return; const info = toRecord(root.info); @@ -317,5 +327,6 @@ function generateId(model) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookImport + convertPostman, + plugin }); diff --git a/src-tauri/vendored/plugins/importer-yaak/build/index.js b/src-tauri/vendored/plugins/importer-yaak/build/index.js index b82f77c7..5c00cd18 100644 --- a/src-tauri/vendored/plugins/importer-yaak/build/index.js +++ b/src-tauri/vendored/plugins/importer-yaak/build/index.js @@ -20,10 +20,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru // src/index.ts var src_exports = {}; __export(src_exports, { - pluginHookImport: () => pluginHookImport + migrateImport: () => migrateImport, + plugin: () => plugin }); module.exports = __toCommonJS(src_exports); -function pluginHookImport(_ctx, contents) { +var plugin = { + importer: { + name: "Yaak", + description: "Yaak official format", + onImport(_ctx, args) { + return migrateImport(args.text); + } + } +}; +function migrateImport(contents) { let parsed; try { parsed = JSON.parse(contents); @@ -66,5 +76,6 @@ function isJSObject(obj) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - pluginHookImport + migrateImport, + plugin }); diff --git a/src-tauri/yaak-grpc/Cargo.toml b/src-tauri/yaak-grpc/Cargo.toml index 2722bad2..7ac6dedf 100644 --- a/src-tauri/yaak-grpc/Cargo.toml +++ b/src-tauri/yaak-grpc/Cargo.toml @@ -5,23 +5,23 @@ edition = "2021" publish = false [dependencies] -tonic = "0.12.3" +anyhow = "1.0.79" +async-recursion = "1.1.1" +dunce = "1.0.4" +hyper = "1.5.2" +hyper-rustls = { version = "0.27.5", default-features = false, features = ["http2", "rustls-platform-verifier"] } +hyper-util = { version = "0.1.10", features = ["client-legacy", "client"] } +log = "0.4.20" +md5 = "0.7.0" prost = "0.13.4" -tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "fs"] } -tonic-reflection = "0.12.3" -tokio-stream = "0.1.14" +prost-reflect = { version = "0.14.4", default-features = false, features = ["serde", "derive"] } prost-types = "0.13.4" serde = { version = "1.0.196", features = ["derive"] } serde_json = "1.0.113" -prost-reflect = { version = "0.14.4", default-features = false, features = ["serde", "derive"] } -log = "0.4.20" -anyhow = "1.0.79" -hyper = "1.5.2" -hyper-util = { version = "0.1.10", features = ["client-legacy", "client"] } -hyper-rustls = { version = "0.27.5", default-features = false, features = ["http2", "rustls-platform-verifier"] } -uuid = { version = "1.7.0", features = ["v4"] } tauri = { workspace = true } tauri-plugin-shell = { workspace = true } -md5 = "0.7.0" -dunce = "1.0.4" -async-recursion = "1.1.1" +tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "fs"] } +tokio-stream = "0.1.14" +tonic = { version = "0.12.3", default-features = false, features = ["transport"] } +tonic-reflection = "0.12.3" +uuid = { version = "1.7.0", features = ["v4"] } diff --git a/src-tauri/yaak-grpc/src/lib.rs b/src-tauri/yaak-grpc/src/lib.rs index e49d9ea3..1de396a4 100644 --- a/src-tauri/yaak-grpc/src/lib.rs +++ b/src-tauri/yaak-grpc/src/lib.rs @@ -2,12 +2,12 @@ use prost_reflect::{DynamicMessage, MethodDescriptor, SerializeOptions}; use serde::{Deserialize, Serialize}; use serde_json::Deserializer; +mod client; mod codec; mod json_schema; pub mod manager; mod reflection; mod transport; -mod client; pub use tonic::metadata::*; pub use tonic::Code; diff --git a/src-tauri/yaak-grpc/src/manager.rs b/src-tauri/yaak-grpc/src/manager.rs index a71459c3..a39b59a9 100644 --- a/src-tauri/yaak-grpc/src/manager.rs +++ b/src-tauri/yaak-grpc/src/manager.rs @@ -16,11 +16,9 @@ use tonic::transport::Uri; use tonic::{IntoRequest, IntoStreamingRequest, Request, Response, Status, Streaming}; use crate::codec::DynamicCodec; -use crate::reflection::{ - fill_pool_from_files, fill_pool_from_reflection, method_desc_to_path, -}; -use crate::{json_schema, MethodDefinition, ServiceDefinition}; +use crate::reflection::{fill_pool_from_files, fill_pool_from_reflection, method_desc_to_path}; use crate::transport::get_transport; +use crate::{json_schema, MethodDefinition, ServiceDefinition}; #[derive(Clone)] pub struct GrpcConnection { diff --git a/src-tauri/yaak-grpc/src/transport.rs b/src-tauri/yaak-grpc/src/transport.rs index 58df85dc..af3dbcf0 100644 --- a/src-tauri/yaak-grpc/src/transport.rs +++ b/src-tauri/yaak-grpc/src/transport.rs @@ -1,6 +1,6 @@ use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder}; -use hyper_util::client::legacy::Client; use hyper_util::client::legacy::connect::HttpConnector; +use hyper_util::client::legacy::Client; use hyper_util::rt::TokioExecutor; use tonic::body::BoxBody; @@ -16,4 +16,3 @@ pub(crate) fn get_transport() -> Client, BoxBody> .http2_only(true) .build(connector) } - diff --git a/src-tauri/yaak-plugins/Cargo.toml b/src-tauri/yaak-plugins/Cargo.toml index 7f9d4489..7f4d69fe 100644 --- a/src-tauri/yaak-plugins/Cargo.toml +++ b/src-tauri/yaak-plugins/Cargo.toml @@ -7,19 +7,16 @@ publish = false [dependencies] dunce = "1.0.4" log = "0.4.21" -prost = "0.13.1" rand = "0.8.5" serde = { version = "1.0.198", features = ["derive"] } serde_json = "1.0.113" tauri = { workspace = true } tauri-plugin-shell = { workspace = true } tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread", "process"] } -tonic = { version = "0.12.3"} -ts-rs = { workspace = true } +ts-rs = { workspace = true, features = ["import-esm"] } thiserror = "2.0.7" yaak-models = { workspace = true } regex = "1.10.6" path-slash = "0.2.1" - -[build-dependencies] -tonic-build = "0.12.1" +tokio-tungstenite = "0.26.1" +futures-util = "0.3.30" diff --git a/src-tauri/yaak-plugins/bindings/events.ts b/src-tauri/yaak-plugins/bindings/events.ts index 5ec1a780..5b043002 100644 --- a/src-tauri/yaak-plugins/bindings/events.ts +++ b/src-tauri/yaak-plugins/bindings/events.ts @@ -1,15 +1,15 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Environment } from "./models"; -import type { Folder } from "./models"; -import type { GrpcRequest } from "./models"; -import type { HttpRequest } from "./models"; -import type { HttpResponse } from "./models"; -import type { JsonValue } from "./serde_json/JsonValue"; -import type { Workspace } from "./models"; +import type { Environment } from "./models.js"; +import type { Folder } from "./models.js"; +import type { GrpcRequest } from "./models.js"; +import type { HttpRequest } from "./models.js"; +import type { HttpResponse } from "./models.js"; +import type { JsonValue } from "./serde_json/JsonValue.js"; +import type { Workspace } from "./models.js"; export type BootRequest = { dir: string, watch: boolean, }; -export type BootResponse = { name: string, version: string, capabilities: Array, }; +export type BootResponse = { name: string, version: string, }; export type CallHttpAuthenticationRequest = { config: { [key in string]?: JsonValue }, method: string, url: string, headers: Array, }; @@ -38,6 +38,8 @@ export type EditorLanguage = "text" | "javascript" | "json" | "html" | "xml" | " export type EmptyPayload = {}; +export type ErrorResponse = { error: string, }; + export type ExportHttpRequestRequest = { httpRequest: HttpRequest, }; export type ExportHttpRequestResponse = { content: string, }; @@ -242,9 +244,9 @@ export type ImportResources = { workspaces: Array, environments: Arra export type ImportResponse = { resources: ImportResources, }; -export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, windowContext: WindowContext, }; +export type InternalEvent = { id: string, pluginRefId: string, pluginName: string, replyId: string | null, windowContext: WindowContext, payload: InternalEventPayload, }; -export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } & EmptyPayload | { "type": "reload_response" } & EmptyPayload | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_request" } & EmptyPayload | { "type": "get_http_authentication_response" } & GetHttpAuthenticationResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyPayload; +export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "reload_request" } & EmptyPayload | { "type": "reload_response" } & EmptyPayload | { "type": "terminate_request" } | { "type": "terminate_response" } | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_request" } & EmptyPayload | { "type": "get_http_authentication_response" } & GetHttpAuthenticationResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; export type PromptTextRequest = { id: string, title: string, label: string, description?: string, defaultValue?: string, placeholder?: string, /** diff --git a/src-tauri/yaak-plugins/build.rs b/src-tauri/yaak-plugins/build.rs deleted file mode 100644 index 7ecc4587..00000000 --- a/src-tauri/yaak-plugins/build.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() -> Result<(), Box> { - // Compile protobuf types - tonic_build::compile_protos("../../proto/plugins/runtime.proto")?; - - Ok(()) -} diff --git a/src-tauri/yaak-plugins/src/error.rs b/src-tauri/yaak-plugins/src/error.rs index d6bba76b..7efe9896 100644 --- a/src-tauri/yaak-plugins/src/error.rs +++ b/src-tauri/yaak-plugins/src/error.rs @@ -1,4 +1,4 @@ -use crate::server::plugin_runtime::EventStreamEvent; +use crate::events::InternalEvent; use thiserror::Error; use tokio::io; use tokio::sync::mpsc::error::SendError; @@ -14,18 +14,15 @@ pub enum Error { #[error("Tauri shell error: {0}")] TauriShellErr(#[from] tauri_plugin_shell::Error), - #[error("Grpc transport error: {0}")] - GrpcTransportErr(#[from] tonic::transport::Error), - #[error("Grpc send error: {0}")] - GrpcSendErr(#[from] SendError>), + GrpcSendErr(#[from] SendError), #[error("JSON error: {0}")] JsonErr(#[from] serde_json::Error), #[error("Plugin not found: {0}")] PluginNotFoundErr(String), - + #[error("Auth plugin not found: {0}")] AuthPluginNotFound(String), diff --git a/src-tauri/yaak-plugins/src/events.rs b/src-tauri/yaak-plugins/src/events.rs index 566c9f4a..984200cd 100644 --- a/src-tauri/yaak-plugins/src/events.rs +++ b/src-tauri/yaak-plugins/src/events.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use serde_json::Value; use std::collections::HashMap; use tauri::{Runtime, WebviewWindow}; use ts_rs::TS; @@ -11,9 +12,24 @@ use yaak_models::models::{Environment, Folder, GrpcRequest, HttpRequest, HttpRes pub struct InternalEvent { pub id: String, pub plugin_ref_id: String, + pub plugin_name: String, pub reply_id: Option, - pub payload: InternalEventPayload, pub window_context: WindowContext, + pub payload: InternalEventPayload, +} + +/// Special type used to deserialize everything but the payload. This is so we can +/// catch any plugin-related type errors, since payload is sent by the plugin author +/// and all other fields are sent by Yaak first-party code. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct InternalEventRawPayload { + pub id: String, + pub plugin_ref_id: String, + pub plugin_name: String, + pub reply_id: Option, + pub window_context: WindowContext, + pub payload: Value, } #[derive(Debug, Clone, Serialize, Deserialize, TS)] @@ -95,6 +111,8 @@ pub enum InternalEventPayload { /// Returned when a plugin doesn't get run, just so the server /// has something to listen for EmptyResponse(EmptyPayload), + + ErrorResponse(ErrorResponse), } #[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] @@ -102,6 +120,13 @@ pub enum InternalEventPayload { #[ts(export, type = "{}", export_to = "events.ts")] pub struct EmptyPayload {} +#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] +#[serde(default)] +#[ts(export, export_to = "events.ts")] +pub struct ErrorResponse { + pub error: String, +} + #[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] #[serde(default, rename_all = "camelCase")] #[ts(export, export_to = "events.ts")] @@ -116,7 +141,6 @@ pub struct BootRequest { pub struct BootResponse { pub name: String, pub version: String, - pub capabilities: Vec, } #[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] diff --git a/src-tauri/yaak-plugins/src/lib.rs b/src-tauri/yaak-plugins/src/lib.rs index 6842c2b7..659b6b01 100644 --- a/src-tauri/yaak-plugins/src/lib.rs +++ b/src-tauri/yaak-plugins/src/lib.rs @@ -9,7 +9,7 @@ pub mod events; pub mod manager; mod nodejs; pub mod plugin_handle; -mod server; +mod server_ws; mod util; pub fn init() -> TauriPlugin { diff --git a/src-tauri/yaak-plugins/src/manager.rs b/src-tauri/yaak-plugins/src/manager.rs index 42bfad94..2735cf42 100644 --- a/src-tauri/yaak-plugins/src/manager.rs +++ b/src-tauri/yaak-plugins/src/manager.rs @@ -12,8 +12,7 @@ use crate::events::{ }; use crate::nodejs::start_nodejs_plugin_runtime; use crate::plugin_handle::PluginHandle; -use crate::server::plugin_runtime::plugin_runtime_server::PluginRuntimeServer; -use crate::server::PluginRuntimeServerImpl; +use crate::server_ws::PluginRuntimeServerWebsocket; use log::{info, warn}; use std::collections::HashMap; use std::env; @@ -25,8 +24,6 @@ use tauri::{AppHandle, Manager, Runtime, WebviewWindow}; use tokio::fs::read_dir; use tokio::net::TcpListener; use tokio::sync::{mpsc, Mutex}; -use tonic::codegen::tokio_stream; -use tonic::transport::Server; use yaak_models::queries::{generate_id, list_plugins}; #[derive(Clone)] @@ -34,7 +31,7 @@ pub struct PluginManager { subscribers: Arc>>>, plugins: Arc>>, kill_tx: tokio::sync::watch::Sender, - grpc_service: Arc, + ws_service: Arc, } #[derive(Clone)] @@ -50,13 +47,13 @@ impl PluginManager { let (client_disconnect_tx, mut client_disconnect_rx) = mpsc::channel(128); let (client_connect_tx, mut client_connect_rx) = tokio::sync::watch::channel(false); - let grpc_service = - PluginRuntimeServerImpl::new(events_tx, client_disconnect_tx, client_connect_tx); + let ws_service = + PluginRuntimeServerWebsocket::new(events_tx, client_disconnect_tx, client_connect_tx); let plugin_manager = PluginManager { plugins: Arc::new(Mutex::new(Vec::new())), subscribers: Arc::new(Mutex::new(HashMap::new())), - grpc_service: Arc::new(grpc_service.clone()), + ws_service: Arc::new(ws_service.clone()), kill_tx: kill_server_tx, }; @@ -79,14 +76,9 @@ impl PluginManager { } }); - info!("Starting plugin server"); - - let svc = PluginRuntimeServer::new(grpc_service.to_owned()) - .max_encoding_message_size(usize::MAX) - .max_decoding_message_size(usize::MAX); - let listen_addr = match option_env!("PORT") { - None => "localhost:0".to_string(), + let listen_addr = match option_env!("YAAK_PLUGIN_SERVER_PORT") { Some(port) => format!("localhost:{port}"), + None => "localhost:0".to_string(), }; let listener = tauri::async_runtime::block_on(async move { TcpListener::bind(listen_addr).await.expect("Failed to bind TCP listener") @@ -114,14 +106,9 @@ impl PluginManager { }; // 1. Spawn server in the background - info!("Starting gRPC plugin server on {addr}"); + info!("Starting plugin server on {addr}"); tauri::async_runtime::spawn(async move { - Server::builder() - .timeout(Duration::from_secs(10)) - .add_service(svc) - .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(listener)) - .await - .expect("grpc plugin runtime server failed to start"); + ws_service.listen(listener).await; }); // 2. Start Node.js runtime and initialize plugins @@ -203,7 +190,7 @@ impl PluginManager { watch: bool, ) -> Result<()> { info!("Adding plugin by dir {dir}"); - let maybe_tx = self.grpc_service.app_to_plugin_events_tx.lock().await; + let maybe_tx = self.ws_service.app_to_plugin_events_tx.lock().await; let tx = match &*maybe_tx { None => return Err(ClientNotInitializedErr), Some(tx) => tx, @@ -357,21 +344,23 @@ impl PluginManager { .collect::>(); // 2. Spawn thread to subscribe to incoming events and check reply ids - let send_events_fut = { + let sub_events_fut = { let events_to_send = events_to_send.clone(); tokio::spawn(async move { let mut found_events = Vec::new(); while let Some(event) = rx.recv().await { - if events_to_send + let matched_sent_event = events_to_send .iter() .find(|e| Some(e.id.to_owned()) == event.reply_id) - .is_some() - { + .is_some(); + if matched_sent_event { found_events.push(event.clone()); }; - if found_events.len() == events_to_send.len() { + + let found_them_all = found_events.len() == events_to_send.len(); + if found_them_all{ break; } } @@ -390,7 +379,7 @@ impl PluginManager { } // 4. Join on the spawned thread - let events = send_events_fut.await.expect("Thread didn't succeed"); + let events = sub_events_fut.await.expect("Thread didn't succeed"); // 5. Unsubscribe self.unsubscribe(rx_id.as_str()).await; @@ -502,7 +491,7 @@ impl PluginManager { // Clone for mutability let mut req = req.clone(); - // Fill in default values + // Fill in default values for arg in authentication.config.clone() { let base = match arg { FormInput::Text(a) => a.base, diff --git a/src-tauri/yaak-plugins/src/nodejs.rs b/src-tauri/yaak-plugins/src/nodejs.rs index a854e6cc..aee90af3 100644 --- a/src-tauri/yaak-plugins/src/nodejs.rs +++ b/src-tauri/yaak-plugins/src/nodejs.rs @@ -32,8 +32,8 @@ pub async fn start_nodejs_plugin_runtime( let cmd = app .shell() .sidecar("yaaknode")? - .env("PORT", addr.port().to_string()) - .args(&[plugin_runtime_main]); + .env("YAAK_PLUGIN_RUNTIME_PORT", addr.port().to_string()) + .args(&[&plugin_runtime_main]); let (mut child_rx, child) = cmd.spawn()?; info!("Spawned plugin runtime"); diff --git a/src-tauri/yaak-plugins/src/plugin_handle.rs b/src-tauri/yaak-plugins/src/plugin_handle.rs index 5821e681..cdef4e6c 100644 --- a/src-tauri/yaak-plugins/src/plugin_handle.rs +++ b/src-tauri/yaak-plugins/src/plugin_handle.rs @@ -1,8 +1,8 @@ use crate::error::Result; use crate::events::{BootResponse, InternalEvent, InternalEventPayload, WindowContext}; -use crate::server::plugin_runtime::EventStreamEvent; use crate::util::gen_id; use log::info; +use std::path::Path; use std::sync::Arc; use tokio::sync::{mpsc, Mutex}; @@ -10,12 +10,12 @@ use tokio::sync::{mpsc, Mutex}; pub struct PluginHandle { pub ref_id: String, pub dir: String, - pub(crate) to_plugin_tx: Arc>>>, + pub(crate) to_plugin_tx: Arc>>, pub(crate) boot_resp: Arc>, } impl PluginHandle { - pub fn new(dir: &str, tx: mpsc::Sender>) -> Self { + pub fn new(dir: &str, tx: mpsc::Sender) -> Self { let ref_id = gen_id(); PluginHandle { @@ -46,9 +46,11 @@ impl PluginHandle { payload: &InternalEventPayload, reply_id: Option, ) -> InternalEvent { + let dir = Path::new(&self.dir); InternalEvent { id: gen_id(), plugin_ref_id: self.ref_id.clone(), + plugin_name: dir.file_name().unwrap().to_str().unwrap().to_string(), reply_id, payload: payload.clone(), window_context, @@ -63,13 +65,7 @@ impl PluginHandle { } pub(crate) async fn send(&self, event: &InternalEvent) -> Result<()> { - self.to_plugin_tx - .lock() - .await - .send(Ok(EventStreamEvent { - event: serde_json::to_string(event)?, - })) - .await?; + self.to_plugin_tx.lock().await.send(event.to_owned()).await?; Ok(()) } diff --git a/src-tauri/yaak-plugins/src/server.rs b/src-tauri/yaak-plugins/src/server.rs deleted file mode 100644 index 1055e9b1..00000000 --- a/src-tauri/yaak-plugins/src/server.rs +++ /dev/null @@ -1,99 +0,0 @@ -use log::warn; -use std::pin::Pin; -use std::sync::Arc; -use tokio::sync::{mpsc, Mutex}; -use tonic::codegen::tokio_stream::wrappers::ReceiverStream; -use tonic::codegen::tokio_stream::{Stream, StreamExt}; -use tonic::{Request, Response, Status, Streaming}; - -use crate::events::InternalEvent; -use crate::server::plugin_runtime::plugin_runtime_server::PluginRuntime; -use plugin_runtime::EventStreamEvent; - -pub mod plugin_runtime { - tonic::include_proto!("yaak.plugins.runtime"); -} - -type ResponseStream = Pin> + Send>>; - -#[derive(Clone)] -pub(crate) struct PluginRuntimeServerImpl { - pub(crate) app_to_plugin_events_tx: - Arc>>>>, - client_disconnect_tx: mpsc::Sender, - client_connect_tx: tokio::sync::watch::Sender, - plugin_to_app_events_tx: mpsc::Sender, -} - -impl PluginRuntimeServerImpl { - pub fn new( - events_tx: mpsc::Sender, - disconnect_tx: mpsc::Sender, - connect_tx: tokio::sync::watch::Sender, - ) -> Self { - PluginRuntimeServerImpl { - app_to_plugin_events_tx: Arc::new(Mutex::new(None)), - client_disconnect_tx: disconnect_tx, - client_connect_tx: connect_tx, - plugin_to_app_events_tx: events_tx, - } - } -} - -#[tonic::async_trait] -impl PluginRuntime for PluginRuntimeServerImpl { - type EventStreamStream = ResponseStream; - - async fn event_stream( - &self, - req: Request>, - ) -> tonic::Result> { - let mut in_stream = req.into_inner(); - - let (to_plugin_tx, to_plugin_rx) = mpsc::channel::>(128); - let mut app_to_plugin_events_tx = self.app_to_plugin_events_tx.lock().await; - *app_to_plugin_events_tx = Some(to_plugin_tx); - - let plugin_to_app_events_tx = self.plugin_to_app_events_tx.clone(); - let client_disconnect_tx = self.client_disconnect_tx.clone(); - - self.client_connect_tx.send(true).expect("Failed to send client ready event"); - - tokio::spawn(async move { - while let Some(result) = in_stream.next().await { - // Received event from plugin runtime - match result { - Ok(v) => { - let event: InternalEvent = match serde_json::from_str(v.event.as_str()) { - Ok(pe) => pe, - Err(e) => { - warn!("Failed to deserialize event {e:?} -> {}", v.event); - continue; - } - }; - - // Send event to subscribers - // Emit event to the channel for server to handle - if let Err(e) = plugin_to_app_events_tx.try_send(event.clone()) { - warn!("Failed to send to channel. Receiver probably isn't listening: {:?}", e); - } - } - Err(err) => { - // TODO: Better error handling - warn!("gRPC server error {err}"); - break; - } - }; - } - - if let Err(e) = client_disconnect_tx.send(true).await { - warn!("Failed to send killed event {:?}", e); - } - }); - - // Write the same data that was received - let out_stream = ReceiverStream::new(to_plugin_rx); - - Ok(Response::new(Box::pin(out_stream) as Self::EventStreamStream)) - } -} diff --git a/src-tauri/yaak-plugins/src/server_ws.rs b/src-tauri/yaak-plugins/src/server_ws.rs new file mode 100644 index 00000000..b0ee1e67 --- /dev/null +++ b/src-tauri/yaak-plugins/src/server_ws.rs @@ -0,0 +1,132 @@ +use crate::events::{ErrorResponse, InternalEvent, InternalEventPayload, InternalEventRawPayload}; +use futures_util::{SinkExt, StreamExt}; +use log::{error, info, warn}; +use std::sync::Arc; +use tokio::net::{TcpListener, TcpStream}; +use tokio::sync::{mpsc, Mutex}; +use tokio_tungstenite::accept_async_with_config; +use tokio_tungstenite::tungstenite::protocol::WebSocketConfig; +use tokio_tungstenite::tungstenite::Message; + +#[derive(Clone)] +pub(crate) struct PluginRuntimeServerWebsocket { + pub(crate) app_to_plugin_events_tx: Arc>>>, + client_disconnect_tx: mpsc::Sender, + client_connect_tx: tokio::sync::watch::Sender, + plugin_to_app_events_tx: mpsc::Sender, +} + +impl PluginRuntimeServerWebsocket { + pub fn new( + events_tx: mpsc::Sender, + disconnect_tx: mpsc::Sender, + connect_tx: tokio::sync::watch::Sender, + ) -> Self { + PluginRuntimeServerWebsocket { + app_to_plugin_events_tx: Arc::new(Mutex::new(None)), + client_disconnect_tx: disconnect_tx, + client_connect_tx: connect_tx, + plugin_to_app_events_tx: events_tx, + } + } + + pub async fn listen(&self, listener: TcpListener) { + while let Ok((stream, _)) = listener.accept().await { + self.accept_connection(stream).await; + } + } + + async fn accept_connection(&self, stream: TcpStream) { + let (to_plugin_tx, mut to_plugin_rx) = mpsc::channel::(128); + let mut app_to_plugin_events_tx = self.app_to_plugin_events_tx.lock().await; + *app_to_plugin_events_tx = Some(to_plugin_tx); + + let plugin_to_app_events_tx = self.plugin_to_app_events_tx.clone(); + let client_disconnect_tx = self.client_disconnect_tx.clone(); + let client_connect_tx = self.client_connect_tx.clone(); + + let addr = stream.peer_addr().expect("connected streams should have a peer address"); + + let conf = WebSocketConfig::default(); + let ws_stream = accept_async_with_config(stream, Some(conf)) + .await + .expect("Error during the websocket handshake occurred"); + + let (mut ws_sender, mut ws_receiver) = ws_stream.split(); + + tauri::async_runtime::spawn(async move { + client_connect_tx.send(true).expect("Failed to send client ready event"); + + info!("New plugin runtime websocket connection: {}", addr); + + loop { + tokio::select! { + msg = ws_receiver.next() => { + let msg = match msg { + Some(Ok(msg)) => msg, + Some(Err(e)) => { + warn!("Websocket error {e:?}"); + continue; + } + None => break, + }; + + // Skip non-text messages + if !msg.is_text() { + return; + } + + let event = match serde_json::from_str::(&msg.into_text().unwrap()) { + Ok(e) => e, + Err(e) => { + error!("Failed to decode plugin event {e:?}"); + continue; + } + }; + + // Parse everything but the payload so we can catch errors on that, specifically + let payload = serde_json::from_value::(event.payload) + .unwrap_or_else(|e| { + InternalEventPayload::ErrorResponse(ErrorResponse { + error: format!("Plugin error from {}: {e:?}", event.plugin_name), + }) + }); + + let event = InternalEvent{ + id: event.id, + payload, + plugin_ref_id: event.plugin_ref_id, + plugin_name: event.plugin_name, + window_context: event.window_context, + reply_id: event.reply_id, + }; + + // Send event to subscribers + // Emit event to the channel for server to handle + if let Err(e) = plugin_to_app_events_tx.try_send(event) { + warn!("Failed to send to channel. Receiver probably isn't listening: {:?}", e); + } + } + + event_for_plugin = to_plugin_rx.recv() => { + match event_for_plugin { + None => { + error!("Plugin runtime client WS channel closed"); + return; + }, + Some(event) => { + let event_bytes = serde_json::to_string(&event).unwrap(); + let msg = Message::text(event_bytes); + ws_sender.send(msg).await.unwrap(); + } + } + } + } + } + + if let Err(e) = client_disconnect_tx.send(true).await { + warn!("Failed to send killed event {:?}", e); + } + }); + } +} diff --git a/src-tauri/yaak-sync/bindings/sync.ts b/src-tauri/yaak-sync/bindings/sync.ts index e486cc48..d3fde759 100644 --- a/src-tauri/yaak-sync/bindings/sync.ts +++ b/src-tauri/yaak-sync/bindings/sync.ts @@ -1,6 +1,6 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { SyncModel } from "./models"; -import type { SyncState } from "./models"; +import type { SyncModel } from "./models.js"; +import type { SyncState } from "./models.js"; export type FsCandidate = { "type": "FsCandidate", model: SyncModel, relPath: string, checksum: string, }; diff --git a/src-web/components/UrlParameterEditor.tsx b/src-web/components/UrlParameterEditor.tsx index 59eb1081..72145caa 100644 --- a/src-web/components/UrlParameterEditor.tsx +++ b/src-web/components/UrlParameterEditor.tsx @@ -23,7 +23,7 @@ export function UrlParametersEditor({ pairs, forceUpdateKey, onChange, stateKey if (pairIndex >= 0) { pairEditor.current?.focusValue(pairIndex); } else { - console.log("Couldn't find pair to focus", { name, pairs }); + console.log(`Couldn't find pair to focus`, { name, pairs }); } }, [pairs], diff --git a/src-web/components/WindowControls.tsx b/src-web/components/WindowControls.tsx index 9ec3f294..f4adee3a 100644 --- a/src-web/components/WindowControls.tsx +++ b/src-web/components/WindowControls.tsx @@ -52,7 +52,6 @@ export function WindowControls({ className, onlyX }: Props) { await w.maximize(); setMaximized(true); } - console.log("TOGGLE", isMaximized); }} > {maximized ? ( diff --git a/src-web/components/core/Dropdown.tsx b/src-web/components/core/Dropdown.tsx index 28563cc3..4cabe3c5 100644 --- a/src-web/components/core/Dropdown.tsx +++ b/src-web/components/core/Dropdown.tsx @@ -122,8 +122,8 @@ export const Dropdown = forwardRef(function Dropdown // we have of detecting the dropdown closed, to do cleanup. useEffect(() => { if (!isOpen) { - buttonRef.current?.focus(); // Focus button - buttonRef.current!.style.backgroundColor = ''; // Clear persisted BG + // Clear persisted BG + buttonRef.current!.style.backgroundColor = ''; // Set to different value when opened and closed to force it to update. This is to force // to reset its selected-index state, which it does when this prop changes setDefaultSelectedIndex(null); diff --git a/src-web/components/core/Toast.tsx b/src-web/components/core/Toast.tsx index 508ad9f7..64b6acd4 100644 --- a/src-web/components/core/Toast.tsx +++ b/src-web/components/core/Toast.tsx @@ -57,7 +57,7 @@ export function Toast({ children, open, onClose, timeout, action, icon, color }: