Compare commits

...

201 Commits

Author SHA1 Message Date
Gregory Schier
1e18933178 Kill plugin manager before NSIS update on Windows 2024-08-28 09:14:39 -07:00
Gregory Schier
97a4770464 Remove tauri "unstable" feature to fix Codemirror selection 2024-08-28 06:48:02 -07:00
Gregory Schier
db02dbcaa4 Hotfix for window focusing 2024-08-27 16:56:04 -07:00
Gregory Schier
badcbc7aef Special case Response()->response() 2024-08-26 15:26:43 -07:00
Gregory Schier
4b91601b98 Clean up code 2024-08-26 15:10:29 -07:00
Gregory Schier
93e0202b86 Default template fn args 2024-08-26 13:10:22 -07:00
Gregory Schier
e75d6abe33 Option to disable telemetry 2024-08-26 12:06:56 -07:00
Gregory Schier
24a4e3494e Node syntaxTree to parse template tags 2024-08-26 11:30:10 -07:00
Gregory Schier
124fb35dcd Force codemirror to parse more to be able to show code folding 2024-08-23 14:09:28 -07:00
Gregory Schier
1aa2839c51 Publish plugin-runtime-types 2024-08-23 13:37:47 -07:00
Gregory Schier
8d3260f394 Fix recursive plugin call locking 2024-08-23 13:20:48 -07:00
Gregory Schier
7e194b9148 Surface plugin error on import 2024-08-23 11:53:40 -07:00
Gregory Schier
f4abc1c7cb Fix initial apply text 2024-08-22 12:49:42 -07:00
Gregory Schier
6766bc8f59 Switch to single quotes for template strings 2024-08-22 12:48:14 -07:00
Gregory Schier
adda44e861 Pass render purpose to render 2024-08-22 11:27:55 -07:00
Gregory Schier
6aab017d3b Move to workspace crate 2024-08-22 10:49:51 -07:00
Gregory Schier
68c1dca9d1 Fix compile 2024-08-22 06:30:19 -07:00
Gregory Schier
066b7ea4f4 Fix deadlock on getting the focused window 2024-08-22 05:46:09 -07:00
Gregory Schier
0763c1b9b8 Some tweaks for beta 2024-08-19 19:10:08 -07:00
Gregory Schier
323e27a047 A bit more chaining cleanup 2024-08-19 16:38:28 -07:00
Gregory Schier
bd02206df2 A bunch of improvements to chaining 2024-08-19 14:10:44 -07:00
Gregory Schier
3411575ecc Actually call template functions 2024-08-19 10:34:22 -07:00
Gregory Schier
1193e1d7aa Async template functions working 2024-08-19 06:21:03 -07:00
Gregory Schier
1b63f33d43 Colored autocompletion icons 2024-08-17 05:47:05 -07:00
Gregory Schier
9f04cfb673 Template Tag Function Editor (#67)
![CleanShot 2024-08-15 at 16 53
09@2x](https://github.com/user-attachments/assets/8c0eb655-1daf-4dc8-811f-f606c770f7dc)
2024-08-16 08:31:19 -07:00
Gregory Schier
1fd1a901f8 Fix sidebar scroll into view 2024-08-15 09:09:18 -07:00
Gregory Schier
06517417b7 Fix some more styles 2024-08-15 05:58:09 -07:00
Gregory Schier
d924709b0c Keep sidebar and cmd+p items in view 2024-08-15 05:50:38 -07:00
Gregory Schier
6d274cea56 Request actions in command palette 2024-08-15 05:37:10 -07:00
Gregory Schier
b95fa25898 Request actions (#65) 2024-08-14 15:31:52 -07:00
Gregory Schier
12f4c2c668 Start on plugin ctx API (#64) 2024-08-14 06:42:54 -07:00
Gregory Schier
e47a2c5fab Variable value as title attr 2024-08-13 10:19:21 -07:00
Gregory Schier
fc279f67a1 Fix dollar sign in Twig grammar 2024-08-13 10:12:09 -07:00
Gregory Schier
6ed6e3e0e0 Fix rose pine themes 2024-08-13 07:51:26 -07:00
Gregory Schier
b5242b9a3f Use new theme vars (#63)
This PR swaps the theme to use the new stuff from the Theme Studio
2024-08-13 07:44:28 -07:00
Gregory Schier
a0950ce5b8 Don't persist settings tab 2024-08-10 08:10:14 -07:00
Gregory Schier
1dd8034cf9 Better curl import 2024-08-10 07:53:26 -07:00
Gregory Schier
7e73b680e6 Catch clipboard errors 2024-08-10 07:33:10 -07:00
Gregory Schier
352ffe9415 Don't show unnamed variables in autocomplete 2024-08-10 07:09:23 -07:00
Gregory Schier
e461851f6f Append [DEV] to window title in dev 2024-08-09 15:35:21 -07:00
Gregory Schier
673f2920a1 Fix gRPC request creation 2024-08-09 14:37:43 -07:00
Gregory Schier
e4ba408534 Correctly wrap small dialog text 2024-08-09 14:28:20 -07:00
Gregory Schier
96ae1d467b GraphQL variables now reset if entire thing deleted 2024-08-09 14:05:38 -07:00
Gregory Schier
48c239b7dc Fix Windows paths for new plugin runtime 2024-08-09 12:43:56 -07:00
Gregory Schier
331f1eb9b9 Better Windows pathing 2024-08-09 11:52:18 -07:00
Gregory Schier
1e9f10a99f UNC paths for plugins 2024-08-09 11:33:54 -07:00
Gregory Schier
6eb2cbd582 Fix up DB creation and migration 2024-08-09 11:20:04 -07:00
Gregory Schier
d9a7dba2e2 Vendor in build script 2024-08-09 08:51:21 -07:00
Gregory Schier
d885e6cb0a Fix body change setting headers/method 2024-08-09 08:33:49 -07:00
Gregory Schier
4cafc30f21 Remove problematic tests from release.yml 2024-08-09 08:33:01 -07:00
Gregory Schier
598a051bf8 Fix release script 2024-08-09 07:53:33 -07:00
Gregory Schier
965b579eb7 Switch to proper log plugin 2024-08-09 07:49:48 -07:00
Gregory Schier
d3a6125488 Fix release script 2024-08-09 07:42:39 -07:00
Gregory Schier
7f3492a1f0 Fix variable regex 2024-08-09 07:41:52 -07:00
Gregory Schier
c3970ba756 Run build before test as well 2024-08-09 07:29:48 -07:00
Gregory Schier
6f0a0a55a4 Fix 2024-08-09 07:12:32 -07:00
Gregory Schier
30fe3ee5cb Fix lint errors 2024-08-09 06:58:36 -07:00
Gregory Schier
1f637c583a Run vendor as separate script 2024-08-09 06:49:18 -07:00
Gregory Schier
3050995fed Fix xpath filtering 2024-08-08 22:54:15 -07:00
Gregory Schier
8081c86ec6 Better TS type generation 2024-08-08 22:07:05 -07:00
Gregory Schier
ed300dd320 Plugin runtime v2 (#62) 2024-08-08 21:30:59 -07:00
Gregory Schier
989b5a8058 Model and DB refactor (#61)
- [x] Move from `sqlx` to `rusqlite`
- [x] Generate TS types from Rust models
2024-08-05 07:58:20 -07:00
Gregory Schier
71013fd701 Use @yaakapp/api in models 2024-08-01 15:14:33 -07:00
Gregory Schier
76dd4380ce Updated plugin APIs 2024-08-01 07:01:57 -07:00
Gregory Schier
a643713139 Start of plugin types refactor 2024-07-31 14:56:55 -07:00
Gregory Schier
1cb86bc1b7 More flexible placeholder match 2024-07-31 07:42:18 -07:00
Gregory Schier
cc9bd2bc70 Template function return Result 2024-07-31 07:32:37 -07:00
Gregory Schier
90bf96c7c1 Apply forceUpdateKey to bulk pair editor 2024-07-30 15:50:29 -07:00
Gregory Schier
4e4c93c34e Always enable pairs from bulk editor 2024-07-30 15:35:06 -07:00
Gregory Schier
c2ce446692 Add rename/delete/send to cmd+k 2024-07-30 15:10:24 -07:00
Gregory Schier
d1a2c9622d Fix hotkey state messing up on Enter->submit 2024-07-30 15:10:08 -07:00
Gregory Schier
ecd8b93bd1 Add timestamp() to template fns 2024-07-30 14:04:33 -07:00
Gregory Schier
dd032a9e4d Fix fold gutter icon direction 2024-07-30 13:58:30 -07:00
Gregory Schier
f350f3b5f4 Named arguments in templating 2024-07-30 08:02:10 -07:00
Gregory Schier
45cb1ef0fe Tweak release things 2024-07-29 14:38:57 -07:00
Gregory Schier
d586ec5fb4 Remove canny-specific links 2024-07-29 11:50:00 -07:00
Gregory Schier
ad8a4933da Generate v1 updater artifacts 2024-07-28 18:32:50 -07:00
Gregory Schier
499d0b09ba Update vendor scripts again 2024-07-28 16:04:05 -07:00
Gregory Schier
ac1181c1b4 Refine vendor scripts 2024-07-28 15:56:48 -07:00
Gregory Schier
b9671781d3 Merge remote-tracking branch 'origin/master' 2024-07-28 15:40:37 -07:00
Gregory Schier
42fd7cb21e Fix killing command on Windows 2024-07-28 15:40:19 -07:00
Gregory Schier
fe9f765c1d Send full request to cmd_send_http_request to prevent
update->send race
2024-07-28 15:33:12 -07:00
Gregory Schier
087a1e5ea1 Remove command group 2024-07-28 14:13:01 -07:00
Gregory Schier
6e156497da Upgrade Tauri dependencies 2024-07-28 13:44:50 -07:00
Gregory Schier
ad3c2ed113 Better wait for kill signal 2024-07-27 09:13:34 -07:00
Gregory Schier
166bae6104 Fix spin lock 2024-07-27 09:05:43 -07:00
Gregory Schier
b3e6a2b34f Add sleep to child polling 2024-07-27 08:26:14 -07:00
Gregory Schier
547f1c9139 Better NodeJS vendoring 2024-07-26 00:01:21 -07:00
Gregory Schier
4d7ded61f8 Put updater back into targets 2024-07-25 20:56:47 -07:00
Gregory Schier
c92472dbac Fix targets 2024-07-25 13:33:00 -07:00
Gregory Schier
d347f2db77 Log when plugin runtime exits 2024-07-25 09:28:08 -07:00
Gregory Schier
80c1675331 Remove unused import 2024-07-25 07:58:04 -07:00
Gregory Schier
23fba45fcb Fix dunce usage 2024-07-25 07:52:53 -07:00
Gregory Schier
80777f712c Convert UNC paths in more places 2024-07-25 07:47:00 -07:00
Gregory Schier
6ffb0015c6 Use process group for node runtime 2024-07-24 10:14:40 -07:00
Gregory Schier
9d9b855c04 Remove UNC prefix for protoc exec 2024-07-24 08:07:06 -07:00
Gregory Schier
e7cbcc7b20 Protoc stderr into error 2024-07-24 07:41:51 -07:00
Gregory Schier
20a5ab3666 Fix external bin names 2024-07-24 07:05:05 -07:00
Gregory Schier
311fda887f Unique sidecar names 2024-07-24 07:04:14 -07:00
Gregory Schier
55e33df8d6 Fix NodeJS vendoring on Linux 2024-07-23 20:41:50 -07:00
Gregory Schier
71c9c8ba8c Fix nodejs vendoring 2024-07-23 15:37:27 -07:00
Gregory Schier
11c2b9bb2c Fix Windows vendor tmp path 2024-07-23 15:28:31 -07:00
Gregory Schier
5cfd208c23 NODE_ARCH -> YAAK_TARGET_ARCH 2024-07-23 14:52:25 -07:00
Gregory Schier
3a0b647ce4 Fix protoc vendoring 2024-07-23 14:35:39 -07:00
Gregory Schier
8367835061 Fix NodeJS vendoring 2024-07-23 14:31:53 -07:00
Gregory Schier
55276b968e Response info in new tab 2024-07-23 12:13:09 -07:00
Gregory Schier
9e04226097 Use SelectFile component in more places 2024-07-23 11:54:35 -07:00
Gregory Schier
51487d5412 Guess mime type on multi-part when not set 2024-07-23 11:39:21 -07:00
Gregory Schier
0dccba4ab2 Set minimum windows size 2024-07-23 11:35:16 -07:00
Gregory Schier
13183ae837 Better handling of large responses 2024-07-23 08:59:15 -07:00
Gregory Schier
f24fd13c45 Better import flow 2024-07-23 08:29:09 -07:00
Gregory Schier
972dffe959 Revert version 2024-07-23 07:31:00 -07:00
Gregory Schier
9f7033ab06 Fix notification status code handling 2024-07-23 07:30:47 -07:00
Gregory Schier
cd07123157 Back to @latest 2024-07-22 18:28:27 -07:00
Gregory Schier
b62901e295 Force bump Yaak CLI 2024-07-22 18:27:24 -07:00
Gregory Schier
96996f73d5 Remove test runs 2024-07-22 18:12:12 -07:00
Gregory Schier
4782fd376b Checkout plugins later in the release workflow 2024-07-22 18:08:49 -07:00
Gregory Schier
41dfa15feb Various tweaks 2024-07-22 17:55:28 -07:00
Gregory Schier
47d4fffc20 Plugin tweaks 2024-07-22 12:17:46 -07:00
Gregory Schier
994f314cff Better wording for moving workspace 2024-07-22 09:46:46 -07:00
Gregory Schier
0f8f086e01 Lowercase product name for Linux 2024-07-22 09:03:31 -07:00
Gregory Schier
19280c3bbc Some small refactoring 2024-07-21 22:18:45 -07:00
Gregory Schier
3cd7c1ef2e From SEA to regular NodeJS 2024-07-21 22:14:17 -07:00
Gregory Schier
6a5f61e84b Fixed plugins on Windows 2024-07-21 16:01:13 -07:00
Gregory Schier
a444984aed Fix import plugin hook 2024-07-21 15:46:47 -07:00
Gregory Schier
c0e253ef84 Change app name 2024-07-20 11:33:02 -07:00
Gregory Schier
7910d1b0fc Fix Windows key map 2024-07-20 10:49:08 -07:00
Gregory Schier
d26d20180e Don't resign SEA binary 2024-07-20 10:28:50 -07:00
Gregory Schier
54d9a78474 Fix tool location 2024-07-19 17:38:57 -07:00
Gregory Schier
216c41d8cf Fix deps 2024-07-19 17:31:37 -07:00
Gregory Schier
bf2c392380 Dynamic signtool.exe location 2024-07-19 17:30:20 -07:00
Gregory Schier
1835fa3ba4 Fix signtool path 2024-07-19 17:28:13 -07:00
Gregory Schier
d701381041 Add ampersand 2024-07-19 17:21:23 -07:00
Gregory Schier
89c19858df Fix signtool path? 2024-07-19 17:18:52 -07:00
Gregory Schier
01136921df Absolute signtool path 2024-07-19 17:11:53 -07:00
Gregory Schier
17ab201b96 Remove tmp dirs 2024-07-19 16:58:55 -07:00
Gregory Schier
5d3182da4c Again 2024-07-19 16:53:37 -07:00
Gregory Schier
293a91012f Better tmp dir creation 2024-07-19 16:51:05 -07:00
Gregory Schier
a43f601b6a Fix tmpdir on Windows 2024-07-19 16:43:22 -07:00
Gregory Schier
447932697d Fix script for Windows? 2024-07-19 16:30:20 -07:00
Gregory Schier
0c75c2289e Add protoc back 2024-07-19 16:23:16 -07:00
Gregory Schier
c97c9b599d Install Yaak CLI 2024-07-19 16:13:39 -07:00
Gregory Schier
fc972b04f7 Oops, fix arch 2024-07-19 16:10:40 -07:00
Gregory Schier
e8410f70a1 Fix Node arch 2024-07-19 16:08:37 -07:00
Gregory Schier
70c63fc63c Debug log 2024-07-19 16:01:05 -07:00
Gregory Schier
c4e1353b51 Add repo token 2024-07-19 15:45:54 -07:00
Gregory Schier
fd6959e868 Add protoc installation 2024-07-19 15:38:44 -07:00
Gregory Schier
854c19c1a1 Add download-protoc to build 2024-07-19 15:25:20 -07:00
Gregory Schier
9370b4879b Deps for plugin-runtime 2024-07-19 15:16:35 -07:00
Gregory Schier
0b2da8e7ae Ignore plugins checkout for eslint 2024-07-19 15:13:19 -07:00
Gregory Schier
2e0982b999 Fix is valid 2024-07-19 15:09:45 -07:00
Gregory Schier
2ec3be4374 Update yaak cli path 2024-07-19 14:39:48 -07:00
Gregory Schier
b1e6f52396 Fix Go install 2024-07-19 14:28:59 -07:00
Gregory Schier
5ce928068c Fix again 2024-07-19 14:28:05 -07:00
Gregory Schier
76b1e5b103 Fix setup go 2024-07-19 14:26:47 -07:00
Gregory Schier
4a95128416 Install Yaak CLI with Go 2024-07-19 14:25:21 -07:00
Gregory Schier
cae6eb2b24 Specify version 2024-07-19 14:06:33 -07:00
Gregory Schier
cdcfb585cf Fix directory 2024-07-19 14:01:21 -07:00
Gregory Schier
d4d56dfe1b Install Yaak CLI in workflow 2024-07-19 13:57:04 -07:00
Gregory Schier
f6c491498b Fix checkout 2024-07-19 11:16:15 -07:00
Gregory Schier
e01cdd1dad Fix working directory 2024-07-19 11:13:58 -07:00
Gregory Schier
9e41d366c1 Remove failing step 2024-07-19 11:10:45 -07:00
Gregory Schier
fee46de974 Move ci/build to workflow 2024-07-19 11:09:07 -07:00
Gregory Schier
fa14b7aaf8 Debug where npm is 2024-07-19 11:06:39 -07:00
Gregory Schier
bb44bfca49 Inherit env for exec 2024-07-19 11:04:03 -07:00
Gregory Schier
6fcb3948ce TRy again 2024-07-19 11:02:15 -07:00
Gregory Schier
f716291328 Add debug 2024-07-19 10:58:48 -07:00
Gregory Schier
9f8eabe22b Fix copy plugins script 2024-07-19 10:53:39 -07:00
Gregory Schier
6d9e14784f Fix workflow 2024-07-19 10:49:29 -07:00
Gregory Schier
1d5f3260e2 NodeJS Plugin Runtime (#53) 2024-07-19 10:41:47 -07:00
Gregory Schier
883fcdb6b8 Update useSaveResponse.tsx 2024-06-27 22:05:41 -07:00
Gregory Schier
c9040a6e5f Fix RadioDropdown key 2024-06-24 11:18:38 -07:00
Gregory Schier
151450f55b Better performance on large workspaces 2024-06-21 10:53:11 -07:00
Gregory Schier
5722880890 Better active workspace change notification 2024-06-21 10:11:00 -07:00
Gregory Schier
d361a40903 Consolidate any* hooks 2024-06-21 10:01:45 -07:00
Gregory Schier
cd9e720835 Add mutationKey everywhere 2024-06-21 09:25:25 -07:00
Gregory Schier
50e2ab3a03 Move request to another workspace (#52) 2024-06-21 09:01:18 -07:00
Gregory Schier
dc5dfeb022 Bump CI node version 2024-06-20 16:45:59 -07:00
Gregory Schier
0b8a18edae Safe URI for reflection 2024-06-20 13:11:40 -07:00
Gregory Schier
0bb3f14b4c Fix button styles 2024-06-20 12:55:13 -07:00
Gregory Schier
c18d30b89f Refactor gRPC reflection! 2024-06-20 12:49:58 -07:00
Gregory Schier
8f06a834c8 Update script 2024-06-20 09:23:50 -07:00
Gregory Schier
bd948f9cd6 Actually write the file 2024-06-20 09:20:04 -07:00
Gregory Schier
d70254bcdc Generic build version 2024-06-20 09:17:28 -07:00
Gregory Schier
fac5385d5d Bump version 2024-06-20 09:07:38 -07:00
Gregory Schier
e8bcc695bb Better fallback request name generation 2024-06-20 09:03:24 -07:00
Gregory Schier
88aeb0e530 Fix GRPC with files not refreshing, and tight render loop 2024-06-20 08:40:10 -07:00
Gregory Schier
92b1582232 Better gRPC reflection errors 2024-06-18 10:54:39 -07:00
Gregory Schier
196990c077 Bump version 2024-06-18 10:41:22 -07:00
Gregory Schier
c42b8cf538 Editor autocomplete same font size as editor 2024-06-18 09:43:51 -07:00
Gregory Schier
085274c960 Move GraphQL introspection out of LocalStorage 2024-06-18 09:43:28 -07:00
Gregory Schier
7ef187abf6 REvert other thing 2024-06-17 17:05:51 -07:00
Gregory Schier
12eac34d95 Fix editor tags wrapping behavior 2024-06-17 17:05:29 -07:00
Gregory Schier
c29b3c6509 Change version 2024-06-17 15:09:44 -07:00
Gregory Schier
7faa423aba Recursive environments 2024-06-17 12:24:06 -07:00
Gregory Schier
5b2162e48d Fix flash loading response viewer 2024-06-17 11:43:45 -07:00
Gregory Schier
ee776143b2 Fix parsing notification timestamp 2024-06-17 11:43:20 -07:00
Gregory Schier
7a18fb29e4 More dynamic plugin access 2024-06-15 22:13:01 -07:00
Gregory Schier
4485cad9e8 Workspace dropdown to RadioDropdown 2024-06-14 17:07:35 -07:00
Gregory Schier
33763b6d2f Fix plugins 2024-06-13 07:03:50 -07:00
Gregory Schier
641fe86cf7 Support nested functions 2024-06-12 23:13:36 -07:00
506 changed files with 22642 additions and 35654 deletions

View File

@@ -1,37 +1,47 @@
module.exports = {
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:import/recommended",
"plugin:jsx-a11y/recommended",
"plugin:@typescript-eslint/recommended",
"eslint-config-prettier"
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:import/recommended',
'plugin:jsx-a11y/recommended',
'plugin:@typescript-eslint/recommended',
'eslint-config-prettier',
],
parser: "@typescript-eslint/parser",
parser: '@typescript-eslint/parser',
parserOptions: {
project: ["./tsconfig.json"]
project: ['./tsconfig.json'],
},
ignorePatterns: ["src-tauri/**/*", "plugins/**/*"],
ignorePatterns: [
'scripts/**/*',
'plugin-runtime/**/*',
'plugin-runtime-types/**/*',
'src-tauri/**/*',
'plugins/**/*',
'tailwind.config.cjs',
],
settings: {
react: {
version: "detect"
version: 'detect',
},
"import/resolver": {
'import/resolver': {
node: {
paths: ["src-web"],
extensions: [".ts", ".tsx"]
}
}
paths: ['src-web'],
extensions: ['.ts', '.tsx'],
},
},
},
rules: {
"jsx-a11y/no-autofocus": "off",
"react/react-in-jsx-scope": "off",
"import/no-unresolved": "off",
"@typescript-eslint/consistent-type-imports": ["error", {
prefer: "type-imports",
disallowTypeAnnotations: true,
fixStyle: "separate-type-imports"
}]
}
'jsx-a11y/no-autofocus': 'off',
'react/react-in-jsx-scope': 'off',
'import/no-unresolved': 'off',
'@typescript-eslint/consistent-type-imports': [
'error',
{
prefer: 'type-imports',
disallowTypeAnnotations: true,
fixStyle: 'separate-type-imports',
},
],
},
};

View File

@@ -12,7 +12,7 @@ jobs:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
node-version: 20
- run: npm ci
- run: npm run lint
- run: npm test

View File

@@ -3,35 +3,51 @@ on:
push:
tags: [ v* ]
env:
YAAK_PLUGINS_DIR: checkout/plugins
jobs:
build-artifacts:
permissions:
contents: write
name: Build
strategy:
fail-fast: false
matrix:
include:
- platform: 'macos-latest' # for Arm based macs (M1 and above).
- platform: 'macos-latest' # for Arm-based macs (M1 and above).
args: '--target aarch64-apple-darwin'
- platform: 'macos-latest' # for Intel based macs.
yaak_arch: 'arm64'
- platform: 'macos-latest' # for Intel-based macs.
args: '--target x86_64-apple-darwin'
- platform: 'ubuntu-22.04' # for Tauri v1 you could replace this with ubuntu-20.04.
yaak_arch: 'x64'
- platform: 'ubuntu-22.04' # for Tauri v1, you could replace this with ubuntu-20.04.
args: ''
yaak_arch: 'x64'
- platform: 'windows-latest'
args: ''
yaak_arch: 'x64'
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
- name: Checkout yaakapp/app
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: lts/*
node-version: 20
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
with:
# Those targets are only used on macos runners so it's in an `if` to slightly speed up windows and linux builds.
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- uses: actions/cache@v3
continue-on-error: false
with:
@@ -43,19 +59,48 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
- name: install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04' # This must match the platform value defined above.
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- name: Install dependencies
run: npm ci
- name: Install Node dependencies
run: |
npm ci
- name: Install plugin-runtime Node dependencies
working-directory: plugin-runtime
run: |
npm ci
- name: Install Protoc for plugin-runtime
uses: arduino/setup-protoc@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install yaak CLI
run: go install github.com/yaakapp/yaakcli@latest
- name: Run lint
run: npm run lint
- name: Run tests
run: npm test
- name: Checkout yaakapp/plugins
uses: actions/checkout@v4
with:
repository: yaakapp/plugins
path: ${{ env.YAAK_PLUGINS_DIR }}
- name: Set version
run: npm run replace-version
env:
YAAK_VERSION: ${{ github.ref_name }}
- uses: tauri-apps/tauri-action@v0
env:
YAAK_PLUGINS_DIR: ${{ env.YAAK_PLUGINS_DIR }}
YAAK_TARGET_ARCH: ${{ matrix.yaak_arch }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
@@ -69,7 +114,7 @@ jobs:
with:
tagName: 'v__VERSION__'
releaseName: 'Release __VERSION__'
releaseBody: 'https://yaak.app/changelog/__VERSION__'
releaseBody: 'https://yaak.app/blog/__VERSION__'
releaseDraft: true
prerelease: false
args: ${{ matrix.args }}

4
.gitignore vendored
View File

@@ -28,4 +28,6 @@ dist-ssr
*.sqlite-*
.cargo
plugins/**/build
.tmp
tmp

View File

@@ -7,7 +7,8 @@
</scripts>
<node-interpreter value="project" />
<envs>
<env name="RUST_BACKTRACE" value="1" />
</envs>
<method v="2" />
</configuration>
</component>
</component>

View File

@@ -14,3 +14,8 @@ cargo sqlx migrate add ${MIGRATION_NAME}
cargo sqlx migrate run --database-url 'sqlite://db.sqlite?mode=rw'
cargo sqlx prepare --database-url 'sqlite://db.sqlite'
```
## Add App->Plugin API
- Add event in `events.rs`
- Add handler to `index.worker.ts`

View File

@@ -4,20 +4,20 @@
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Yaak App</title>
<!-- <script src="http://localhost:8097"></script>-->
<!-- <script src="http://localhost:8097"></script>-->
<!-- Certain elements like webview (and maybe <select>?) will use background
color depending on document background color-->
<style>
html, body {
background-color: white;
}
html, body {
background-color: white;
}
@media (prefers-color-scheme: dark) {
html, body {
background-color: #1b1a29;
}
@media (prefers-color-scheme: dark) {
html, body {
background-color: #1b1a29;
}
}
</style>
</head>

1422
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
{
"name": "yaak",
"name": "yaak-app",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -9,23 +9,18 @@
"tauri-dev:ios": "tauri ios dev --force-ip-prompt --config ./src-tauri/tauri-dev.conf.json",
"tauri-build": "tauri build",
"tauri": "tauri",
"build": "npm run build:frontend",
"dev": "vite dev",
"dev:js": "vite dev",
"lint": "tsc && eslint . --ext .ts,.tsx",
"build": "run-p build:*",
"build:icon:release": "tauri icon design/icon.png --output ./src-tauri/icons/release",
"build:icon:dev": "tauri icon design/icon-dev.png --output ./src-tauri/icons/dev",
"build:frontend": "vite build",
"build:plugins": "run-p build:plugin:*",
"build:plugin:exporter-curl": "cd plugins/exporter-curl && vite build --emptyOutDir",
"build:plugin:importer-insomnia": "cd plugins/importer-insomnia && vite build --emptyOutDir",
"build:plugin:importer-postman": "cd plugins/importer-postman && vite build --emptyOutDir",
"build:plugin:importer-yaak": "cd plugins/importer-yaak && vite build --emptyOutDir",
"build:plugin:importer-curl": "cd plugins/importer-curl && vite build --emptyOutDir",
"build:plugin:filter-jsonpath": "cd plugins/filter-jsonpath && vite build --emptyOutDir",
"build:plugin:filter-xpath": "cd plugins/filter-xpath && vite build --emptyOutDir",
"test": "vitest",
"coverage": "vitest run --coverage",
"prepare": "husky install"
"build:js": "vite build",
"build:plugin-runtime": "npm run --prefix plugin-runtime build",
"build:vendor-protoc": "node scripts/vendor-protoc.cjs",
"build:vendor-plugins": "node scripts/vendor-plugins.cjs",
"build:vendor-node": "node scripts/vendor-node.cjs",
"prepare": "husky install",
"replace-version": "node scripts/replace-version.cjs"
},
"dependencies": {
"@codemirror/commands": "^6.2.1",
@@ -39,13 +34,15 @@
"@lezer/lr": "^1.3.3",
"@react-hook/resize-observer": "^1.2.6",
"@tailwindcss/container-queries": "^0.1.0",
"@tanstack/react-query": "^5.35.5",
"@tauri-apps/api": ">=2.0.0-beta.0",
"@tauri-apps/plugin-clipboard-manager": "^2.1.0-beta.1",
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
"@tauri-apps/plugin-fs": ">=2.0.0-beta.0",
"@tauri-apps/plugin-os": ">=2.0.0-beta.0",
"@tauri-apps/plugin-shell": ">=2.0.0-beta.0",
"@tanstack/react-query": "^5.45.1",
"@tauri-apps/api": "^2.0.0-rc.0",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0-rc.0",
"@tauri-apps/plugin-dialog": "^2.0.0-rc.0",
"@tauri-apps/plugin-fs": "^2.0.0-rc.0",
"@tauri-apps/plugin-log": "^2.0.0-rc.0",
"@tauri-apps/plugin-os": "^2.0.0-rc.0",
"@tauri-apps/plugin-shell": "^2.0.0-rc.0",
"@yaakapp/api": "^0.1.13",
"buffer": "^6.0.3",
"classnames": "^2.3.2",
"cm6-graphql": "^0.0.9",
@@ -56,6 +53,7 @@
"focus-trap-react": "^10.1.1",
"format-graphql": "^1.4.0",
"framer-motion": "^9.0.4",
"jotai": "^2.9.3",
"lucide-react": "^0.309.0",
"mime": "^4.0.1",
"papaparse": "^5.4.1",
@@ -69,14 +67,13 @@
"react-router-dom": "^6.8.1",
"react-use": "^17.4.0",
"slugify": "^1.6.6",
"tauri-plugin-log-api": "github:tauri-apps/tauri-plugin-log#v2",
"uuid": "^9.0.0",
"xml-formatter": "^3.6.2"
},
"devDependencies": {
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
"@tanstack/react-query-devtools": "^5.35.5",
"@tauri-apps/cli": ">=2.0.0-beta.0",
"@tanstack/react-query-devtools": "^5.45.1",
"@tauri-apps/cli": "^2.0.0-rc.2",
"@types/node": "^18.7.10",
"@types/papaparse": "^5.3.7",
"@types/parse-color": "^1.0.1",
@@ -88,6 +85,7 @@
"@typescript-eslint/parser": "^7.0.2",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.13",
"decompress": "^4.2.1",
"eslint": "^8.34.0",
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
@@ -97,18 +95,19 @@
"husky": "^8.0.3",
"internal-ip": "^8.0.0",
"lint-staged": "^15.0.2",
"nodejs-file-downloader": "^4.13.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.21",
"postcss-nesting": "^11.2.1",
"prettier": "^2.8.4",
"react-devtools": "^4.27.2",
"rimraf": "^5.0.7",
"tailwindcss": "^3.2.7",
"typescript": "^5.4.5",
"vite": "^5.0.0",
"vite-plugin-static-copy": "^1.0.5",
"vite-plugin-svgr": "^4.2.0",
"vite-plugin-top-level-await": "^1.4.1",
"vitest": "^1.3.0"
"vite-plugin-top-level-await": "^1.4.1"
},
"lint-staged": {
"*.{ts,tsx}": "eslint --cache --fix",

2
plugin-runtime-types/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
lib
node_modules

44
plugin-runtime-types/package-lock.json generated Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "@yaakapp/api",
"version": "0.1.11",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@yaakapp/api",
"version": "0.1.11",
"dependencies": {
"@types/node": "^22.0.0"
},
"devDependencies": {
"typescript": "^5.5.4"
}
},
"node_modules/@types/node": {
"version": "22.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.0.tgz",
"integrity": "sha512-VT7KSYudcPOzP5Q0wfbowyNLaVR8QWUdw+088uFWwfvpY6uCWaXpqV6ieLAu9WBcnTa7H4Z5RLK8I5t2FuOcqw==",
"dependencies": {
"undici-types": "~6.11.1"
}
},
"node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.11.1",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz",
"integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ=="
}
}
}

View File

@@ -0,0 +1,19 @@
{
"name": "@yaakapp/api",
"version": "0.1.13",
"main": "lib/index.js",
"typings": "./lib/index.d.ts",
"files": [
"lib"
],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"dependencies": {
"@types/node": "^22.0.0"
},
"devDependencies": {
"typescript": "^5.5.4"
}
}

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type BootRequest = { dir: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type BootResponse = { name: string, version: string, capabilities: Array<string>, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
export type CallHttpRequestActionArgs = { httpRequest: HttpRequest, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { CallHttpRequestActionArgs } from "./CallHttpRequestActionArgs";
export type CallHttpRequestActionRequest = { key: string, pluginRefId: string, args: CallHttpRequestActionArgs, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RenderPurpose } from "./RenderPurpose";
export type CallTemplateFunctionArgs = { purpose: RenderPurpose, values: { [key: string]: string }, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { CallTemplateFunctionArgs } from "./CallTemplateFunctionArgs";
export type CallTemplateFunctionRequest = { name: string, args: CallTemplateFunctionArgs, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type CallTemplateFunctionResponse = { value: string | null, };

View File

@@ -0,0 +1,5 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { CookieDomain } from "./CookieDomain";
import type { CookieExpires } from "./CookieExpires";
export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type CookieExpires = { "AtUtc": string } | "SessionEnd";

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { Cookie } from "./Cookie";
export type CookieJar = { id: string, model: "cookie_jar", createdAt: string, updatedAt: string, workspaceId: string, name: string, cookies: Array<Cookie>, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type CopyTextRequest = { text: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type EmptyResponse = {};

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { EnvironmentVariable } from "./EnvironmentVariable";
export type Environment = { id: string, workspaceId: string, model: "environment", createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
export type ExportHttpRequestRequest = { httpRequest: HttpRequest, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ExportHttpRequestResponse = { content: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type FilterRequest = { content: string, filter: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type FilterResponse = { content: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type FindHttpResponsesRequest = { requestId: string, limit: number | null, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpResponse } from "./HttpResponse";
export type FindHttpResponsesResponse = { httpResponses: Array<HttpResponse>, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type Folder = { createdAt: string, updatedAt: string, id: string, workspaceId: string, folderId: string | null, model: "folder", name: string, sortPriority: number, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GetHttpRequestActionsRequest = Record<string, never>;

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequestAction } from "./HttpRequestAction";
export type GetHttpRequestActionsResponse = { actions: Array<HttpRequestAction>, pluginRefId: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GetHttpRequestByIdRequest = { id: string, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
export type GetHttpRequestByIdResponse = { httpRequest: HttpRequest | null, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { TemplateFunction } from "./TemplateFunction";
export type GetTemplateFunctionsResponse = { functions: Array<TemplateFunction>, pluginRefId: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GrpcConnection = { id: string, model: "grpc_connection", workspaceId: string, requestId: string, createdAt: string, updatedAt: string, service: string, method: string, elapsed: number, status: number, url: string, error: string | null, trailers: { [key: string]: string }, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { GrpcEventType } from "./GrpcEventType";
export type GrpcEvent = { id: string, model: "grpc_event", workspaceId: string, requestId: string, connectionId: string, createdAt: string, content: string, eventType: GrpcEventType, metadata: { [key: string]: string }, status: number | null, error: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end";

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type GrpcMetadataEntry = { enabled?: boolean, name: string, value: string, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { GrpcMetadataEntry } from "./GrpcMetadataEntry";
export type GrpcRequest = { id: string, model: "grpc_request", workspaceId: string, createdAt: string, updatedAt: string, folderId: string | null, name: string, sortPriority: number, url: string, service: string | null, method: string | null, message: string, authenticationType: string | null, authentication: Record<string, any>, metadata: Array<GrpcMetadataEntry>, };

View File

@@ -0,0 +1,5 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequestHeader } from "./HttpRequestHeader";
import type { HttpUrlParameter } from "./HttpUrlParameter";
export type HttpRequest = { createdAt: string, updatedAt: string, id: string, workspaceId: string, folderId: string | null, model: "http_request", sortPriority: number, name: string, url: string, urlParameters: Array<HttpUrlParameter>, method: string, body: Record<string, any>, bodyType: string | null, authentication: Record<string, any>, authenticationType: string | null, headers: Array<HttpRequestHeader>, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type HttpRequestAction = { key: string, label: string, icon: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpResponseHeader } from "./HttpResponseHeader";
export type HttpResponse = { id: string, model: "http_response", workspaceId: string, requestId: string, createdAt: string, updatedAt: string, error: string | null, url: string, contentLength: number | null, version: string | null, elapsed: number, elapsedHeaders: number, remoteAddr: string | null, status: number, statusReason: string | null, bodyPath: string | null, headers: Array<HttpResponseHeader>, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type HttpResponseHeader = { name: string, value: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ImportRequest = { content: string, };

View File

@@ -0,0 +1,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { Environment } from "./Environment";
import type { Folder } from "./Folder";
import type { GrpcRequest } from "./GrpcRequest";
import type { HttpRequest } from "./HttpRequest";
import type { Workspace } from "./Workspace";
export type ImportResources = { workspaces: Array<Workspace>, environments: Array<Environment>, folders: Array<Folder>, httpRequests: Array<HttpRequest>, grpcRequests: Array<GrpcRequest>, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ImportResources } from "./ImportResources";
export type ImportResponse = { resources: ImportResources, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { InternalEventPayload } from "./InternalEventPayload";
export type InternalEvent = { id: string, pluginRefId: string, replyId: string | null, payload: InternalEventPayload, };

View File

@@ -0,0 +1,28 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { BootRequest } from "./BootRequest";
import type { BootResponse } from "./BootResponse";
import type { CallHttpRequestActionRequest } from "./CallHttpRequestActionRequest";
import type { CallTemplateFunctionRequest } from "./CallTemplateFunctionRequest";
import type { CallTemplateFunctionResponse } from "./CallTemplateFunctionResponse";
import type { CopyTextRequest } from "./CopyTextRequest";
import type { EmptyResponse } from "./EmptyResponse";
import type { ExportHttpRequestRequest } from "./ExportHttpRequestRequest";
import type { ExportHttpRequestResponse } from "./ExportHttpRequestResponse";
import type { FilterRequest } from "./FilterRequest";
import type { FilterResponse } from "./FilterResponse";
import type { FindHttpResponsesRequest } from "./FindHttpResponsesRequest";
import type { FindHttpResponsesResponse } from "./FindHttpResponsesResponse";
import type { GetHttpRequestActionsRequest } from "./GetHttpRequestActionsRequest";
import type { GetHttpRequestActionsResponse } from "./GetHttpRequestActionsResponse";
import type { GetHttpRequestByIdRequest } from "./GetHttpRequestByIdRequest";
import type { GetHttpRequestByIdResponse } from "./GetHttpRequestByIdResponse";
import type { GetTemplateFunctionsResponse } from "./GetTemplateFunctionsResponse";
import type { ImportRequest } from "./ImportRequest";
import type { ImportResponse } from "./ImportResponse";
import type { RenderHttpRequestRequest } from "./RenderHttpRequestRequest";
import type { RenderHttpRequestResponse } from "./RenderHttpRequestResponse";
import type { SendHttpRequestRequest } from "./SendHttpRequestRequest";
import type { SendHttpRequestResponse } from "./SendHttpRequestResponse";
import type { ShowToastRequest } from "./ShowToastRequest";
export type InternalEventPayload = { "type": "boot_request" } & BootRequest | { "type": "boot_response" } & BootResponse | { "type": "import_request" } & ImportRequest | { "type": "import_response" } & ImportResponse | { "type": "filter_request" } & FilterRequest | { "type": "filter_response" } & FilterResponse | { "type": "export_http_request_request" } & ExportHttpRequestRequest | { "type": "export_http_request_response" } & ExportHttpRequestResponse | { "type": "send_http_request_request" } & SendHttpRequestRequest | { "type": "send_http_request_response" } & SendHttpRequestResponse | { "type": "get_http_request_actions_request" } & GetHttpRequestActionsRequest | { "type": "get_http_request_actions_response" } & GetHttpRequestActionsResponse | { "type": "call_http_request_action_request" } & CallHttpRequestActionRequest | { "type": "get_template_functions_request" } | { "type": "get_template_functions_response" } & GetTemplateFunctionsResponse | { "type": "call_template_function_request" } & CallTemplateFunctionRequest | { "type": "call_template_function_response" } & CallTemplateFunctionResponse | { "type": "copy_text_request" } & CopyTextRequest | { "type": "render_http_request_request" } & RenderHttpRequestRequest | { "type": "render_http_request_response" } & RenderHttpRequestResponse | { "type": "show_toast_request" } & ShowToastRequest | { "type": "get_http_request_by_id_request" } & GetHttpRequestByIdRequest | { "type": "get_http_request_by_id_response" } & GetHttpRequestByIdResponse | { "type": "find_http_responses_request" } & FindHttpResponsesRequest | { "type": "find_http_responses_response" } & FindHttpResponsesResponse | { "type": "empty_response" } & EmptyResponse;

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type KeyValue = { model: "key_value", createdAt: string, updatedAt: string, namespace: string, key: string, value: string, };

View File

@@ -0,0 +1,14 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { CookieJar } from "./CookieJar";
import type { Environment } from "./Environment";
import type { Folder } from "./Folder";
import type { GrpcConnection } from "./GrpcConnection";
import type { GrpcEvent } from "./GrpcEvent";
import type { GrpcRequest } from "./GrpcRequest";
import type { HttpRequest } from "./HttpRequest";
import type { HttpResponse } from "./HttpResponse";
import type { KeyValue } from "./KeyValue";
import type { Settings } from "./Settings";
import type { Workspace } from "./Workspace";
export type Model = Environment | Folder | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | KeyValue | Workspace | CookieJar | Settings;

View File

@@ -0,0 +1,5 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
import type { RenderPurpose } from "./RenderPurpose";
export type RenderHttpRequestRequest = { httpRequest: HttpRequest, purpose: RenderPurpose, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
export type RenderHttpRequestResponse = { httpRequest: HttpRequest, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RenderPurpose = "send" | "preview";

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RenderRequest = { template: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RenderResponse = { rendered: string, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpRequest } from "./HttpRequest";
export type SendHttpRequestRequest = { httpRequest: HttpRequest, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { HttpResponse } from "./HttpResponse";
export type SendHttpRequestResponse = { httpResponse: HttpResponse, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type Settings = { id: string, model: "settings", createdAt: string, updatedAt: string, theme: string, appearance: string, themeDark: string, themeLight: string, updateChannel: string, interfaceFontSize: number, interfaceScale: number, editorFontSize: number, editorSoftWrap: boolean, telemetry: boolean, openWorkspaceNewWindow: boolean | null, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ToastVariant } from "./ToastVariant";
export type ShowToastRequest = { message: string, variant: ToastVariant, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { TemplateFunctionArg } from "./TemplateFunctionArg";
export type TemplateFunction = { name: string, args: Array<TemplateFunctionArg>, };

View File

@@ -0,0 +1,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { TemplateFunctionCheckboxArg } from "./TemplateFunctionCheckboxArg";
import type { TemplateFunctionHttpRequestArg } from "./TemplateFunctionHttpRequestArg";
import type { TemplateFunctionSelectArg } from "./TemplateFunctionSelectArg";
import type { TemplateFunctionTextArg } from "./TemplateFunctionTextArg";
export type TemplateFunctionArg = { "type": "text" } & TemplateFunctionTextArg | { "type": "select" } & TemplateFunctionSelectArg | { "type": "checkbox" } & TemplateFunctionCheckboxArg | { "type": "http_request" } & TemplateFunctionHttpRequestArg;

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TemplateFunctionBaseArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TemplateFunctionCheckboxArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TemplateFunctionHttpRequestArg = { name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { TemplateFunctionSelectOption } from "./TemplateFunctionSelectOption";
export type TemplateFunctionSelectArg = { options: Array<TemplateFunctionSelectOption>, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TemplateFunctionSelectOption = { name: string, value: string, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TemplateFunctionTextArg = { placeholder?: string | null, name: string, optional?: boolean | null, label?: string | null, defaultValue?: string | null, };

View File

@@ -0,0 +1,3 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ToastVariant = "custom" | "copied" | "success" | "info" | "warning" | "error";

View File

@@ -0,0 +1,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { EnvironmentVariable } from "./EnvironmentVariable";
export type Workspace = { id: string, model: "workspace", createdAt: string, updatedAt: string, name: string, description: string, variables: Array<EnvironmentVariable>, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };

View File

@@ -0,0 +1,2 @@
export type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
export type OneOrMany<T> = T[] | T;

View File

@@ -0,0 +1,65 @@
export type * from './plugins';
export type * from './themes';
// TODO: The next ts-rs release includes the ability to put everything in 1 file!
export * from './gen/BootRequest';
export * from './gen/BootResponse';
export * from './gen/CallHttpRequestActionArgs';
export * from './gen/CallHttpRequestActionRequest';
export * from './gen/CallTemplateFunctionRequest';
export * from './gen/CallTemplateFunctionResponse';
export * from './gen/CallTemplateFunctionArgs';
export * from './gen/Cookie';
export * from './gen/CookieDomain';
export * from './gen/CookieExpires';
export * from './gen/CookieJar';
export * from './gen/CopyTextRequest';
export * from './gen/EmptyResponse';
export * from './gen/Environment';
export * from './gen/EnvironmentVariable';
export * from './gen/ExportHttpRequestRequest';
export * from './gen/ExportHttpRequestResponse';
export * from './gen/FilterRequest';
export * from './gen/FilterResponse';
export * from './gen/Folder';
export * from './gen/FindHttpResponsesRequest';
export * from './gen/FindHttpResponsesResponse';
export * from './gen/GetHttpRequestActionsResponse';
export * from './gen/GetHttpRequestByIdRequest';
export * from './gen/GetHttpRequestByIdResponse';
export * from './gen/GetTemplateFunctionsResponse';
export * from './gen/GrpcConnection';
export * from './gen/GrpcEvent';
export * from './gen/GrpcMetadataEntry';
export * from './gen/GrpcRequest';
export * from './gen/HttpRequest';
export * from './gen/HttpRequestAction';
export * from './gen/HttpRequestHeader';
export * from './gen/HttpResponse';
export * from './gen/HttpResponseHeader';
export * from './gen/HttpUrlParameter';
export * from './gen/ImportRequest';
export * from './gen/ImportResources';
export * from './gen/ImportResponse';
export * from './gen/InternalEvent';
export * from './gen/InternalEventPayload';
export * from './gen/KeyValue';
export * from './gen/Model';
export * from './gen/RenderHttpRequestRequest';
export * from './gen/RenderHttpRequestResponse';
export * from './gen/RenderPurpose';
export * from './gen/SendHttpRequestRequest';
export * from './gen/SendHttpRequestResponse';
export * from './gen/SendHttpRequestResponse';
export * from './gen/Settings';
export * from './gen/ShowToastRequest';
export * from './gen/TemplateFunction';
export * from './gen/TemplateFunctionArg';
export * from './gen/TemplateFunctionBaseArg';
export * from './gen/TemplateFunctionCheckboxArg';
export * from './gen/TemplateFunctionHttpRequestArg';
export * from './gen/TemplateFunctionSelectArg';
export * from './gen/TemplateFunctionSelectOption';
export * from './gen/TemplateFunctionTextArg';
export * from './gen/ToastVariant';
export * from './gen/Workspace';

View File

@@ -0,0 +1,26 @@
import { FindHttpResponsesRequest } from '../gen/FindHttpResponsesRequest';
import { FindHttpResponsesResponse } from '../gen/FindHttpResponsesResponse';
import { GetHttpRequestByIdRequest } from '../gen/GetHttpRequestByIdRequest';
import { GetHttpRequestByIdResponse } from '../gen/GetHttpRequestByIdResponse';
import { RenderHttpRequestRequest } from '../gen/RenderHttpRequestRequest';
import { RenderHttpRequestResponse } from '../gen/RenderHttpRequestResponse';
import { SendHttpRequestRequest } from '../gen/SendHttpRequestRequest';
import { SendHttpRequestResponse } from '../gen/SendHttpRequestResponse';
import { ShowToastRequest } from '../gen/ShowToastRequest';
export type Context = {
clipboard: {
copyText(text: string): void;
};
toast: {
show(args: ShowToastRequest): void;
};
httpRequest: {
send(args: SendHttpRequestRequest): Promise<SendHttpRequestResponse['httpResponse']>;
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse['httpRequest']>;
};
httpResponse: {
find(args: FindHttpResponsesRequest): Promise<FindHttpResponsesResponse['httpResponses']>;
};
};

View File

@@ -0,0 +1,13 @@
import { Context } from './Context';
export type FilterPluginResponse = string[];
export type FilterPlugin = {
name: string;
description?: string;
canFilter(ctx: Context, args: { mimeType: string }): Promise<boolean>;
onFilter(
ctx: Context,
args: { payload: string; mimeType: string },
): Promise<FilterPluginResponse>;
};

View File

@@ -0,0 +1,7 @@
import { CallHttpRequestActionArgs } from '../gen/CallHttpRequestActionArgs';
import { HttpRequestAction } from '../gen/HttpRequestAction';
import { Context } from './Context';
export type HttpRequestActionPlugin = HttpRequestAction & {
onSelect(ctx: Context, args: CallHttpRequestActionArgs): Promise<void> | void;
};

View File

@@ -0,0 +1,19 @@
import { Environment } from '../gen/Environment';
import { Folder } from '../gen/Folder';
import { HttpRequest } from '../gen/HttpRequest';
import { Workspace } from '../gen/Workspace';
import { AtLeast } from '../helpers';
import { Context } from './Context';
export type ImportPluginResponse = null | {
workspaces: AtLeast<Workspace, 'name' | 'id' | 'model'>[];
environments: AtLeast<Environment, 'name' | 'id' | 'model' | 'workspaceId'>[];
httpRequests: AtLeast<HttpRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
};
export type ImporterPlugin = {
name: string;
description?: string;
onImport(ctx: Context, args: { text: string }): Promise<ImportPluginResponse>;
};

View File

@@ -0,0 +1,7 @@
import { CallTemplateFunctionArgs } from '../gen/CallTemplateFunctionArgs';
import { TemplateFunction } from '../gen/TemplateFunction';
import { Context } from './Context';
export type TemplateFunctionPlugin = TemplateFunction & {
onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise<string | null>;
};

View File

@@ -0,0 +1,8 @@
import { Theme } from '../themes';
import { Context } from './Context';
export type ThemePlugin = {
name: string;
description?: string;
getTheme(ctx: Context, fileContents: string): Promise<Theme>;
};

View File

@@ -0,0 +1,18 @@
import { FilterPlugin } from './FilterPlugin';
import { HttpRequestActionPlugin } from './HttpRequestActionPlugin';
import { ImporterPlugin } from './ImporterPlugin';
import { TemplateFunctionPlugin } from './TemplateFunctionPlugin';
import { ThemePlugin } from './ThemePlugin';
export type { Context } from './Context';
/**
* The global structure of a Yaak plugin
*/
export type Plugin = {
importer?: ImporterPlugin;
theme?: ThemePlugin;
filter?: FilterPlugin;
httpRequestActions?: HttpRequestActionPlugin[];
templateFunctions?: TemplateFunctionPlugin[];
};

View File

@@ -0,0 +1,44 @@
export type Colors = {
surface: string;
surfaceHighlight?: string;
surfaceActive?: string;
text: string;
textSubtle?: string;
textSubtlest?: string;
border?: string;
borderSubtle?: string;
borderFocus?: string;
shadow?: string;
backdrop?: string;
selection?: string;
primary?: string;
secondary?: string;
info?: string;
success?: string;
notice?: string;
warning?: string;
danger?: string;
};
export type Theme = Colors & {
id: string;
name: string;
components?: Partial<{
dialog: Partial<Colors>;
menu: Partial<Colors>;
toast: Partial<Colors>;
sidebar: Partial<Colors>;
responsePane: Partial<Colors>;
appHeader: Partial<Colors>;
button: Partial<Colors>;
banner: Partial<Colors>;
placeholder: Partial<Colors>;
urlBar: Partial<Colors>;
editor: Partial<Colors>;
input: Partial<Colors>;
}>;
};

View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "node16",
"target": "es6",
"lib": ["es2021"],
"declaration": true,
"declarationDir": "./lib",
"outDir": "./lib",
"strict": true,
"types": ["node"]
},
"files": [
"src/index.ts"
]
}

3
plugin-runtime/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
build
node_modules
*.blob

View File

@@ -0,0 +1,5 @@
{
"watch": ["src"],
"ext": "ts",
"exec": "node -r ts-node/register ./src/index.ts"
}

3065
plugin-runtime/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,25 @@
{
"name": "@yaak/plugin-runtime",
"scripts": {
"dev": "nodemon",
"build": "run-p build:*",
"build:main": "esbuild src/index.ts --bundle --platform=node --outfile=build/index.cjs",
"build:worker": "esbuild src/index.worker.ts --bundle --platform=node --outfile=build/index.worker.cjs",
"build:proto": "grpc_tools_node_protoc --ts_proto_out=src/gen --ts_proto_opt=outputServices=nice-grpc,outputServices=generic-definitions,useExactTypes=false --proto_path=../proto ../proto/plugins/*.proto"
},
"dependencies": {
"intercept-stdout": "^0.1.2",
"long": "^5.2.3",
"nice-grpc": "^2.1.9",
"protobufjs": "^7.3.2"
},
"devDependencies": {
"@types/intercept-stdout": "^0.1.3",
"grpc-tools": "^1.12.4",
"nodemon": "^3.1.4",
"npm-run-all": "^4.1.5",
"ts-node": "^10.9.2",
"ts-proto": "^1.180.0",
"typescript": "^5.5.2"
}
}

View File

@@ -0,0 +1,21 @@
import { InternalEvent } from '@yaakapp/api';
import EventEmitter from 'node:events';
import { EventStreamEvent } from './gen/plugins/runtime';
export class EventChannel {
emitter: EventEmitter = new EventEmitter();
emit(e: InternalEvent) {
this.emitter.emit('__plugin_event__', { event: JSON.stringify(e) });
}
async *listen(): AsyncGenerator<EventStreamEvent> {
while (true) {
yield new Promise<EventStreamEvent>((resolve) => {
this.emitter.once('__plugin_event__', (event: EventStreamEvent) => {
resolve(event);
});
});
}
}
}

View File

@@ -0,0 +1,42 @@
import { InternalEvent } from '@yaakapp/api';
import path from 'node:path';
import { Worker } from 'node:worker_threads';
import { EventChannel } from './EventChannel';
export class PluginHandle {
readonly #worker: Worker;
constructor(
readonly pluginDir: string,
readonly pluginRefId: string,
readonly events: EventChannel,
) {
const workerPath = process.env.YAAK_WORKER_PATH ?? path.join(__dirname, 'index.worker.cjs');
this.#worker = new Worker(workerPath, {
workerData: {
pluginDir,
pluginRefId,
},
});
this.#worker.on('message', (e) => this.events.emit(e));
this.#worker.on('error', this.#handleError.bind(this));
this.#worker.on('exit', this.#handleExit.bind(this));
}
sendToWorker(event: InternalEvent) {
this.#worker.postMessage(event);
}
async #handleError(err: Error) {
console.error('Plugin errored', this.pluginDir, err);
}
async #handleExit(code: number) {
if (code === 0) {
console.log('Plugin exited successfully', this.pluginDir);
} else {
console.log('Plugin exited with error', code, this.pluginDir);
}
}
}

View File

@@ -0,0 +1,116 @@
// Code generated by protoc-gen-ts_proto. DO NOT EDIT.
// versions:
// protoc-gen-ts_proto v1.180.0
// protoc v3.19.1
// source: plugins/runtime.proto
/* eslint-disable */
import { type CallContext, type CallOptions } from "nice-grpc-common";
import * as _m0 from "protobufjs/minimal";
export const protobufPackage = "yaak.plugins.runtime";
export interface EventStreamEvent {
event: string;
}
function createBaseEventStreamEvent(): EventStreamEvent {
return { event: "" };
}
export const EventStreamEvent = {
encode(message: EventStreamEvent, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.event !== "") {
writer.uint32(10).string(message.event);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): EventStreamEvent {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseEventStreamEvent();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.event = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): EventStreamEvent {
return { event: isSet(object.event) ? globalThis.String(object.event) : "" };
},
toJSON(message: EventStreamEvent): unknown {
const obj: any = {};
if (message.event !== "") {
obj.event = message.event;
}
return obj;
},
create(base?: DeepPartial<EventStreamEvent>): EventStreamEvent {
return EventStreamEvent.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<EventStreamEvent>): EventStreamEvent {
const message = createBaseEventStreamEvent();
message.event = object.event ?? "";
return message;
},
};
export type PluginRuntimeDefinition = typeof PluginRuntimeDefinition;
export const PluginRuntimeDefinition = {
name: "PluginRuntime",
fullName: "yaak.plugins.runtime.PluginRuntime",
methods: {
eventStream: {
name: "EventStream",
requestType: EventStreamEvent,
requestStream: true,
responseType: EventStreamEvent,
responseStream: true,
options: {},
},
},
} as const;
export interface PluginRuntimeServiceImplementation<CallContextExt = {}> {
eventStream(
request: AsyncIterable<EventStreamEvent>,
context: CallContext & CallContextExt,
): ServerStreamingMethodResult<DeepPartial<EventStreamEvent>>;
}
export interface PluginRuntimeClient<CallOptionsExt = {}> {
eventStream(
request: AsyncIterable<DeepPartial<EventStreamEvent>>,
options?: CallOptions & CallOptionsExt,
): AsyncIterable<EventStreamEvent>;
}
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
export type DeepPartial<T> = T extends Builtin ? T
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
: Partial<T>;
function isSet(value: any): boolean {
return value !== null && value !== undefined;
}
export type ServerStreamingMethodResult<Response> = { [Symbol.asyncIterator](): AsyncIterator<Response, void> };

View File

@@ -0,0 +1,42 @@
import { InternalEvent } from '@yaakapp/api';
import { createChannel, createClient, Status } from 'nice-grpc';
import { EventChannel } from './EventChannel';
import { PluginRuntimeClient, PluginRuntimeDefinition } from './gen/plugins/runtime';
import { PluginHandle } from './PluginHandle';
const port = process.env.PORT || '50051';
const channel = createChannel(`localhost:${port}`);
const client: PluginRuntimeClient = createClient(PluginRuntimeDefinition, channel);
const events = new EventChannel();
const plugins: Record<string, PluginHandle> = {};
(async () => {
try {
for await (const e of client.eventStream(events.listen())) {
const pluginEvent: InternalEvent = JSON.parse(e.event);
// Handle special event to bootstrap plugin
if (pluginEvent.payload.type === 'boot_request') {
const plugin = new PluginHandle(pluginEvent.payload.dir, pluginEvent.pluginRefId, events);
plugins[pluginEvent.pluginRefId] = plugin;
}
// Once booted, forward all events to plugin's worker
const plugin = plugins[pluginEvent.pluginRefId];
if (!plugin) {
console.warn('Failed to get plugin for event by', pluginEvent.pluginRefId);
continue;
}
plugin.sendToWorker(pluginEvent);
}
console.log('Stream ended');
} catch (err: any) {
if (err.code === Status.CANCELLED) {
console.log('Stream was cancelled by server');
} else {
console.log('Client stream errored', err);
}
}
})();

View File

@@ -0,0 +1,287 @@
import {
Context,
FindHttpResponsesResponse,
GetHttpRequestByIdResponse,
HttpRequestAction,
ImportResponse,
InternalEvent,
InternalEventPayload,
RenderHttpRequestResponse,
SendHttpRequestResponse,
TemplateFunction,
} from '@yaakapp/api';
import { HttpRequestActionPlugin } from '@yaakapp/api/lib/plugins/httpRequestAction';
import { TemplateFunctionPlugin } from '@yaakapp/api/lib/plugins/TemplateFunctionPlugin';
import interceptStdout from 'intercept-stdout';
import * as console from 'node:console';
import { readFileSync } from 'node:fs';
import path from 'node:path';
import * as util from 'node:util';
import { parentPort, workerData } from 'node:worker_threads';
new Promise<void>(async (resolve, reject) => {
const { pluginDir, pluginRefId } = workerData;
const pathPkg = path.join(pluginDir, 'package.json');
// NOTE: Use POSIX join because require() needs forward slash
const pathMod = path.posix.join(pluginDir, 'build', 'index.js');
let pkg: { [x: string]: any };
try {
pkg = JSON.parse(readFileSync(pathPkg, 'utf8'));
} catch (err) {
// TODO: Do something better here
reject(err);
return;
}
prefixStdout(`[plugin][${pkg.name}] %s`);
const mod = (await import(pathMod)).default ?? {};
const capabilities: string[] = [];
if (typeof mod.pluginHookExport === 'function') capabilities.push('export');
if (typeof mod.pluginHookImport === 'function') capabilities.push('import');
if (typeof mod.pluginHookResponseFilter === 'function') capabilities.push('filter');
console.log('Plugin initialized', pkg.name, capabilities, Object.keys(mod));
function buildEventToSend(
payload: InternalEventPayload,
replyId: string | null = null,
): InternalEvent {
return { pluginRefId, id: genId(), replyId, payload };
}
function sendEmpty(replyId: string | null = null): string {
return sendPayload({ type: 'empty_response' }, replyId);
}
function sendPayload(payload: InternalEventPayload, replyId: string | null): string {
const event = buildEventToSend(payload, replyId);
sendEvent(event);
return event.id;
}
function sendEvent(event: InternalEvent) {
if (event.payload.type !== 'empty_response') {
console.log('Sending event to app', event.id, event.payload.type);
}
parentPort!.postMessage(event);
}
async function sendAndWaitForReply<T extends Omit<InternalEventPayload, 'type'>>(
payload: InternalEventPayload,
): Promise<T> {
// 1. Build event to send
const eventToSend = buildEventToSend(payload, null);
// 2. Spawn listener in background
const promise = new Promise<InternalEventPayload>(async (resolve) => {
const cb = (event: InternalEvent) => {
if (event.replyId === eventToSend.id) {
parentPort!.off('message', cb); // Unlisten, now that we're done
resolve(event.payload); // Not type-safe but oh well
}
};
parentPort!.on('message', cb);
});
// 3. Send the event after we start listening (to prevent race)
sendEvent(eventToSend);
// 4. Return the listener promise
return promise as unknown as Promise<T>;
}
const ctx: Context = {
clipboard: {
async copyText(text) {
await sendAndWaitForReply({ type: 'copy_text_request', text });
},
},
toast: {
async show(args) {
await sendAndWaitForReply({ type: 'show_toast_request', ...args });
},
},
httpResponse: {
async find(args) {
const payload = { type: 'find_http_responses_request', ...args } as const;
const { httpResponses } = await sendAndWaitForReply<FindHttpResponsesResponse>(payload);
return httpResponses;
},
},
httpRequest: {
async getById(args) {
const payload = { type: 'get_http_request_by_id_request', ...args } as const;
const { httpRequest } = await sendAndWaitForReply<GetHttpRequestByIdResponse>(payload);
return httpRequest;
},
async send(args) {
const payload = { type: 'send_http_request_request', ...args } as const;
const { httpResponse } = await sendAndWaitForReply<SendHttpRequestResponse>(payload);
return httpResponse;
},
async render(args) {
const payload = { type: 'render_http_request_request', ...args } as const;
const result = await sendAndWaitForReply<RenderHttpRequestResponse>(payload);
return result.httpRequest;
},
},
};
// Message comes into the plugin to be processed
parentPort!.on('message', async ({ payload, id: replyId }: InternalEvent) => {
try {
if (payload.type === 'boot_request') {
const payload: InternalEventPayload = {
type: 'boot_response',
name: pkg.name,
version: pkg.version,
capabilities,
};
sendPayload(payload, replyId);
return;
}
if (payload.type === 'import_request' && typeof mod.pluginHookImport === 'function') {
const reply: ImportResponse | null = await mod.pluginHookImport(ctx, payload.content);
if (reply != null) {
const replyPayload: InternalEventPayload = {
type: 'import_response',
resources: reply?.resources,
};
sendPayload(replyPayload, replyId);
return;
} else {
// Continue, to send back an empty reply
}
}
if (
payload.type === 'export_http_request_request' &&
typeof mod.pluginHookExport === 'function'
) {
const reply: string = await mod.pluginHookExport(ctx, payload.httpRequest);
const replyPayload: InternalEventPayload = {
type: 'export_http_request_response',
content: reply,
};
sendPayload(replyPayload, replyId);
return;
}
if (payload.type === 'filter_request' && typeof mod.pluginHookResponseFilter === 'function') {
const reply: string = await mod.pluginHookResponseFilter(ctx, {
filter: payload.filter,
body: payload.content,
});
const replyPayload: InternalEventPayload = {
type: 'filter_response',
content: reply,
};
sendPayload(replyPayload, replyId);
return;
}
if (
payload.type === 'get_http_request_actions_request' &&
Array.isArray(mod.plugin?.httpRequestActions)
) {
const reply: HttpRequestAction[] = mod.plugin.httpRequestActions.map(
(a: HttpRequestActionPlugin) => ({
...a,
// Add everything except onSelect
onSelect: undefined,
}),
);
const replyPayload: InternalEventPayload = {
type: 'get_http_request_actions_response',
pluginRefId,
actions: reply,
};
sendPayload(replyPayload, replyId);
return;
}
if (
payload.type === 'get_template_functions_request' &&
Array.isArray(mod.plugin?.templateFunctions)
) {
const reply: TemplateFunction[] = mod.plugin.templateFunctions.map(
(a: TemplateFunctionPlugin) => ({
...a,
// Add everything except render
onRender: undefined,
}),
);
const replyPayload: InternalEventPayload = {
type: 'get_template_functions_response',
pluginRefId,
functions: reply,
};
sendPayload(replyPayload, replyId);
return;
}
if (
payload.type === 'call_http_request_action_request' &&
Array.isArray(mod.plugin?.httpRequestActions)
) {
const action = mod.plugin.httpRequestActions.find((a) => a.key === payload.key);
if (typeof action?.onSelect === 'function') {
await action.onSelect(ctx, payload.args);
sendEmpty(replyId);
return;
}
}
if (
payload.type === 'call_template_function_request' &&
Array.isArray(mod.plugin?.templateFunctions)
) {
const action = mod.plugin.templateFunctions.find((a) => a.name === payload.name);
if (typeof action?.onRender === 'function') {
const result = await action.onRender(ctx, payload.args);
sendPayload({ type: 'call_template_function_response', value: result ?? null }, replyId);
return;
}
}
} catch (err) {
console.log('Plugin call threw exception', payload.type, err);
// TODO: Return errors to server
}
// No matches, so send back an empty response so the caller doesn't block forever
sendEmpty(replyId);
});
resolve();
}).catch((err) => {
console.log('failed to boot plugin', err);
});
function genId(len = 5): string {
const alphabet = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let id = '';
for (let i = 0; i < len; i++) {
id += alphabet[Math.floor(Math.random() * alphabet.length)];
}
return id;
}
function prefixStdout(s: string) {
if (!s.includes('%s')) {
throw new Error('Console prefix must contain a "%s" replacer');
}
interceptStdout((text) => {
const lines = text.split(/\n/);
let newText = '';
for (let i = 0; i < lines.length; i++) {
if (lines[i] == '') continue;
newText += util.format(s, lines[i]) + '\n';
}
return newText.trimEnd();
});
}

View File

@@ -0,0 +1,24 @@
{
"compilerOptions": {
"module": "node16",
"strict": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es2021",
"lib": ["es2021"],
"noImplicitAny": false,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*",
"src/types/*"
]
}
},
"include": [
"src/**/*"
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
{
"name": "exporter-curl",
"version": "0.0.1",
"devDependencies": {
"vitest": "^1.4.0"
}
}

View File

@@ -1,76 +0,0 @@
import { HttpRequest } from '../../../src-web/lib/models';
const NEWLINE = '\\\n ';
export function pluginHookExport(_: any, request: Partial<HttpRequest>) {
const xs = ['curl'];
// Add method and URL all on first line
if (request.method) xs.push('-X', request.method);
if (request.url) xs.push(quote(request.url));
xs.push(NEWLINE);
// Add URL params
for (const p of (request.urlParameters ?? []).filter(onlyEnabled)) {
xs.push('--url-query', quote(`${p.name}=${p.value}`));
xs.push(NEWLINE);
}
// Add headers
for (const h of (request.headers ?? []).filter(onlyEnabled)) {
xs.push('--header', quote(`${h.name}: ${h.value}`));
xs.push(NEWLINE);
}
// Add form params
if (Array.isArray(request.body?.form)) {
const flag = request.bodyType === 'multipart/form-data' ? '--form' : '--data';
for (const p of (request.body?.form ?? []).filter(onlyEnabled)) {
if (p.file) {
let v = `${p.name}=@${p.file}`;
v += p.contentType ? `;type=${p.contentType}` : '';
xs.push(flag, v);
} else {
xs.push(flag, quote(`${p.name}=${p.value}`));
}
xs.push(NEWLINE);
}
} else if (typeof request.body?.text === 'string') {
// --data-raw $'...' to do special ANSI C quoting
xs.push('--data-raw', `$${quote(request.body.text)}`);
xs.push(NEWLINE);
}
// Add basic/digest authentication
if (request.authenticationType === 'basic' || request.authenticationType === 'digest') {
if (request.authenticationType === 'digest') xs.push('--digest');
xs.push(
'--user',
quote(`${request.authentication?.username ?? ''}:${request.authentication?.password ?? ''}`),
);
xs.push(NEWLINE);
}
// Add bearer authentication
if (request.authenticationType === 'bearer') {
xs.push('--header', quote(`Authorization: Bearer ${request.authentication?.token ?? ''}`));
xs.push(NEWLINE);
}
// Remove trailing newline
if (xs[xs.length - 1] === NEWLINE) {
xs.splice(xs.length - 1, 1);
}
return xs.join(' ');
}
function quote(arg: string): string {
const escaped = arg.replace(/'/g, "\\'");
return `'${escaped}'`;
}
function onlyEnabled(v: { name?: string; enabled?: boolean }): boolean {
return v.enabled !== false && !!v.name;
}

Some files were not shown because too many files have changed in this diff Show More