diff --git a/.claude/rules.md b/.claude/rules.md new file mode 100644 index 00000000..eb78902d --- /dev/null +++ b/.claude/rules.md @@ -0,0 +1,22 @@ +# Project Rules + +## General Development +- **NEVER** commit or push without explicit confirmation + +## Build and Lint +- **ALWAYS** run `npm run lint` after modifying TypeScript or JavaScript files +- Run `npm run bootstrap` after changing plugin runtime or MCP server code + +## Plugin System + +### Backend Constraints +- Always use `UpdateSource::Plugin` when calling database methods from plugin events +- Never send timestamps (`createdAt`, `updatedAt`) from TypeScript - Rust backend controls these +- Backend uses `NaiveDateTime` (no timezone) so avoid sending ISO timestamp strings + +### MCP Server +- MCP server has **no active window context** - cannot call `window.workspaceId()` +- Get workspace ID from `workspaceCtx.yaak.workspace.list()` instead + +## Rust Type Generation +- Run `cd src-tauri && cargo test --package yaak-plugins` to regenerate TypeScript bindings after modifying Rust event types diff --git a/package-lock.json b/package-lock.json index 86c09beb..4e0faf4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "packages/common-lib", "packages/plugin-runtime", "packages/plugin-runtime-types", + "plugins-external/mcp-server", + "plugins-external/template-function-faker", "plugins/action-copy-curl", "plugins/action-copy-grpcurl", "plugins/auth-apikey", @@ -1488,6 +1490,33 @@ "integrity": "sha512-I7xWjLs2YSVMc5gGx1Z3ZG1lgFpITPndpi8Ku55GeEIKpACCPQNS/OTqQbxgTCfq0Ncvcc+CrFov96itVh6Qvw==", "license": "MIT" }, + "node_modules/@hono/mcp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@hono/mcp/-/mcp-0.2.3.tgz", + "integrity": "sha512-wrYKVQSjnBg4/ZinnnP/1t3jlvP3Z9fqZv8OzuhLXV4gVTLOHOHDhnXsIwD0nFVKk2pMOvA+sDfrKyRzw4yUPg==", + "license": "MIT", + "dependencies": { + "pkce-challenge": "^5.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.1", + "hono": "*", + "hono-rate-limiter": "^0.4.2", + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.7", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.7.tgz", + "integrity": "sha512-vUcD0uauS7EU2caukW8z5lJKtoGMokxNbJtBiwHgpqxEXokaHCBkQUmCHhjFB1VUTWdqj25QoMkMKzgjq+uhrw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -1715,6 +1744,62 @@ "@mjackson/headers": "^0.11.1" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.1.tgz", + "integrity": "sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.7", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.0.1", + "express-rate-limit": "^7.5.0", + "jose": "^6.1.1", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -1979,22 +2064,6 @@ "node": ">=16.9" } }, - "node_modules/@prantlf/jsonlint/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@prantlf/jsonlint/node_modules/ajv-draft-04": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", @@ -2072,12 +2141,6 @@ "node": ">= 6" } }, - "node_modules/@prantlf/jsonlint/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, "node_modules/@prantlf/jsonlint/node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -4048,6 +4111,10 @@ "resolved": "plugins/importer-yaak", "link": true }, + "node_modules/@yaak/mcp-server": { + "resolved": "plugins-external/mcp-server", + "link": true + }, "node_modules/@yaak/template-function-1password": { "resolved": "plugins/template-function-1password", "link": true @@ -4272,6 +4339,44 @@ "win32" ] }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -4312,6 +4417,22 @@ "node": ">=8" } }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -4329,28 +4450,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, "node_modules/ansi-regex": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", @@ -4819,6 +4918,46 @@ "safe-buffer": "^5.1.1" } }, + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -4940,6 +5079,15 @@ "dev": true, "license": "MIT" }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -5596,6 +5744,28 @@ "dev": true, "license": "MIT" }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-hrtime": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", @@ -5616,12 +5786,30 @@ "dev": true, "license": "MIT" }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-es": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", "license": "MIT" }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -5657,6 +5845,19 @@ "dev": true, "license": "MIT" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "8.3.6", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", @@ -6452,7 +6653,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6590,9 +6790,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6900,6 +7100,15 @@ "node": ">=0.10.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -7090,6 +7299,12 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.5.182", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.182.tgz", @@ -7104,6 +7319,15 @@ "dev": true, "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -7371,6 +7595,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -7405,12 +7635,42 @@ "@types/estree": "^1.0.0" } }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/execa": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", @@ -7633,6 +7893,89 @@ "node": ">=12.0.0" } }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.5.1.tgz", + "integrity": "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -7856,6 +8199,27 @@ "node": ">=8" } }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/find-index": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", @@ -8015,6 +8379,15 @@ "node": ">= 10.x" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -8069,6 +8442,15 @@ } } }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -9128,6 +9510,25 @@ "@babel/runtime": "^7.7.6" } }, + "node_modules/hono": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.3.tgz", + "integrity": "sha512-PmQi306+M/ct/m5s66Hrg+adPnkD5jiO6IjA7WhWw0gSBSo1EcRegwuI1deZ+wd5pzCGynCcn2DprnE4/yEV4w==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hono-rate-limiter": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/hono-rate-limiter/-/hono-rate-limiter-0.4.2.tgz", + "integrity": "sha512-AAtFqgADyrmbDijcRTT/HJfwqfvhalya2Zo+MgfdrMPas3zSMD8SU03cv+ZsYwRU1swv7zgVt0shwN059yzhjw==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "hono": "^4.1.1" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -9155,6 +9556,26 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/http-reasons": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/http-reasons/-/http-reasons-0.1.0.tgz", @@ -9387,6 +9808,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-accessor-descriptor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", @@ -9863,6 +10293,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -10053,7 +10489,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -10094,6 +10529,15 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jose": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", + "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/jotai": { "version": "2.12.5", "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.12.5.tgz", @@ -10239,6 +10683,18 @@ "node": ">=12.0.0" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -11195,6 +11651,15 @@ "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "license": "CC0-1.0" }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -11230,6 +11695,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge-refs": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", @@ -12157,6 +12634,15 @@ "url": "https://nearley.js.org/#give-to-nearley" } }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/neotraverse": { "version": "0.6.15", "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.15.tgz", @@ -12859,7 +13345,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -13036,11 +13521,22 @@ "node": ">=0.10.0" } }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -13123,12 +13619,6 @@ } } }, - "node_modules/openapi-to-postmanv2/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, "node_modules/openapi-to-postmanv2/node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", @@ -13415,6 +13905,15 @@ "node": ">=4" } }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -13461,7 +13960,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -13498,6 +13996,16 @@ "dev": true, "license": "ISC" }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/path-type": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", @@ -13628,6 +14136,15 @@ "node": ">= 6" } }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -14014,6 +14531,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -14023,6 +14553,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -14097,6 +14642,46 @@ "node": ">=0.10.0" } }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -14963,6 +15548,22 @@ "fsevents": "~2.3.2" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/rtl-css-js": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", @@ -15143,6 +15744,57 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/seroval": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/seroval/-/seroval-1.3.2.tgz", @@ -15164,6 +15816,25 @@ "seroval": "^1.0" } }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -15265,11 +15936,16 @@ "node": ">=0.10.0" } }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -15282,7 +15958,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15895,6 +16570,15 @@ "node": ">= 0.4" } }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/std-env": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", @@ -16790,6 +17474,15 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -16888,6 +17581,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -16967,9 +17699,9 @@ } }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -17170,6 +17902,15 @@ "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/unplugin": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz", @@ -17401,6 +18142,15 @@ "resolved": "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz", "integrity": "sha512-kRAyotcbNaSYoDnXvb4MHg/0a1egJdLwS6oJ38TJY7aw9n93Fl/3blIXdyYvPOp55CNxywooG/3BcrwNrBpcSg==" }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -17767,7 +18517,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -18056,7 +18805,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/ws": { @@ -18275,12 +19023,20 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", @@ -18314,6 +19070,38 @@ "cpy-cli": "^5.0.0" } }, + "plugins-external/mcp-server": { + "name": "@yaak/mcp-server", + "version": "0.1.0", + "dependencies": { + "@hono/mcp": "^0.2.3", + "@hono/node-server": "^1.19.7", + "@modelcontextprotocol/sdk": "^1.25.1", + "hono": "^4.11.3", + "zod": "^3.25.76" + }, + "devDependencies": { + "@types/node": "^25.0.3", + "typescript": "^5.9.3" + } + }, + "plugins-external/mcp-server/node_modules/@types/node": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", + "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "plugins-external/mcp-server/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, "plugins/action-copy-curl": { "name": "@yaak/action-copy-curl", "version": "0.1.0" @@ -18430,6 +19218,22 @@ "name": "@yaak/importer-yaak", "version": "0.1.0" }, + "plugins/mcp-server": { + "name": "@yaak/mcp-server", + "version": "0.1.0", + "extraneous": true, + "dependencies": { + "@hono/mcp": "^0.2.3", + "@hono/node-server": "^1.19.7", + "@modelcontextprotocol/sdk": "^1.25.1", + "hono": "^4.11.3", + "zod": "^3.25.76" + }, + "devDependencies": { + "@types/node": "^25.0.3", + "typescript": "^5.9.3" + } + }, "plugins/template-function-1password": { "name": "@yaak/template-function-1password", "version": "0.1.0", diff --git a/package.json b/package.json index da5722c0..2625d006 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "packages/common-lib", "packages/plugin-runtime", "packages/plugin-runtime-types", + "plugins-external/mcp-server", + "plugins-external/template-function-faker", "plugins/action-copy-curl", "plugins/action-copy-grpcurl", "plugins/auth-apikey", diff --git a/packages/plugin-runtime-types/package-lock.json b/packages/plugin-runtime-types/package-lock.json deleted file mode 100644 index ae23aa14..00000000 --- a/packages/plugin-runtime-types/package-lock.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "@yaakapp/api", - "version": "0.1.17", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@yaakapp/api", - "version": "0.1.17", - "dependencies": { - "@types/node": "^22.5.4" - }, - "devDependencies": { - "typescript": "^5.6.2" - } - }, - "node_modules/@types/node": { - "version": "22.5.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - } - } -} diff --git a/packages/plugin-runtime-types/src/bindings/gen_events.ts b/packages/plugin-runtime-types/src/bindings/gen_events.ts index 24a283e4..ee150d4d 100644 --- a/packages/plugin-runtime-types/src/bindings/gen_events.ts +++ b/packages/plugin-runtime-types/src/bindings/gen_events.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace } from "./gen_models"; +import type { AnyModel, Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace } from "./gen_models"; import type { JsonValue } from "./serde_json/JsonValue"; export type BootRequest = { dir: string, watch: boolean, }; @@ -62,6 +62,10 @@ export type DeleteKeyValueRequest = { key: string, }; export type DeleteKeyValueResponse = { deleted: boolean, }; +export type DeleteModelRequest = { model: string, id: string, }; + +export type DeleteModelResponse = { model: AnyModel, }; + export type EditorLanguage = "text" | "javascript" | "json" | "html" | "xml" | "graphql" | "markdown"; export type EmptyPayload = {}; @@ -411,7 +415,7 @@ export type ImportResponse = { resources: ImportResources, }; export type InternalEvent = { id: string, pluginRefId: string, pluginName: string, replyId: string | null, context: PluginContext, payload: InternalEventPayload, }; -export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } | { "type": "reload_response" } & ReloadResponse | { "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": "list_cookie_names_request" } & ListCookieNamesRequest | { "type": "list_cookie_names_response" } & ListCookieNamesResponse | { "type": "get_cookie_value_request" } & GetCookieValueRequest | { "type": "get_cookie_value_response" } & GetCookieValueResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_websocket_request_actions_request" } & EmptyPayload | { "type": "get_websocket_request_actions_response" } & GetWebsocketRequestActionsResponse | { "type": "call_websocket_request_action_request" } & CallWebsocketRequestActionRequest | { "type": "get_workspace_actions_request" } & EmptyPayload | { "type": "get_workspace_actions_response" } & GetWorkspaceActionsResponse | { "type": "call_workspace_action_request" } & CallWorkspaceActionRequest | { "type": "get_folder_actions_request" } & EmptyPayload | { "type": "get_folder_actions_response" } & GetFolderActionsResponse | { "type": "call_folder_action_request" } & CallFolderActionRequest | { "type": "get_grpc_request_actions_request" } & EmptyPayload | { "type": "get_grpc_request_actions_response" } & GetGrpcRequestActionsResponse | { "type": "call_grpc_request_action_request" } & CallGrpcRequestActionRequest | { "type": "get_template_function_summary_request" } & EmptyPayload | { "type": "get_template_function_summary_response" } & GetTemplateFunctionSummaryResponse | { "type": "get_template_function_config_request" } & GetTemplateFunctionConfigRequest | { "type": "get_template_function_config_response" } & GetTemplateFunctionConfigResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_summary_request" } & EmptyPayload | { "type": "get_http_authentication_summary_response" } & GetHttpAuthenticationSummaryResponse | { "type": "get_http_authentication_config_request" } & GetHttpAuthenticationConfigRequest | { "type": "get_http_authentication_config_response" } & GetHttpAuthenticationConfigResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "call_http_authentication_action_request" } & CallHttpAuthenticationActionRequest | { "type": "call_http_authentication_action_response" } & EmptyPayload | { "type": "copy_text_request" } & CopyTextRequest | { "type": "copy_text_response" } & EmptyPayload | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "render_grpc_request_request" } & RenderGrpcRequestRequest | { "type": "render_grpc_request_response" } & RenderGrpcRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "get_key_value_request" } & GetKeyValueRequest | { "type": "get_key_value_response" } & GetKeyValueResponse | { "type": "set_key_value_request" } & SetKeyValueRequest | { "type": "set_key_value_response" } & SetKeyValueResponse | { "type": "delete_key_value_request" } & DeleteKeyValueRequest | { "type": "delete_key_value_response" } & DeleteKeyValueResponse | { "type": "open_window_request" } & OpenWindowRequest | { "type": "window_navigate_event" } & WindowNavigateEvent | { "type": "window_close_event" } | { "type": "close_window_request" } & CloseWindowRequest | { "type": "show_toast_request" } & ShowToastRequest | { "type": "show_toast_response" } & EmptyPayload | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "window_info_request" } & WindowInfoRequest | { "type": "window_info_response" } & WindowInfoResponse | { "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": "list_http_requests_request" } & ListHttpRequestsRequest | { "type": "list_http_requests_response" } & ListHttpRequestsResponse | { "type": "list_folders_request" } & ListFoldersRequest | { "type": "list_folders_response" } & ListFoldersResponse | { "type": "get_themes_request" } & GetThemesRequest | { "type": "get_themes_response" } & GetThemesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; +export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } | { "type": "reload_response" } & ReloadResponse | { "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": "list_cookie_names_request" } & ListCookieNamesRequest | { "type": "list_cookie_names_response" } & ListCookieNamesResponse | { "type": "get_cookie_value_request" } & GetCookieValueRequest | { "type": "get_cookie_value_response" } & GetCookieValueResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_websocket_request_actions_request" } & EmptyPayload | { "type": "get_websocket_request_actions_response" } & GetWebsocketRequestActionsResponse | { "type": "call_websocket_request_action_request" } & CallWebsocketRequestActionRequest | { "type": "get_workspace_actions_request" } & EmptyPayload | { "type": "get_workspace_actions_response" } & GetWorkspaceActionsResponse | { "type": "call_workspace_action_request" } & CallWorkspaceActionRequest | { "type": "get_folder_actions_request" } & EmptyPayload | { "type": "get_folder_actions_response" } & GetFolderActionsResponse | { "type": "call_folder_action_request" } & CallFolderActionRequest | { "type": "get_grpc_request_actions_request" } & EmptyPayload | { "type": "get_grpc_request_actions_response" } & GetGrpcRequestActionsResponse | { "type": "call_grpc_request_action_request" } & CallGrpcRequestActionRequest | { "type": "get_template_function_summary_request" } & EmptyPayload | { "type": "get_template_function_summary_response" } & GetTemplateFunctionSummaryResponse | { "type": "get_template_function_config_request" } & GetTemplateFunctionConfigRequest | { "type": "get_template_function_config_response" } & GetTemplateFunctionConfigResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_summary_request" } & EmptyPayload | { "type": "get_http_authentication_summary_response" } & GetHttpAuthenticationSummaryResponse | { "type": "get_http_authentication_config_request" } & GetHttpAuthenticationConfigRequest | { "type": "get_http_authentication_config_response" } & GetHttpAuthenticationConfigResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "call_http_authentication_action_request" } & CallHttpAuthenticationActionRequest | { "type": "call_http_authentication_action_response" } & EmptyPayload | { "type": "copy_text_request" } & CopyTextRequest | { "type": "copy_text_response" } & EmptyPayload | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "render_grpc_request_request" } & RenderGrpcRequestRequest | { "type": "render_grpc_request_response" } & RenderGrpcRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "get_key_value_request" } & GetKeyValueRequest | { "type": "get_key_value_response" } & GetKeyValueResponse | { "type": "set_key_value_request" } & SetKeyValueRequest | { "type": "set_key_value_response" } & SetKeyValueResponse | { "type": "delete_key_value_request" } & DeleteKeyValueRequest | { "type": "delete_key_value_response" } & DeleteKeyValueResponse | { "type": "open_window_request" } & OpenWindowRequest | { "type": "window_navigate_event" } & WindowNavigateEvent | { "type": "window_close_event" } | { "type": "close_window_request" } & CloseWindowRequest | { "type": "show_toast_request" } & ShowToastRequest | { "type": "show_toast_response" } & EmptyPayload | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "window_info_request" } & WindowInfoRequest | { "type": "window_info_response" } & WindowInfoResponse | { "type": "list_workspaces_request" } & ListWorkspacesRequest | { "type": "list_workspaces_response" } & ListWorkspacesResponse | { "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": "list_http_requests_request" } & ListHttpRequestsRequest | { "type": "list_http_requests_response" } & ListHttpRequestsResponse | { "type": "list_folders_request" } & ListFoldersRequest | { "type": "list_folders_response" } & ListFoldersResponse | { "type": "upsert_model_request" } & UpsertModelRequest | { "type": "upsert_model_response" } & UpsertModelResponse | { "type": "delete_model_request" } & DeleteModelRequest | { "type": "delete_model_response" } & DeleteModelResponse | { "type": "get_themes_request" } & GetThemesRequest | { "type": "get_themes_response" } & GetThemesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; export type JsonPrimitive = string | number | boolean | null; @@ -427,6 +431,10 @@ export type ListHttpRequestsRequest = { folderId?: string, }; export type ListHttpRequestsResponse = { httpRequests: Array, }; +export type ListWorkspacesRequest = Record; + +export type ListWorkspacesResponse = { workspaces: Array, }; + export type OpenWindowRequest = { url: string, /** * Label for the window. If not provided, a random one will be generated. @@ -521,6 +529,10 @@ export type ThemeComponentColors = { surface?: string, surfaceHighlight?: string export type ThemeComponents = { dialog?: ThemeComponentColors, menu?: ThemeComponentColors, toast?: ThemeComponentColors, sidebar?: ThemeComponentColors, responsePane?: ThemeComponentColors, appHeader?: ThemeComponentColors, button?: ThemeComponentColors, banner?: ThemeComponentColors, templateTag?: ThemeComponentColors, urlBar?: ThemeComponentColors, editor?: ThemeComponentColors, input?: ThemeComponentColors, }; +export type UpsertModelRequest = { model: AnyModel, }; + +export type UpsertModelResponse = { model: AnyModel, }; + export type WebsocketRequestAction = { label: string, icon?: Icon, }; export type WindowInfoRequest = { label: string, }; @@ -532,3 +544,5 @@ export type WindowNavigateEvent = { url: string, }; export type WindowSize = { width: number, height: number, }; export type WorkspaceAction = { label: string, icon?: Icon, }; + +export type WorkspaceInfo = { id: string, name: string, }; diff --git a/packages/plugin-runtime-types/src/bindings/gen_models.ts b/packages/plugin-runtime-types/src/bindings/gen_models.ts index 454903fe..ba67aba3 100644 --- a/packages/plugin-runtime-types/src/bindings/gen_models.ts +++ b/packages/plugin-runtime-types/src/bindings/gen_models.ts @@ -1,11 +1,37 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +export type AnyModel = CookieJar | Environment | Folder | GraphQlIntrospection | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | HttpResponseEvent | KeyValue | Plugin | Settings | SyncState | WebsocketConnection | WebsocketEvent | WebsocketRequest | Workspace | WorkspaceMeta; + +export type ClientCertificate = { host: string, port: number | null, crtFile: string | null, keyFile: string | null, pfxFile: string | null, passphrase: string | null, enabled?: boolean, }; + +export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], }; + +export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty"; + +export type CookieExpires = { "AtUtc": string } | "SessionEnd"; + +export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array, name: string, }; + +export type EditorKeymap = "default" | "vim" | "vscode" | "emacs"; + +export type EncryptedKey = { encryptedKey: string, }; + export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, public: boolean, parentModel: string, parentId: string | null, variables: Array, color: string | null, sortPriority: number, }; export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, }; export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, description: string, headers: Array, name: string, sortPriority: number, }; +export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, }; + +export type GrpcConnection = { model: "grpc_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, method: string, service: string, status: number, state: GrpcConnectionState, trailers: { [key in string]?: string }, url: string, }; + +export type GrpcConnectionState = "initialized" | "connected" | "closed"; + +export type GrpcEvent = { model: "grpc_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, content: string, error: string | null, eventType: GrpcEventType, metadata: { [key in string]?: string }, status: number | null, }; + +export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end"; + export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record, description: string, message: string, metadata: Array, method: string | null, name: string, service: string | null, sortPriority: number, url: string, }; export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, body: Record, bodyType: string | null, description: string, headers: Array, method: string, name: string, sortPriority: number, url: string, urlParameters: Array, }; @@ -14,12 +40,43 @@ export type HttpRequestHeader = { enabled?: boolean, name: string, value: string export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, contentLengthCompressed: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array, remoteAddr: string | null, requestContentLength: number | null, requestHeaders: Array, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, }; +export type HttpResponseEvent = { model: "http_response_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, responseId: string, event: HttpResponseEventData, }; + +/** + * Serializable representation of HTTP response events for DB storage. + * This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support. + * The `From` impl is in yaak-http to avoid circular dependencies. + */ +export type HttpResponseEventData = { "type": "setting", name: string, value: string, } | { "type": "info", message: string, } | { "type": "redirect", url: string, status: number, behavior: string, } | { "type": "send_url", method: string, path: string, } | { "type": "receive_url", version: string, status: string, } | { "type": "header_up", name: string, value: string, } | { "type": "header_down", name: string, value: string, } | { "type": "chunk_sent", bytes: number, } | { "type": "chunk_received", bytes: number, }; + export type HttpResponseHeader = { name: string, value: string, }; export type HttpResponseState = "initialized" | "connected" | "closed"; export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id?: string, }; +export type KeyValue = { model: "key_value", id: string, createdAt: string, updatedAt: string, key: string, namespace: string, value: string, }; + +export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, }; + +export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" }; + +export type ProxySettingAuth = { user: string, password: string, }; + +export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, clientCertificates: Array, coloredMethods: boolean, editorFont: string | null, editorFontSize: number, editorKeymap: EditorKeymap, editorSoftWrap: boolean, hideWindowControls: boolean, useNativeTitlebar: boolean, interfaceFont: string | null, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, hideLicenseBadge: boolean, autoupdate: boolean, autoDownloadUpdates: boolean, checkNotifications: boolean, }; + +export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, }; + +export type WebsocketConnection = { model: "websocket_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, headers: Array, state: WebsocketConnectionState, status: number, url: string, }; + +export type WebsocketConnectionState = "initialized" | "connected" | "closing" | "closed"; + +export type WebsocketEvent = { model: "websocket_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, isServer: boolean, message: Array, messageType: WebsocketEventType, }; + +export type WebsocketEventType = "binary" | "close" | "frame" | "open" | "ping" | "pong" | "text"; + export type WebsocketRequest = { model: "websocket_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, description: string, headers: Array, message: string, name: string, sortPriority: number, url: string, urlParameters: Array, }; export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, authentication: Record, authenticationType: string | null, description: string, headers: Array, name: string, encryptionKeyChallenge: string | null, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, }; + +export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, }; diff --git a/packages/plugin-runtime-types/src/plugins/Context.ts b/packages/plugin-runtime-types/src/plugins/Context.ts index 36c314fc..3619a9ce 100644 --- a/packages/plugin-runtime-types/src/plugins/Context.ts +++ b/packages/plugin-runtime-types/src/plugins/Context.ts @@ -1,29 +1,33 @@ import type { - FindHttpResponsesRequest, - FindHttpResponsesResponse, - GetCookieValueRequest, - GetCookieValueResponse, - GetHttpRequestByIdRequest, - GetHttpRequestByIdResponse, - ListCookieNamesResponse, - ListFoldersRequest, - ListFoldersResponse, - ListHttpRequestsRequest, - ListHttpRequestsResponse, - OpenWindowRequest, - PromptTextRequest, - PromptTextResponse, - RenderGrpcRequestRequest, - RenderGrpcRequestResponse, - RenderHttpRequestRequest, - RenderHttpRequestResponse, - SendHttpRequestRequest, - SendHttpRequestResponse, - ShowToastRequest, - TemplateRenderRequest, + FindHttpResponsesRequest, + FindHttpResponsesResponse, + GetCookieValueRequest, + GetCookieValueResponse, + GetHttpRequestByIdRequest, + GetHttpRequestByIdResponse, + ListCookieNamesResponse, + ListFoldersRequest, + ListFoldersResponse, + ListHttpRequestsRequest, + ListHttpRequestsResponse, + OpenWindowRequest, + PromptTextRequest, + PromptTextResponse, + RenderGrpcRequestRequest, + RenderGrpcRequestResponse, + RenderHttpRequestRequest, + RenderHttpRequestResponse, + SendHttpRequestRequest, + SendHttpRequestResponse, + ShowToastRequest, + TemplateRenderRequest, + WorkspaceInfo, } from '../bindings/gen_events.ts'; +import type { HttpRequest } from '../bindings/gen_models.ts'; import type { JsonValue } from '../bindings/serde_json/JsonValue'; +export type WorkspaceHandle = Pick; + export interface Context { clipboard: { copyText(text: string): Promise; @@ -62,6 +66,15 @@ export interface Context { getById(args: GetHttpRequestByIdRequest): Promise; render(args: RenderHttpRequestRequest): Promise; list(args?: ListHttpRequestsRequest): Promise; + create( + args: Omit, 'id' | 'model' | 'createdAt' | 'updatedAt'> & + Pick, + ): Promise; + update( + args: Omit, 'model' | 'createdAt' | 'updatedAt'> & + Pick, + ): Promise; + delete(args: { id: string }): Promise; }; folder: { list(args?: ListFoldersRequest): Promise; @@ -75,4 +88,8 @@ export interface Context { plugin: { reload(): void; }; + workspace: { + list(): Promise; + withContext(handle: WorkspaceHandle): Context; + }; } diff --git a/packages/plugin-runtime-types/src/plugins/index.ts b/packages/plugin-runtime-types/src/plugins/index.ts index 7fb13081..b17087f6 100644 --- a/packages/plugin-runtime-types/src/plugins/index.ts +++ b/packages/plugin-runtime-types/src/plugins/index.ts @@ -4,7 +4,7 @@ import type { Context } from './Context'; import type { FilterPlugin } from './FilterPlugin'; import { GrpcRequestActionPlugin } from './GrpcRequestActionPlugin'; import type { HttpRequestActionPlugin } from './HttpRequestActionPlugin'; -import type { WebsocketRequestActionPlugin } from './WebSocketRequestActionPlugin'; +import type { WebsocketRequestActionPlugin } from './WebsocketRequestActionPlugin'; import type { WorkspaceActionPlugin } from './WorkspaceActionPlugin'; import type { FolderActionPlugin } from './FolderActionPlugin'; import type { ImporterPlugin } from './ImporterPlugin'; diff --git a/packages/plugin-runtime/package-lock.json b/packages/plugin-runtime/package-lock.json deleted file mode 100644 index a17683ee..00000000 --- a/packages/plugin-runtime/package-lock.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "@yaakapp-internal/plugin-runtime", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@yaakapp-internal/plugin-runtime" - } - } -} diff --git a/packages/plugin-runtime/src/PluginInstance.ts b/packages/plugin-runtime/src/PluginInstance.ts index bf452b6d..00a6eb77 100644 --- a/packages/plugin-runtime/src/PluginInstance.ts +++ b/packages/plugin-runtime/src/PluginInstance.ts @@ -2,6 +2,7 @@ import { applyFormInputDefaults, validateTemplateFunctionArgs } from '@yaakapp-i import { BootRequest, DeleteKeyValueResponse, + DeleteModelResponse, FindHttpResponsesResponse, GetCookieValueRequest, GetCookieValueResponse, @@ -9,10 +10,12 @@ import { GetKeyValueResponse, GrpcRequestAction, HttpAuthenticationAction, + HttpRequest, HttpRequestAction, InternalEvent, InternalEventPayload, ListCookieNamesResponse, + ListWorkspacesResponse, PluginContext, PromptTextResponse, RenderGrpcRequestResponse, @@ -20,6 +23,7 @@ import { SendHttpRequestResponse, TemplateFunction, TemplateRenderResponse, + UpsertModelResponse, WindowInfoResponse, } from '@yaakapp-internal/plugins'; import { Context, PluginDefinition } from '@yaakapp/api'; @@ -706,6 +710,40 @@ export class PluginInstance { const { httpRequests } = await this.#sendForReply(context, payload); return httpRequests as any[]; }, + create: async (args) => { + const payload = { + type: 'upsert_model_request', + model: { + name: '', + method: 'GET', + ...args, + id: '', + model: 'http_request', + }, + } as InternalEventPayload; + const response = await this.#sendForReply(context, payload); + return response.model as HttpRequest; + }, + update: async (args) => { + const payload = { + type: 'upsert_model_request', + model: { + model: 'http_request', + ...args, + }, + } as InternalEventPayload; + const response = await this.#sendForReply(context, payload); + return response.model as HttpRequest; + }, + delete: async (args) => { + const payload = { + type: 'delete_model_request', + model: 'http_request', + id: args.id, + } as InternalEventPayload; + const response = await this.#sendForReply(context, payload); + return response.model as HttpRequest; + }, }, folder: { list: async () => { @@ -768,6 +806,29 @@ export class PluginInstance { this.#sendPayload(context, { type: 'reload_response', silent: true }, null); }, }, + workspace: { + list: async () => { + const payload = { + type: 'list_workspaces_request' + } as InternalEventPayload; + const response = await this.#sendForReply(context, payload); + return response.workspaces.map((w) => ({ + id: w.id, + name: w.name, + // Hide label from plugin authors, but keep it for internal routing + _label: (w as any).label as string, + })); + }, + withContext: (workspaceHandle: { id: string; name: string; _label?: string }) => { + // Create a new context with the workspace's window label + const newContext: PluginContext = { + ...context, + label: workspaceHandle._label || null, + workspaceId: workspaceHandle.id, + }; + return this.#newCtx(newContext); + }, + }, }; } } diff --git a/packages/plugin-runtime/tests/common.test.ts b/packages/plugin-runtime/tests/common.test.ts index 0b371cbb..de128a9a 100644 --- a/packages/plugin-runtime/tests/common.test.ts +++ b/packages/plugin-runtime/tests/common.test.ts @@ -1,7 +1,8 @@ +import { applyFormInputDefaults } from '@yaakapp-internal/lib/templateFunction'; import { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins'; import { Context, DynamicTemplateFunctionArg } from '@yaakapp/api'; import { describe, expect, test } from 'vitest'; -import { applyDynamicFormInput, applyFormInputDefaults } from '../src/common'; +import { applyDynamicFormInput } from '../src/common'; describe('applyFormInputDefaults', () => { test('Works with top-level select', () => { diff --git a/plugins-external/.gitignore b/plugins-external/.gitignore new file mode 100644 index 00000000..5c644e17 --- /dev/null +++ b/plugins-external/.gitignore @@ -0,0 +1 @@ +*/build diff --git a/plugins-external/faker/README.md b/plugins-external/faker/README.md new file mode 100644 index 00000000..c7baaf82 --- /dev/null +++ b/plugins-external/faker/README.md @@ -0,0 +1,76 @@ +# Yaak Faker Plugin + +This is a template function that generates realistic fake data +for testing and development using [FakerJS](https://fakerjs.dev). + +![CleanShot 2024-09-19 at 13 56 33@2x](https://github.com/user-attachments/assets/2f935110-4af2-4236-a50d-18db5454176d) + +## Example JSON Body + +Here's an example JSON body that uses fake data: + +```json +{ + "id": "${[ faker.string.uuid() ]}", + "name": "${[ faker.person.fullName() ]}", + "email": "${[ faker.internet.email() ]}", + "phone": "${[ faker.phone.number() ]}", + "address": { + "street": "${[ faker.location.streetAddress() ]}", + "city": "${[ faker.location.city() ]}", + "country": "${[ faker.location.country() ]}", + "zipCode": "${[ faker.location.zipCode() ]}" + }, + "company": "${[ faker.company.name() ]}", + "website": "${[ faker.internet.url() ]}" +} +``` + +This will generate a random JSON body on every request: + +```json +{ + "id": "589f0aec-7310-4bf2-81c4-0b1bb7f1c3c1", + "name": "Lucy Gottlieb-Weissnat", + "email": "Destiny_Herzog@gmail.com", + "phone": "411.805.2871 x699", + "address": { + "street": "846 Christ Mills", + "city": "Spencerfurt", + "country": "United Kingdom", + "zipCode": "20354" + }, + "company": "Emard, Kohler and Rutherford", + "website": "https://watery-detective.org" +} +``` + +## Available Categories + +The plugin provides access to all FakerJS modules and their methods: + +| Category | Description | Example Methods | +|------------|---------------------------|--------------------------------------------| +| `airline` | Airline-related data | `aircraftType`, `airline`, `airplane` | +| `animal` | Animal names and types | `bear`, `bird`, `cat`, `dog`, `fish` | +| `color` | Colors in various formats | `human`, `rgb`, `hex`, `hsl` | +| `commerce` | E-commerce data | `department`, `product`, `price` | +| `company` | Company information | `name`, `catchPhrase`, `bs` | +| `database` | Database-related data | `column`, `type`, `collation` | +| `date` | Date and time values | `recent`, `future`, `past`, `between` | +| `finance` | Financial data | `account`, `amount`, `currency` | +| `git` | Git-related data | `branch`, `commitEntry`, `commitSha` | +| `hacker` | Tech/hacker terminology | `abbreviation`, `noun`, `phrase` | +| `image` | Image URLs and data | `avatar`, `url`, `dataUri` | +| `internet` | Internet-related data | `email`, `url`, `ip`, `userAgent` | +| `location` | Geographic data | `city`, `country`, `latitude`, `longitude` | +| `lorem` | Lorem ipsum text | `word`, `sentence`, `paragraph` | +| `person` | Personal information | `firstName`, `lastName`, `fullName` | +| `music` | Music-related data | `genre`, `songName`, `artist` | +| `number` | Numeric data | `int`, `float`, `binary`, `hex` | +| `phone` | Phone numbers | `number`, `imei` | +| `science` | Scientific data | `chemicalElement`, `unit` | +| `string` | String utilities | `uuid`, `alpha`, `alphanumeric` | +| `system` | System-related data | `fileName`, `mimeType`, `fileExt` | +| `vehicle` | Vehicle information | `vehicle`, `manufacturer`, `model` | +| `word` | Word generation | `adjective`, `adverb`, `conjunction` | diff --git a/plugins-external/faker/package.json b/plugins-external/faker/package.json new file mode 100755 index 00000000..396b4b82 --- /dev/null +++ b/plugins-external/faker/package.json @@ -0,0 +1,23 @@ +{ + "name": "@yaak/faker", + "private": true, + "version": "0.1.0", + "displayName": "Faker", + "description": "Template functions for generating fake data using FakerJS", + "repository": { + "type": "git", + "url": "https://github.com/mountain-loop/yaak.git", + "directory": "plugins-external/faker" + }, + "scripts": { + "build": "yaakcli build", + "dev": "yaakcli dev" + }, + "dependencies": { + "@faker-js/faker": "^10.1.0" + }, + "devDependencies": { + "@types/node": "^25.0.3", + "typescript": "^5.9.3" + } +} diff --git a/plugins-external/faker/src/index.ts b/plugins-external/faker/src/index.ts new file mode 100755 index 00000000..21de7d94 --- /dev/null +++ b/plugins-external/faker/src/index.ts @@ -0,0 +1,106 @@ +import { faker } from '@faker-js/faker'; +import type { PluginDefinition, TemplateFunctionArg } from '@yaakapp/api'; + +const modules = [ + 'airline', + 'animal', + 'color', + 'commerce', + 'company', + 'database', + 'date', + 'finance', + 'git', + 'hacker', + 'image', + 'internet', + 'location', + 'lorem', + 'person', + 'music', + 'number', + 'phone', + 'science', + 'string', + 'system', + 'vehicle', + 'word', +]; + +function normalizeResult(result: unknown): string { + if (typeof result === 'string') return result; + return JSON.stringify(result); +} + +// Whatever Yaak’s arg type shape is – rough example +function args(modName: string, fnName: string): TemplateFunctionArg[] { + return [ + { + type: 'banner', + color: 'info', + inputs: [ + { + type: 'markdown', + content: `Need help? View documentation for [\`${modName}.${fnName}(…)\`](https://fakerjs.dev/api/${encodeURIComponent(modName)}.html#${encodeURIComponent(fnName)})`, + }, + ], + }, + { + name: 'options', + label: 'Arguments', + type: 'editor', + language: 'json', + optional: true, + placeholder: 'e.g. { "min": 1, "max": 10 } or 10 or ["en","US"]', + }, + ]; +} + +export const plugin: PluginDefinition = { + templateFunctions: modules.flatMap((modName) => { + // @ts-expect-error - Dynamic access to faker modules + const mod = faker[modName]; + return Object.keys(mod) + .filter((n) => n !== 'faker') + .map((fnName) => ({ + name: ['faker', modName, fnName].join('.'), + args: args(modName, fnName), + async onRender(_ctx, args) { + const fn = mod[fnName] as (...a: unknown[]) => unknown; + const options = args.values.options; + + // No options supplied + if (options == null || options === '') { + return normalizeResult(fn()); + } + + // Try JSON first + let parsed: unknown = options; + if (typeof options === 'string') { + try { + parsed = JSON.parse(options); + } catch { + // Not valid JSON – maybe just a scalar + const n = Number(options); + if (!Number.isNaN(n)) { + parsed = n; + } else { + parsed = options; + } + } + } + + let result: unknown; + if (Array.isArray(parsed)) { + // Treat as positional arguments + result = fn(...parsed); + } else { + // Treat as a single argument (option object or scalar) + result = fn(parsed); + } + + return normalizeResult(result); + }, + })); + }), +}; diff --git a/plugins-external/faker/tsconfig.json b/plugins-external/faker/tsconfig.json new file mode 100755 index 00000000..4082f16a --- /dev/null +++ b/plugins-external/faker/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins-external/mcp-server/README.md b/plugins-external/mcp-server/README.md new file mode 100644 index 00000000..df53a7a4 --- /dev/null +++ b/plugins-external/mcp-server/README.md @@ -0,0 +1,54 @@ +# Yaak MCP Server Plugin + +A Yaak plugin that exposes Yaak's functionality via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/), allowing AI assistants and other tools to interact with Yaak programmatically. + +## Features + +This plugin starts an MCP server on `http://127.0.0.1:64343/mcp` that provides tools for: + +### HTTP Requests +- `list_http_requests` - List all HTTP requests in a workspace +- `get_http_request` - Get details of a specific HTTP request +- `send_http_request` - Send an HTTP request and get the response +- `create_http_request` - Create a new HTTP request +- `update_http_request` - Update an existing HTTP request +- `delete_http_request` - Delete an HTTP request + +### Folders +- `list_folders` - List all folders in a workspace + +### Workspaces +- `list_workspaces` - List all open workspaces in Yaak + +### Clipboard +- `copy_to_clipboard` - Copy text to the system clipboard + +### Window +- `get_workspace_id` - Get the current workspace ID +- `get_environment_id` - Get the current environment ID + +### Toast Notifications +- `show_toast` - Show a toast notification in Yaak + +## Usage + +Once the plugin is installed and Yaak is running, the MCP server will be available at: + +``` +http://127.0.0.1:64343/mcp +``` + +Configure your MCP client to connect to this endpoint to start interacting with Yaak. + +## Development + +```bash +# Install dependencies +npm install + +# Build the plugin +npm run build + +# Development mode with auto-rebuild +npm run dev +``` diff --git a/plugins-external/mcp-server/package.json b/plugins-external/mcp-server/package.json new file mode 100644 index 00000000..d582b6e4 --- /dev/null +++ b/plugins-external/mcp-server/package.json @@ -0,0 +1,28 @@ +{ + "name": "@yaak/mcp-server", + "private": true, + "version": "0.1.0", + "displayName": "MCP Server", + "description": "Expose Yaak functionality via Model Context Protocol", + "minYaakVersion": "2025.10.0-beta.6", + "repository": { + "type": "git", + "url": "https://github.com/mountain-loop/yaak.git", + "directory": "plugins-external/mcp-server" + }, + "scripts": { + "build": "yaakcli build", + "dev": "yaakcli dev" + }, + "dependencies": { + "@hono/mcp": "^0.2.3", + "@hono/node-server": "^1.19.7", + "@modelcontextprotocol/sdk": "^1.25.1", + "hono": "^4.11.3", + "zod": "^3.25.76" + }, + "devDependencies": { + "@types/node": "^25.0.3", + "typescript": "^5.9.3" + } +} diff --git a/plugins-external/mcp-server/src/index.ts b/plugins-external/mcp-server/src/index.ts new file mode 100644 index 00000000..dc343d29 --- /dev/null +++ b/plugins-external/mcp-server/src/index.ts @@ -0,0 +1,25 @@ +import type { Context, PluginDefinition } from '@yaakapp/api'; +import { createMcpServer } from './server.js'; + +const serverPort = 64343; + +let mcpServer: Awaited> | null = null; + +export const plugin: PluginDefinition = { + async init(ctx: Context) { + // Start the server after waiting, so there's an active window open to do things + // like show the startup toast. + setTimeout(() => { + mcpServer = createMcpServer({ yaak: ctx }, serverPort); + }, 5000); + }, + + async dispose() { + console.log('Disposing MCP Server plugin'); + + if (mcpServer) { + await mcpServer.close(); + mcpServer = null; + } + }, +}; diff --git a/plugins-external/mcp-server/src/server.ts b/plugins-external/mcp-server/src/server.ts new file mode 100644 index 00000000..7d75de19 --- /dev/null +++ b/plugins-external/mcp-server/src/server.ts @@ -0,0 +1,58 @@ +import { serve } from '@hono/node-server'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js'; +import { Hono } from 'hono'; +import { registerFolderTools } from './tools/folder.js'; +import { registerHttpRequestTools } from './tools/httpRequest.js'; +import { registerToastTools } from './tools/toast.js'; +import { registerWindowTools } from './tools/window.js'; +import { registerWorkspaceTools } from './tools/workspace.js'; +import type { McpServerContext } from './types.js'; + +export function createMcpServer(ctx: McpServerContext, port: number) { + const server = new McpServer({ + name: 'yaak-mcp-server', + version: '0.1.0', + }); + + // Register all tools + registerToastTools(server, ctx); + registerHttpRequestTools(server, ctx); + registerFolderTools(server, ctx); + registerWindowTools(server, ctx); + registerWorkspaceTools(server, ctx); + + // Create a stateless transport + const transport = new WebStandardStreamableHTTPServerTransport(); + + // Create Hono app + const app = new Hono(); + + // MCP endpoint - reuse the same transport for all requests + app.all('/mcp', (c) => transport.handleRequest(c.req.raw)); + + // Connect server to transport + server.connect(transport).then(() => { + console.log(`MCP Server running at http://127.0.0.1:${port}/mcp`); + ctx.yaak.toast.show({ + message: `MCP Server running on port ${port}`, + icon: 'check_circle', + color: 'success', + }); + }); + + // Start the HTTP server + const honoServer = serve({ + fetch: app.fetch, + port, + hostname: '127.0.0.1', + }); + + return { + server, + close: async () => { + honoServer.close(); + await server.close(); + }, + }; +} diff --git a/plugins-external/mcp-server/src/tools/folder.ts b/plugins-external/mcp-server/src/tools/folder.ts new file mode 100644 index 00000000..0a6cc533 --- /dev/null +++ b/plugins-external/mcp-server/src/tools/folder.ts @@ -0,0 +1,33 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod/v4'; +import type { McpServerContext } from '../types.js'; +import { getWorkspaceContext } from './helpers.js'; + +export function registerFolderTools(server: McpServer, ctx: McpServerContext) { + server.registerTool( + 'list_folders', + { + title: 'List Folders', + description: 'List all folders in a workspace', + inputSchema: z.object({ + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + }), + }, + async ({ workspaceId }) => { + const workspaceCtx = await getWorkspaceContext(ctx, workspaceId); + const folders = await workspaceCtx.yaak.folder.list(); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify(folders, null, 2), + }, + ], + }; + }, + ); +} diff --git a/plugins-external/mcp-server/src/tools/helpers.ts b/plugins-external/mcp-server/src/tools/helpers.ts new file mode 100644 index 00000000..05089be1 --- /dev/null +++ b/plugins-external/mcp-server/src/tools/helpers.ts @@ -0,0 +1,32 @@ +import type { McpServerContext } from '../types.js'; + +export async function getWorkspaceContext( + ctx: McpServerContext, + workspaceId?: string, +): Promise { + const workspaces = await ctx.yaak.workspace.list(); + + if (!workspaceId && workspaces.length > 1) { + const workspaceList = workspaces.map((w, i) => `${i + 1}. ${w.name} (ID: ${w.id})`).join('\n'); + throw new Error( + `Multiple workspaces are open. Please specify which workspace to use.\n\n` + + `Currently open workspaces:\n${workspaceList}\n\n` + + `You can use the list_workspaces tool to get workspace IDs, then use other tools ` + + `with the workspace context. For example, ask the user which workspace they want ` + + `to work with by presenting them with the numbered list above.`, + ); + } + + const workspace = workspaceId ? workspaces.find((w) => w.id === workspaceId) : workspaces[0]; + if (!workspace) { + const workspaceList = workspaces.map((w) => `- ${w.name} (ID: ${w.id})`).join('\n'); + throw new Error( + `Workspace with ID "${workspaceId}" not found.\n\n` + + `Available workspaces:\n${workspaceList}`, + ); + } + + return { + yaak: ctx.yaak.workspace.withContext(workspace), + }; +} diff --git a/plugins-external/mcp-server/src/tools/httpRequest.ts b/plugins-external/mcp-server/src/tools/httpRequest.ts new file mode 100644 index 00000000..7cfc0927 --- /dev/null +++ b/plugins-external/mcp-server/src/tools/httpRequest.ts @@ -0,0 +1,219 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod/v4'; +import type { McpServerContext } from '../types.js'; +import { getWorkspaceContext } from './helpers.js'; + +export function registerHttpRequestTools(server: McpServer, ctx: McpServerContext) { + server.registerTool( + 'list_http_requests', + { + title: 'List HTTP Requests', + description: 'List all HTTP requests in a workspace', + inputSchema: z.object({ + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + }), + }, + async ({ workspaceId }) => { + const workspaceCtx = await getWorkspaceContext(ctx, workspaceId); + const requests = await workspaceCtx.yaak.httpRequest.list(); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify(requests, null, 2), + }, + ], + }; + }, + ); + + server.registerTool( + 'get_http_request', + { + title: 'Get HTTP Request', + description: 'Get details of a specific HTTP request by ID', + inputSchema: z.object({ + id: z.string().describe('The HTTP request ID'), + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + }), + }, + async ({ id, workspaceId }) => { + const workspaceCtx = await getWorkspaceContext(ctx, workspaceId); + const request = await workspaceCtx.yaak.httpRequest.getById({ id }); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify(request, null, 2), + }, + ], + }; + }, + ); + + server.registerTool( + 'send_http_request', + { + title: 'Send HTTP Request', + description: 'Send an HTTP request and get the response', + inputSchema: z.object({ + id: z.string().describe('The HTTP request ID to send'), + environmentId: z.string().optional().describe('Optional environment ID to use'), + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + }), + }, + async ({ id, workspaceId }) => { + const workspaceCtx = await getWorkspaceContext(ctx, workspaceId); + const httpRequest = await workspaceCtx.yaak.httpRequest.getById({ id }); + if (httpRequest == null) { + throw new Error(`HTTP request with ID ${id} not found`); + } + + const response = await workspaceCtx.yaak.httpRequest.send({ httpRequest }); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify(response, null, 2), + }, + ], + }; + }, + ); + + server.registerTool( + 'create_http_request', + { + title: 'Create HTTP Request', + description: 'Create a new HTTP request', + inputSchema: z.object({ + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + name: z + .string() + .optional() + .describe('Request name (empty string to auto-generate from URL)'), + url: z.string().describe('Request URL'), + method: z.string().optional().describe('HTTP method (defaults to GET)'), + folderId: z.string().optional().describe('Parent folder ID'), + description: z.string().optional().describe('Request description'), + headers: z + .array( + z.object({ + name: z.string(), + value: z.string(), + enabled: z.boolean().default(true), + }), + ) + .optional() + .describe('Request headers'), + urlParameters: z + .array( + z.object({ + name: z.string(), + value: z.string(), + enabled: z.boolean().default(true), + }), + ) + .optional() + .describe('URL query parameters'), + }), + }, + async ({ workspaceId: ogWorkspaceId, ...args }) => { + const workspaceCtx = await getWorkspaceContext(ctx, ogWorkspaceId); + const workspaceId = await workspaceCtx.yaak.window.workspaceId(); + if (!workspaceId) { + throw new Error('No workspace is open'); + } + + const httpRequest = await workspaceCtx.yaak.httpRequest.create({ + workspaceId: workspaceId, + ...args, + }); + + return { + content: [{ type: 'text' as const, text: JSON.stringify(httpRequest, null, 2) }], + }; + }, + ); + + server.registerTool( + 'update_http_request', + { + title: 'Update HTTP Request', + description: 'Update an existing HTTP request', + inputSchema: z.object({ + id: z.string().describe('HTTP request ID to update'), + workspaceId: z + .string() + .optional() + .describe('Workspace ID (required if multiple workspaces are open)'), + name: z.string().optional().describe('Request name'), + url: z.string().optional().describe('Request URL'), + method: z.string().optional().describe('HTTP method'), + folderId: z.string().optional().describe('Parent folder ID'), + description: z.string().optional().describe('Request description'), + headers: z + .array( + z.object({ + name: z.string(), + value: z.string(), + enabled: z.boolean().default(true), + }), + ) + .optional() + .describe('Request headers'), + urlParameters: z + .array( + z.object({ + name: z.string(), + value: z.string(), + enabled: z.boolean().default(true), + }), + ) + .optional() + .describe('URL query parameters'), + }), + }, + async ({ id, workspaceId, ...updates }) => { + const workspaceCtx = await getWorkspaceContext(ctx, workspaceId); + const httpRequest = await workspaceCtx.yaak.httpRequest.update({ id, ...updates }); + return { + content: [{ type: 'text' as const, text: JSON.stringify(httpRequest, null, 2) }], + }; + }, + ); + + server.registerTool( + 'delete_http_request', + { + title: 'Delete HTTP Request', + description: 'Delete an HTTP request by ID', + inputSchema: z.object({ + id: z.string().describe('HTTP request ID to delete'), + }), + }, + async ({ id }) => { + const httpRequest = await ctx.yaak.httpRequest.delete({ id }); + return { + content: [ + { type: 'text' as const, text: `Deleted: ${httpRequest.name} (${httpRequest.id})` }, + ], + }; + }, + ); +} diff --git a/plugins-external/mcp-server/src/tools/toast.ts b/plugins-external/mcp-server/src/tools/toast.ts new file mode 100644 index 00000000..e90a3c63 --- /dev/null +++ b/plugins-external/mcp-server/src/tools/toast.ts @@ -0,0 +1,59 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import type { Color, Icon } from '@yaakapp/api'; +import * as z from 'zod/v4'; +import type { McpServerContext } from '../types.js'; + +const ICON_VALUES = [ + 'alert_triangle', + 'check', + 'check_circle', + 'chevron_down', + 'copy', + 'info', + 'pin', + 'search', + 'trash', +] as const satisfies readonly Icon[]; + +const COLOR_VALUES = [ + 'primary', + 'secondary', + 'info', + 'success', + 'notice', + 'warning', + 'danger', +] as const satisfies readonly Color[]; + +export function registerToastTools(server: McpServer, ctx: McpServerContext) { + server.registerTool( + 'show_toast', + { + title: 'Show Toast', + description: 'Show a toast notification in Yaak', + inputSchema: z.object({ + message: z.string().describe('The message to display'), + icon: z.enum(ICON_VALUES).optional().describe('Icon name'), + color: z.enum(COLOR_VALUES).optional().describe('Toast color'), + timeout: z.number().optional().describe('Timeout in milliseconds'), + }), + }, + async ({ message, icon, color, timeout }) => { + await ctx.yaak.toast.show({ + message, + icon, + color, + timeout, + }); + + return { + content: [ + { + type: 'text' as const, + text: `✓ Toast shown: "${message}"`, + }, + ], + }; + }, + ); +} diff --git a/plugins-external/mcp-server/src/tools/window.ts b/plugins-external/mcp-server/src/tools/window.ts new file mode 100644 index 00000000..a08ae9db --- /dev/null +++ b/plugins-external/mcp-server/src/tools/window.ts @@ -0,0 +1,50 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod/v4'; +import type { McpServerContext } from '../types.js'; +import { getWorkspaceContext } from './helpers.js'; + +export function registerWindowTools(server: McpServer, ctx: McpServerContext) { + server.registerTool( + 'get_workspace_id', + { + title: 'Get Workspace ID', + description: 'Get the current workspace ID', + inputSchema: z.object({}), + }, + async () => { + const workspaceCtx = await getWorkspaceContext(ctx); + const workspaceId = await workspaceCtx.yaak.window.workspaceId(); + + return { + content: [ + { + type: 'text' as const, + text: workspaceId || 'No workspace open', + }, + ], + }; + }, + ); + + server.registerTool( + 'get_environment_id', + { + title: 'Get Environment ID', + description: 'Get the current environment ID', + inputSchema: z.object({}), + }, + async () => { + const workspaceCtx = await getWorkspaceContext(ctx); + const environmentId = await workspaceCtx.yaak.window.environmentId(); + + return { + content: [ + { + type: 'text' as const, + text: environmentId || 'No environment selected', + }, + ], + }; + }, + ); +} diff --git a/plugins-external/mcp-server/src/tools/workspace.ts b/plugins-external/mcp-server/src/tools/workspace.ts new file mode 100644 index 00000000..480afd60 --- /dev/null +++ b/plugins-external/mcp-server/src/tools/workspace.ts @@ -0,0 +1,26 @@ +import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import * as z from 'zod/v4'; +import type { McpServerContext } from '../types.js'; + +export function registerWorkspaceTools(server: McpServer, ctx: McpServerContext) { + server.registerTool( + 'list_workspaces', + { + title: 'List Workspaces', + description: 'List all open workspaces in Yaak', + inputSchema: z.object({}), + }, + async () => { + const workspaces = await ctx.yaak.workspace.list(); + + return { + content: [ + { + type: 'text' as const, + text: JSON.stringify(workspaces, null, 2), + }, + ], + }; + }, + ); +} diff --git a/plugins-external/mcp-server/src/types.ts b/plugins-external/mcp-server/src/types.ts new file mode 100644 index 00000000..fa57eb4f --- /dev/null +++ b/plugins-external/mcp-server/src/types.ts @@ -0,0 +1,5 @@ +import type { Context } from '@yaakapp/api'; + +export interface McpServerContext { + yaak: Context; +} diff --git a/plugins-external/mcp-server/tsconfig.json b/plugins-external/mcp-server/tsconfig.json new file mode 100644 index 00000000..4082f16a --- /dev/null +++ b/plugins-external/mcp-server/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/importer-curl/src/index.ts b/plugins/importer-curl/src/index.ts index 5e4b6d98..f8b0606e 100644 --- a/plugins/importer-curl/src/index.ts +++ b/plugins/importer-curl/src/index.ts @@ -198,7 +198,8 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) { // - Single dash followed by a letter: -X, -H, -d // - Double dash followed by a letter: --data-raw, --header // This prevents mistaking data that starts with dashes (like multipart boundaries ------) as flags - const nextEntryIsFlag = typeof nextEntry === 'string' && + const nextEntryIsFlag = + typeof nextEntry === 'string' && (nextEntry.match(/^-[a-zA-Z]/) || nextEntry.match(/^--[a-zA-Z]/)); if (isSingleDash && name.length > 1) { // Handle squished arguments like -XPOST @@ -328,7 +329,9 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) { ]; // Check if this is multipart form data in --data-raw (Chrome DevTools format) - let multipartFormDataFromRaw: { name: string; value?: string; file?: string; enabled: boolean }[] | null = null; + let multipartFormDataFromRaw: + | { name: string; value?: string; file?: string; enabled: boolean }[] + | null = null; if (mimeType === 'multipart/form-data' && boundary && rawDataValues.length > 0) { const rawBody = rawDataValues.join(''); multipartFormDataFromRaw = parseMultipartFormData(rawBody, boundary); diff --git a/scripts/vendor-plugins.cjs b/scripts/vendor-plugins.cjs index 0e099165..c461a54f 100644 --- a/scripts/vendor-plugins.cjs +++ b/scripts/vendor-plugins.cjs @@ -1,13 +1,28 @@ -const { readdirSync, cpSync } = require('node:fs'); +const { readdirSync, cpSync, existsSync } = require('node:fs'); const path = require('node:path'); const pluginsDir = path.join(__dirname, '..', 'plugins'); +const externalPluginsDir = path.join(__dirname, '..', 'plugins-external'); + +// Get list of external (non-bundled) plugins +const externalPlugins = new Set(); +if (existsSync(externalPluginsDir)) { + for (const name of readdirSync(externalPluginsDir)) { + if (!name.startsWith('.')) { + externalPlugins.add(name); + } + } +} console.log('Copying Yaak plugins to', pluginsDir); for (const name of readdirSync(pluginsDir)) { const dir = path.join(pluginsDir, name); if (name.startsWith('.')) continue; + if (externalPlugins.has(name)) { + console.log(`Skipping ${name} (external plugin)`); + continue; + } const destDir = path.join(__dirname, '../src-tauri/vendored/plugins/', name); console.log(`Copying ${name} to ${destDir}`); cpSync(path.join(dir, 'package.json'), path.join(destDir, 'package.json')); diff --git a/src-tauri/src/http_request.rs b/src-tauri/src/http_request.rs index 860d10fd..b8f69993 100644 --- a/src-tauri/src/http_request.rs +++ b/src-tauri/src/http_request.rs @@ -22,8 +22,8 @@ use yaak_http::types::{ }; use yaak_models::blob_manager::{BlobManagerExt, BodyChunk}; use yaak_models::models::{ - Cookie, CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseEvent, - HttpResponseHeader, HttpResponseState, ProxySetting, ProxySettingAuth, + CookieJar, Environment, HttpRequest, HttpResponse, HttpResponseEvent, HttpResponseHeader, + HttpResponseState, ProxySetting, ProxySettingAuth, }; use yaak_models::query_manager::QueryManagerExt; use yaak_models::util::UpdateSource; diff --git a/src-tauri/src/plugin_events.rs b/src-tauri/src/plugin_events.rs index cb730dab..b167b014 100644 --- a/src-tauri/src/plugin_events.rs +++ b/src-tauri/src/plugin_events.rs @@ -13,7 +13,7 @@ use tauri::{AppHandle, Emitter, Manager, Runtime}; use tauri_plugin_clipboard_manager::ClipboardExt; use yaak_common::window::WorkspaceWindowTrait; use yaak_models::blob_manager::BlobManagerExt; -use yaak_models::models::{HttpResponse, Plugin}; +use yaak_models::models::{AnyModel, HttpResponse, Plugin}; use yaak_models::queries::any_request::AnyRequest; use yaak_models::query_manager::QueryManagerExt; use yaak_models::util::UpdateSource; @@ -21,10 +21,10 @@ use yaak_plugins::error::Error::PluginErr; use yaak_plugins::events::{ Color, DeleteKeyValueResponse, EmptyPayload, ErrorResponse, FindHttpResponsesResponse, GetCookieValueResponse, GetHttpRequestByIdResponse, GetKeyValueResponse, Icon, InternalEvent, - InternalEventPayload, ListCookieNamesResponse, ListHttpRequestsResponse, + InternalEventPayload, ListCookieNamesResponse, ListHttpRequestsResponse, ListWorkspacesResponse, RenderGrpcRequestResponse, RenderHttpRequestResponse, SendHttpRequestResponse, SetKeyValueResponse, ShowToastRequest, TemplateRenderResponse, WindowInfoResponse, - WindowNavigateEvent, + WindowNavigateEvent, WorkspaceInfo, }; use yaak_plugins::plugin_handle::PluginHandle; use yaak_plugins::template_callback::PluginTemplateCallback; @@ -87,6 +87,70 @@ pub(crate) async fn handle_plugin_event( yaak_plugins::events::ListFoldersResponse { folders }, ))) } + InternalEventPayload::UpsertModelRequest(req) => { + use AnyModel::*; + let model = match &req.model { + HttpRequest(m) => { + HttpRequest(app_handle.db().upsert_http_request(m, &UpdateSource::Plugin)?) + } + GrpcRequest(m) => { + GrpcRequest(app_handle.db().upsert_grpc_request(m, &UpdateSource::Plugin)?) + } + WebsocketRequest(m) => WebsocketRequest( + app_handle.db().upsert_websocket_request(m, &UpdateSource::Plugin)?, + ), + Folder(m) => Folder(app_handle.db().upsert_folder(m, &UpdateSource::Plugin)?), + Environment(m) => { + Environment(app_handle.db().upsert_environment(m, &UpdateSource::Plugin)?) + } + Workspace(m) => { + Workspace(app_handle.db().upsert_workspace(m, &UpdateSource::Plugin)?) + } + _ => { + return Err(PluginErr("Upsert not supported for this model type".into()).into()) + } + }; + + Ok(Some(InternalEventPayload::UpsertModelResponse( + yaak_plugins::events::UpsertModelResponse { model }, + ))) + } + InternalEventPayload::DeleteModelRequest(req) => { + let model = match req.model.as_str() { + "http_request" => AnyModel::HttpRequest( + app_handle + .db() + .delete_http_request_by_id(&req.id, &UpdateSource::Plugin)?, + ), + "grpc_request" => AnyModel::GrpcRequest( + app_handle + .db() + .delete_grpc_request_by_id(&req.id, &UpdateSource::Plugin)?, + ), + "websocket_request" => AnyModel::WebsocketRequest( + app_handle + .db() + .delete_websocket_request_by_id(&req.id, &UpdateSource::Plugin)?, + ), + "folder" => AnyModel::Folder( + app_handle + .db() + .delete_folder_by_id(&req.id, &UpdateSource::Plugin)?, + ), + "environment" => AnyModel::Environment( + app_handle + .db() + .delete_environment_by_id(&req.id, &UpdateSource::Plugin)?, + ), + _ => { + return Err(PluginErr("Delete not supported for this model type".into()).into()) + } + }; + + Ok(Some(InternalEventPayload::DeleteModelResponse( + yaak_plugins::events::DeleteModelResponse { model }, + ))) + } InternalEventPayload::GetHttpRequestByIdRequest(req) => { let http_request = app_handle.db().get_http_request(&req.id).ok(); Ok(Some(InternalEventPayload::GetHttpRequestByIdResponse(GetHttpRequestByIdResponse { @@ -382,6 +446,24 @@ pub(crate) async fn handle_plugin_event( }))) } + InternalEventPayload::ListWorkspacesRequest(_) => { + let mut workspaces = Vec::new(); + + for (_, window) in app_handle.webview_windows() { + if let Some(workspace) = workspace_from_window(&window) { + workspaces.push(WorkspaceInfo { + id: workspace.id.clone(), + name: workspace.name.clone(), + label: window.label().to_string(), + }); + } + } + + Ok(Some(InternalEventPayload::ListWorkspacesResponse(ListWorkspacesResponse { + workspaces, + }))) + } + _ => Ok(None), } } diff --git a/src-tauri/yaak-plugins/bindings/gen_events.ts b/src-tauri/yaak-plugins/bindings/gen_events.ts index 24a283e4..ee150d4d 100644 --- a/src-tauri/yaak-plugins/bindings/gen_events.ts +++ b/src-tauri/yaak-plugins/bindings/gen_events.ts @@ -1,5 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -import type { Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace } from "./gen_models"; +import type { AnyModel, Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace } from "./gen_models"; import type { JsonValue } from "./serde_json/JsonValue"; export type BootRequest = { dir: string, watch: boolean, }; @@ -62,6 +62,10 @@ export type DeleteKeyValueRequest = { key: string, }; export type DeleteKeyValueResponse = { deleted: boolean, }; +export type DeleteModelRequest = { model: string, id: string, }; + +export type DeleteModelResponse = { model: AnyModel, }; + export type EditorLanguage = "text" | "javascript" | "json" | "html" | "xml" | "graphql" | "markdown"; export type EmptyPayload = {}; @@ -411,7 +415,7 @@ export type ImportResponse = { resources: ImportResources, }; export type InternalEvent = { id: string, pluginRefId: string, pluginName: string, replyId: string | null, context: PluginContext, payload: InternalEventPayload, }; -export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } | { "type": "reload_response" } & ReloadResponse | { "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": "list_cookie_names_request" } & ListCookieNamesRequest | { "type": "list_cookie_names_response" } & ListCookieNamesResponse | { "type": "get_cookie_value_request" } & GetCookieValueRequest | { "type": "get_cookie_value_response" } & GetCookieValueResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_websocket_request_actions_request" } & EmptyPayload | { "type": "get_websocket_request_actions_response" } & GetWebsocketRequestActionsResponse | { "type": "call_websocket_request_action_request" } & CallWebsocketRequestActionRequest | { "type": "get_workspace_actions_request" } & EmptyPayload | { "type": "get_workspace_actions_response" } & GetWorkspaceActionsResponse | { "type": "call_workspace_action_request" } & CallWorkspaceActionRequest | { "type": "get_folder_actions_request" } & EmptyPayload | { "type": "get_folder_actions_response" } & GetFolderActionsResponse | { "type": "call_folder_action_request" } & CallFolderActionRequest | { "type": "get_grpc_request_actions_request" } & EmptyPayload | { "type": "get_grpc_request_actions_response" } & GetGrpcRequestActionsResponse | { "type": "call_grpc_request_action_request" } & CallGrpcRequestActionRequest | { "type": "get_template_function_summary_request" } & EmptyPayload | { "type": "get_template_function_summary_response" } & GetTemplateFunctionSummaryResponse | { "type": "get_template_function_config_request" } & GetTemplateFunctionConfigRequest | { "type": "get_template_function_config_response" } & GetTemplateFunctionConfigResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_summary_request" } & EmptyPayload | { "type": "get_http_authentication_summary_response" } & GetHttpAuthenticationSummaryResponse | { "type": "get_http_authentication_config_request" } & GetHttpAuthenticationConfigRequest | { "type": "get_http_authentication_config_response" } & GetHttpAuthenticationConfigResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "call_http_authentication_action_request" } & CallHttpAuthenticationActionRequest | { "type": "call_http_authentication_action_response" } & EmptyPayload | { "type": "copy_text_request" } & CopyTextRequest | { "type": "copy_text_response" } & EmptyPayload | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "render_grpc_request_request" } & RenderGrpcRequestRequest | { "type": "render_grpc_request_response" } & RenderGrpcRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "get_key_value_request" } & GetKeyValueRequest | { "type": "get_key_value_response" } & GetKeyValueResponse | { "type": "set_key_value_request" } & SetKeyValueRequest | { "type": "set_key_value_response" } & SetKeyValueResponse | { "type": "delete_key_value_request" } & DeleteKeyValueRequest | { "type": "delete_key_value_response" } & DeleteKeyValueResponse | { "type": "open_window_request" } & OpenWindowRequest | { "type": "window_navigate_event" } & WindowNavigateEvent | { "type": "window_close_event" } | { "type": "close_window_request" } & CloseWindowRequest | { "type": "show_toast_request" } & ShowToastRequest | { "type": "show_toast_response" } & EmptyPayload | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "window_info_request" } & WindowInfoRequest | { "type": "window_info_response" } & WindowInfoResponse | { "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": "list_http_requests_request" } & ListHttpRequestsRequest | { "type": "list_http_requests_response" } & ListHttpRequestsResponse | { "type": "list_folders_request" } & ListFoldersRequest | { "type": "list_folders_response" } & ListFoldersResponse | { "type": "get_themes_request" } & GetThemesRequest | { "type": "get_themes_response" } & GetThemesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; +export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } | { "type": "reload_response" } & ReloadResponse | { "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": "list_cookie_names_request" } & ListCookieNamesRequest | { "type": "list_cookie_names_response" } & ListCookieNamesResponse | { "type": "get_cookie_value_request" } & GetCookieValueRequest | { "type": "get_cookie_value_response" } & GetCookieValueResponse | { "type": "get_http_request_actions_request" } & EmptyPayload | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_websocket_request_actions_request" } & EmptyPayload | { "type": "get_websocket_request_actions_response" } & GetWebsocketRequestActionsResponse | { "type": "call_websocket_request_action_request" } & CallWebsocketRequestActionRequest | { "type": "get_workspace_actions_request" } & EmptyPayload | { "type": "get_workspace_actions_response" } & GetWorkspaceActionsResponse | { "type": "call_workspace_action_request" } & CallWorkspaceActionRequest | { "type": "get_folder_actions_request" } & EmptyPayload | { "type": "get_folder_actions_response" } & GetFolderActionsResponse | { "type": "call_folder_action_request" } & CallFolderActionRequest | { "type": "get_grpc_request_actions_request" } & EmptyPayload | { "type": "get_grpc_request_actions_response" } & GetGrpcRequestActionsResponse | { "type": "call_grpc_request_action_request" } & CallGrpcRequestActionRequest | { "type": "get_template_function_summary_request" } & EmptyPayload | { "type": "get_template_function_summary_response" } & GetTemplateFunctionSummaryResponse | { "type": "get_template_function_config_request" } & GetTemplateFunctionConfigRequest | { "type": "get_template_function_config_response" } & GetTemplateFunctionConfigResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "get_http_authentication_summary_request" } & EmptyPayload | { "type": "get_http_authentication_summary_response" } & GetHttpAuthenticationSummaryResponse | { "type": "get_http_authentication_config_request" } & GetHttpAuthenticationConfigRequest | { "type": "get_http_authentication_config_response" } & GetHttpAuthenticationConfigResponse | { "type": "call_http_authentication_request" } & CallHttpAuthenticationRequest | { "type": "call_http_authentication_response" } & CallHttpAuthenticationResponse | { "type": "call_http_authentication_action_request" } & CallHttpAuthenticationActionRequest | { "type": "call_http_authentication_action_response" } & EmptyPayload | { "type": "copy_text_request" } & CopyTextRequest | { "type": "copy_text_response" } & EmptyPayload | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "render_grpc_request_request" } & RenderGrpcRequestRequest | { "type": "render_grpc_request_response" } & RenderGrpcRequestResponse | { "type": "template_render_request" } & TemplateRenderRequest | { "type": "template_render_response" } & TemplateRenderResponse | { "type": "get_key_value_request" } & GetKeyValueRequest | { "type": "get_key_value_response" } & GetKeyValueResponse | { "type": "set_key_value_request" } & SetKeyValueRequest | { "type": "set_key_value_response" } & SetKeyValueResponse | { "type": "delete_key_value_request" } & DeleteKeyValueRequest | { "type": "delete_key_value_response" } & DeleteKeyValueResponse | { "type": "open_window_request" } & OpenWindowRequest | { "type": "window_navigate_event" } & WindowNavigateEvent | { "type": "window_close_event" } | { "type": "close_window_request" } & CloseWindowRequest | { "type": "show_toast_request" } & ShowToastRequest | { "type": "show_toast_response" } & EmptyPayload | { "type": "prompt_text_request" } & PromptTextRequest | { "type": "prompt_text_response" } & PromptTextResponse | { "type": "window_info_request" } & WindowInfoRequest | { "type": "window_info_response" } & WindowInfoResponse | { "type": "list_workspaces_request" } & ListWorkspacesRequest | { "type": "list_workspaces_response" } & ListWorkspacesResponse | { "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": "list_http_requests_request" } & ListHttpRequestsRequest | { "type": "list_http_requests_response" } & ListHttpRequestsResponse | { "type": "list_folders_request" } & ListFoldersRequest | { "type": "list_folders_response" } & ListFoldersResponse | { "type": "upsert_model_request" } & UpsertModelRequest | { "type": "upsert_model_response" } & UpsertModelResponse | { "type": "delete_model_request" } & DeleteModelRequest | { "type": "delete_model_response" } & DeleteModelResponse | { "type": "get_themes_request" } & GetThemesRequest | { "type": "get_themes_response" } & GetThemesResponse | { "type": "empty_response" } & EmptyPayload | { "type": "error_response" } & ErrorResponse; export type JsonPrimitive = string | number | boolean | null; @@ -427,6 +431,10 @@ export type ListHttpRequestsRequest = { folderId?: string, }; export type ListHttpRequestsResponse = { httpRequests: Array, }; +export type ListWorkspacesRequest = Record; + +export type ListWorkspacesResponse = { workspaces: Array, }; + export type OpenWindowRequest = { url: string, /** * Label for the window. If not provided, a random one will be generated. @@ -521,6 +529,10 @@ export type ThemeComponentColors = { surface?: string, surfaceHighlight?: string export type ThemeComponents = { dialog?: ThemeComponentColors, menu?: ThemeComponentColors, toast?: ThemeComponentColors, sidebar?: ThemeComponentColors, responsePane?: ThemeComponentColors, appHeader?: ThemeComponentColors, button?: ThemeComponentColors, banner?: ThemeComponentColors, templateTag?: ThemeComponentColors, urlBar?: ThemeComponentColors, editor?: ThemeComponentColors, input?: ThemeComponentColors, }; +export type UpsertModelRequest = { model: AnyModel, }; + +export type UpsertModelResponse = { model: AnyModel, }; + export type WebsocketRequestAction = { label: string, icon?: Icon, }; export type WindowInfoRequest = { label: string, }; @@ -532,3 +544,5 @@ export type WindowNavigateEvent = { url: string, }; export type WindowSize = { width: number, height: number, }; export type WorkspaceAction = { label: string, icon?: Icon, }; + +export type WorkspaceInfo = { id: string, name: string, }; diff --git a/src-tauri/yaak-plugins/bindings/gen_models.ts b/src-tauri/yaak-plugins/bindings/gen_models.ts index 454903fe..ba67aba3 100644 --- a/src-tauri/yaak-plugins/bindings/gen_models.ts +++ b/src-tauri/yaak-plugins/bindings/gen_models.ts @@ -1,11 +1,37 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +export type AnyModel = CookieJar | Environment | Folder | GraphQlIntrospection | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | HttpResponseEvent | KeyValue | Plugin | Settings | SyncState | WebsocketConnection | WebsocketEvent | WebsocketRequest | Workspace | WorkspaceMeta; + +export type ClientCertificate = { host: string, port: number | null, crtFile: string | null, keyFile: string | null, pfxFile: string | null, passphrase: string | null, enabled?: boolean, }; + +export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], }; + +export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty"; + +export type CookieExpires = { "AtUtc": string } | "SessionEnd"; + +export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array, name: string, }; + +export type EditorKeymap = "default" | "vim" | "vscode" | "emacs"; + +export type EncryptedKey = { encryptedKey: string, }; + export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, public: boolean, parentModel: string, parentId: string | null, variables: Array, color: string | null, sortPriority: number, }; export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, }; export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, description: string, headers: Array, name: string, sortPriority: number, }; +export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, }; + +export type GrpcConnection = { model: "grpc_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, method: string, service: string, status: number, state: GrpcConnectionState, trailers: { [key in string]?: string }, url: string, }; + +export type GrpcConnectionState = "initialized" | "connected" | "closed"; + +export type GrpcEvent = { model: "grpc_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, content: string, error: string | null, eventType: GrpcEventType, metadata: { [key in string]?: string }, status: number | null, }; + +export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end"; + export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record, description: string, message: string, metadata: Array, method: string | null, name: string, service: string | null, sortPriority: number, url: string, }; export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, body: Record, bodyType: string | null, description: string, headers: Array, method: string, name: string, sortPriority: number, url: string, urlParameters: Array, }; @@ -14,12 +40,43 @@ export type HttpRequestHeader = { enabled?: boolean, name: string, value: string export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, contentLengthCompressed: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array, remoteAddr: string | null, requestContentLength: number | null, requestHeaders: Array, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, }; +export type HttpResponseEvent = { model: "http_response_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, responseId: string, event: HttpResponseEventData, }; + +/** + * Serializable representation of HTTP response events for DB storage. + * This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support. + * The `From` impl is in yaak-http to avoid circular dependencies. + */ +export type HttpResponseEventData = { "type": "setting", name: string, value: string, } | { "type": "info", message: string, } | { "type": "redirect", url: string, status: number, behavior: string, } | { "type": "send_url", method: string, path: string, } | { "type": "receive_url", version: string, status: string, } | { "type": "header_up", name: string, value: string, } | { "type": "header_down", name: string, value: string, } | { "type": "chunk_sent", bytes: number, } | { "type": "chunk_received", bytes: number, }; + export type HttpResponseHeader = { name: string, value: string, }; export type HttpResponseState = "initialized" | "connected" | "closed"; export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id?: string, }; +export type KeyValue = { model: "key_value", id: string, createdAt: string, updatedAt: string, key: string, namespace: string, value: string, }; + +export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, }; + +export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" }; + +export type ProxySettingAuth = { user: string, password: string, }; + +export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, clientCertificates: Array, coloredMethods: boolean, editorFont: string | null, editorFontSize: number, editorKeymap: EditorKeymap, editorSoftWrap: boolean, hideWindowControls: boolean, useNativeTitlebar: boolean, interfaceFont: string | null, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, hideLicenseBadge: boolean, autoupdate: boolean, autoDownloadUpdates: boolean, checkNotifications: boolean, }; + +export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, }; + +export type WebsocketConnection = { model: "websocket_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, headers: Array, state: WebsocketConnectionState, status: number, url: string, }; + +export type WebsocketConnectionState = "initialized" | "connected" | "closing" | "closed"; + +export type WebsocketEvent = { model: "websocket_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, isServer: boolean, message: Array, messageType: WebsocketEventType, }; + +export type WebsocketEventType = "binary" | "close" | "frame" | "open" | "ping" | "pong" | "text"; + export type WebsocketRequest = { model: "websocket_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record, authenticationType: string | null, description: string, headers: Array, message: string, name: string, sortPriority: number, url: string, urlParameters: Array, }; export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, authentication: Record, authenticationType: string | null, description: string, headers: Array, name: string, encryptionKeyChallenge: string | null, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, }; + +export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, }; diff --git a/src-tauri/yaak-plugins/src/events.rs b/src-tauri/yaak-plugins/src/events.rs index bf7f9702..c53e221d 100644 --- a/src-tauri/yaak-plugins/src/events.rs +++ b/src-tauri/yaak-plugins/src/events.rs @@ -4,7 +4,8 @@ use tauri::{Runtime, WebviewWindow}; use ts_rs::TS; use yaak_common::window::WorkspaceWindowTrait; use yaak_models::models::{ - Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, Workspace, + AnyModel, Environment, Folder, GrpcRequest, HttpRequest, HttpResponse, WebsocketRequest, + Workspace, }; use yaak_models::util::generate_prefixed_id; @@ -161,6 +162,9 @@ pub enum InternalEventPayload { WindowInfoRequest(WindowInfoRequest), WindowInfoResponse(WindowInfoResponse), + ListWorkspacesRequest(ListWorkspacesRequest), + ListWorkspacesResponse(ListWorkspacesResponse), + GetHttpRequestByIdRequest(GetHttpRequestByIdRequest), GetHttpRequestByIdResponse(GetHttpRequestByIdResponse), @@ -171,6 +175,12 @@ pub enum InternalEventPayload { ListFoldersRequest(ListFoldersRequest), ListFoldersResponse(ListFoldersResponse), + UpsertModelRequest(UpsertModelRequest), + UpsertModelResponse(UpsertModelResponse), + + DeleteModelRequest(DeleteModelRequest), + DeleteModelResponse(DeleteModelResponse), + GetThemesRequest(GetThemesRequest), GetThemesResponse(GetThemesResponse), @@ -573,6 +583,28 @@ pub struct WindowInfoResponse { pub label: String, } +#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] +#[serde(default, rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct ListWorkspacesRequest {} + +#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] +#[serde(default, rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct ListWorkspacesResponse { + pub workspaces: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct WorkspaceInfo { + pub id: String, + pub name: String, + #[ts(skip)] + pub label: String, +} + #[derive(Debug, Clone, Serialize, Deserialize, TS)] #[serde(rename_all = "snake_case")] #[ts(export, export_to = "gen_events.ts")] @@ -1330,6 +1362,35 @@ pub struct ListFoldersResponse { pub folders: Vec, } +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct UpsertModelRequest { + pub model: AnyModel, +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct UpsertModelResponse { + pub model: AnyModel, +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct DeleteModelRequest { + pub model: String, + pub id: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export, export_to = "gen_events.ts")] +pub struct DeleteModelResponse { + pub model: AnyModel, +} + #[derive(Debug, Clone, Default, Serialize, Deserialize, TS)] #[serde(default, rename_all = "camelCase")] #[ts(export, export_to = "gen_events.ts")] diff --git a/src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm b/src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm index dfa7764d..3259c304 100644 Binary files a/src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm and b/src-tauri/yaak-templates/pkg/yaak_templates_bg.wasm differ diff --git a/src-tauri/yaak-tls/src/lib.rs b/src-tauri/yaak-tls/src/lib.rs index 093f55ed..6dc357dd 100644 --- a/src-tauri/yaak-tls/src/lib.rs +++ b/src-tauri/yaak-tls/src/lib.rs @@ -248,7 +248,6 @@ pub fn find_client_certificate( // Match host (case-insensitive) if !cert.host.eq_ignore_ascii_case(host) { - debug!("Client certificate host does not match {} != {} (cert)", host, cert.host); continue; } diff --git a/src-web/components/RequestBodyViewer.tsx b/src-web/components/RequestBodyViewer.tsx index 7e0ccd51..5c108d84 100644 --- a/src-web/components/RequestBodyViewer.tsx +++ b/src-web/components/RequestBodyViewer.tsx @@ -2,8 +2,8 @@ import type { HttpResponse } from '@yaakapp-internal/models'; import { lazy, Suspense } from 'react'; import { useHttpRequestBody } from '../hooks/useHttpRequestBody'; import { getMimeTypeFromContentType, languageFromContentType } from '../lib/contentType'; -import { EmptyStateText } from './EmptyStateText'; import { LoadingIcon } from './core/LoadingIcon'; +import { EmptyStateText } from './EmptyStateText'; import { AudioViewer } from './responseViewers/AudioViewer'; import { CsvViewer } from './responseViewers/CsvViewer'; import { ImageViewer } from './responseViewers/ImageViewer'; diff --git a/src-web/components/Settings/SettingsLicense.tsx b/src-web/components/Settings/SettingsLicense.tsx index ea0134e1..19ec89d5 100644 --- a/src-web/components/Settings/SettingsLicense.tsx +++ b/src-web/components/Settings/SettingsLicense.tsx @@ -42,7 +42,10 @@ function SettingsLicenseCmp() { case 'trialing': return ( - +

{pluralizeCount('day', differenceInDays(check.data.data.end, new Date()))} @@ -56,10 +59,7 @@ function SettingsLicenseCmp() { Contact Support - + Learn More @@ -70,7 +70,10 @@ function SettingsLicenseCmp() { case 'personal_use': return ( - +

Your commercial-use trial has ended.
@@ -84,10 +87,7 @@ function SettingsLicenseCmp() { Contact Support - + Learn More diff --git a/src-web/components/Sidebar.tsx b/src-web/components/Sidebar.tsx index af1bba18..2a974a91 100644 --- a/src-web/components/Sidebar.tsx +++ b/src-web/components/Sidebar.tsx @@ -34,15 +34,15 @@ import { activeRequestIdAtom } from '../hooks/useActiveRequestId'; import { activeWorkspaceAtom, activeWorkspaceIdAtom } from '../hooks/useActiveWorkspace'; import { allRequestsAtom } from '../hooks/useAllRequests'; import { getCreateDropdownItems } from '../hooks/useCreateDropdownItems'; +import { getFolderActions } from '../hooks/useFolderActions'; import { getGrpcRequestActions } from '../hooks/useGrpcRequestActions'; import { useHotKey } from '../hooks/useHotKey'; import { getHttpRequestActions } from '../hooks/useHttpRequestActions'; -import { getWebsocketRequestActions } from '../hooks/useWebsocketRequestActions'; -import { getFolderActions } from '../hooks/useFolderActions'; import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent'; import { getModelAncestors } from '../hooks/useModelAncestors'; import { sendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest'; import { useSidebarHidden } from '../hooks/useSidebarHidden'; +import { getWebsocketRequestActions } from '../hooks/useWebsocketRequestActions'; import { deepEqualAtom } from '../lib/atoms'; import { deleteModelWithConfirm } from '../lib/deleteModelWithConfirm'; import { jotaiStore } from '../lib/jotai'; diff --git a/src-web/components/core/Editor/twig/twig.terms.ts b/src-web/components/core/Editor/twig/twig.terms.ts index d6bda1a3..7ac3c791 100644 --- a/src-web/components/core/Editor/twig/twig.terms.ts +++ b/src-web/components/core/Editor/twig/twig.terms.ts @@ -1,8 +1,7 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. -export const - Template = 1, +export const Template = 1, Tag = 2, TagOpen = 3, TagContent = 4, TagClose = 5, - Text = 6 + Text = 6; diff --git a/src-web/components/core/Editor/twig/twig.ts b/src-web/components/core/Editor/twig/twig.ts index 41f91be7..e124c988 100644 --- a/src-web/components/core/Editor/twig/twig.ts +++ b/src-web/components/core/Editor/twig/twig.ts @@ -1,18 +1,20 @@ // This file was generated by lezer-generator. You probably shouldn't edit it. -import {LRParser, LocalTokenGroup} from "@lezer/lr" -import {highlight} from "./highlight" +import { LocalTokenGroup, LRParser } from '@lezer/lr'; +import { highlight } from './highlight'; export const parser = LRParser.deserialize({ version: 14, - states: "!^QQOPOOOOOO'#C_'#C_OYOQO'#C^OOOO'#Cc'#CcQQOPOOOOOO'#Cd'#CdO_OQO,58xOOOO-E6a-E6aOOOO-E6b-E6bOOOO1G.d1G.d", - stateData: "g~OUROYPO~OSTO~OSTOTXO~O", - goto: "nXPPY^PPPbhTROSTQOSQSORVSQUQRWU", - nodeNames: "⚠ Template Tag TagOpen TagContent TagClose Text", + states: + "!^QQOPOOOOOO'#C_'#C_OYOQO'#C^OOOO'#Cc'#CcQQOPOOOOOO'#Cd'#CdO_OQO,58xOOOO-E6a-E6aOOOO-E6b-E6bOOOO1G.d1G.d", + stateData: 'g~OUROYPO~OSTO~OSTOTXO~O', + goto: 'nXPPY^PPPbhTROSTQOSQSORVSQUQRWU', + nodeNames: '⚠ Template Tag TagOpen TagContent TagClose Text', maxTerm: 10, propSources: [highlight], skippedNodes: [0], repeatNodeCount: 2, - tokenData: "#{~RTOtbtu!zu;'Sb;'S;=`!o<%lOb~gTU~Otbtuvu;'Sb;'S;=`!o<%lOb~yVO#ob#o#p!`#p;'Sb;'S;=`!o<%l~b~Ob~~!u~!cSO!}b#O;'Sb;'S;=`!o<%lOb~!rP;=`<%lb~!zOU~~!}VO#ob#o#p#d#p;'Sb;'S;=`!o<%l~b~Ob~~!u~#gTO!}b!}#O#v#O;'Sb;'S;=`!o<%lOb~#{OY~", - tokenizers: [1, new LocalTokenGroup("b~RP#P#QU~XP#q#r[~aOT~~", 17, 4)], - topRules: {"Template":[0,1]}, - tokenPrec: 0 -}) + tokenData: + "#{~RTOtbtu!zu;'Sb;'S;=`!o<%lOb~gTU~Otbtuvu;'Sb;'S;=`!o<%lOb~yVO#ob#o#p!`#p;'Sb;'S;=`!o<%l~b~Ob~~!u~!cSO!}b#O;'Sb;'S;=`!o<%lOb~!rP;=`<%lb~!zOU~~!}VO#ob#o#p#d#p;'Sb;'S;=`!o<%l~b~Ob~~!u~#gTO!}b!}#O#v#O;'Sb;'S;=`!o<%lOb~#{OY~", + tokenizers: [1, new LocalTokenGroup('b~RP#P#QU~XP#q#r[~aOT~~', 17, 4)], + topRules: { Template: [0, 1] }, + tokenPrec: 0, +}); diff --git a/src-web/components/core/HttpStatusTag.tsx b/src-web/components/core/HttpStatusTag.tsx index a690abd9..7a56752a 100644 --- a/src-web/components/core/HttpStatusTag.tsx +++ b/src-web/components/core/HttpStatusTag.tsx @@ -1,5 +1,4 @@ -import type { HttpResponse } from '@yaakapp-internal/models'; -import type { HttpResponseState } from '@yaakapp-internal/models'; +import type { HttpResponse, HttpResponseState } from '@yaakapp-internal/models'; import classNames from 'classnames'; interface Props { diff --git a/src-web/hooks/useFolderActions.ts b/src-web/hooks/useFolderActions.ts index 805c64b1..a9fe3635 100644 --- a/src-web/hooks/useFolderActions.ts +++ b/src-web/hooks/useFolderActions.ts @@ -2,8 +2,8 @@ import { useQuery } from '@tanstack/react-query'; import type { Folder } from '@yaakapp-internal/models'; import type { CallFolderActionRequest, - GetFolderActionsResponse, FolderAction, + GetFolderActionsResponse, } from '@yaakapp-internal/plugins'; import { useMemo } from 'react'; import { invokeCmd } from '../lib/tauri';