Compare commits

...

196 Commits

Author SHA1 Message Date
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
Gregory Schier
65e7c804d7 Parse window title and theme better 2024-06-12 10:15:14 -07:00
Gregory Schier
23ec8bee8f Move binary detection to TextViewer 2024-06-12 09:47:34 -07:00
Gregory Schier
8aeeaa2e09 Bump version 2024-06-12 00:23:50 -07:00
Gregory Schier
57f01d249e Entitlement for v8/Deno 2024-06-12 00:23:32 -07:00
Gregory Schier
6c5a914db6 Variables in pair editor 2024-06-11 12:33:43 -07:00
Gregory Schier
155e51aa74 Put toast on top 2024-06-11 12:04:46 -07:00
Gregory Schier
012a984456 Fix bulk edit label 2024-06-11 09:02:11 -07:00
Gregory Schier
25800202f2 Bump version 2024-06-11 08:35:29 -07:00
Gregory Schier
a058064f1f Adjust fuzzy threshold 2024-06-10 23:25:57 -07:00
Gregory Schier
9f40804532 Fix window drag above cmd+k 2024-06-10 23:24:03 -07:00
Gregory Schier
26cc467858 Fix delete request in sidebar 2024-06-10 23:17:12 -07:00
Gregory Schier
be1cf7bf65 Don't arrow-nav to hidden dropdown items 2024-06-10 23:16:37 -07:00
Gregory Schier
ea4f104ca7 Bulk edit environments 2024-06-10 23:16:21 -07:00
Gregory Schier
32a28a3170 Fix hotkey react keys 2024-06-10 22:29:06 -07:00
Gregory Schier
6215914212 Cmd Palette Improvements (#50)
- Fuzzy matching
- Show hotkeys
- Add actions
2024-06-10 21:37:41 -07:00
Gregory Schier
a2dbd7f849 Download Active Response (#49)
This PR prompts you to save un-previewable file types and adds an option
to save to the response history.
2024-06-10 16:36:09 -07:00
Gregory Schier
5bb9815f4b Remove jump to request hotkey 2024-06-10 09:00:26 -07:00
Gregory Schier
7cd8ac3b21 Response viewer for PDF (#48)
This PR adds a response viewer for PDF files using `react-pdf`
2024-06-10 08:57:08 -07:00
Gregory Schier
456d3aaf52 Don't focus sidebar on cmd+0 2024-06-09 08:36:12 -07:00
Gregory Schier
113743f7cf Try fix CI 2024-06-09 08:09:47 -07:00
Gregory Schier
01a4d6f4ac Bump version 2024-06-09 07:56:44 -07:00
Gregory Schier
ff5cfe744e Remove CI again 2024-06-09 07:56:09 -07:00
Gregory Schier
29c4b51f54 Add it back 2024-06-09 07:23:28 -07:00
Gregory Schier
2f74bf8db8 Remove CI in release stage 2024-06-09 07:22:49 -07:00
Gregory Schier
b30d784d06 Remove GH Action step names 2024-06-09 07:16:53 -07:00
Gregory Schier
ac0adaf3d8 Back to other 2024-06-09 07:14:07 -07:00
Gregory Schier
c246d3a748 Fix action step 2024-06-09 07:10:44 -07:00
Gregory Schier
ae40728c1e Rust cache release 2024-06-09 07:09:46 -07:00
Gregory Schier
0430ec883b Cmd jump to request 2024-06-09 07:03:16 -07:00
Gregory Schier
eba6f33536 Only CI on PR 2024-06-09 06:47:47 -07:00
Gregory Schier
dae2873376 Fix Rust lint 2024-06-09 06:43:53 -07:00
Gregory Schier
cb2f56d9a1 Remove slow udeps from CI 2024-06-08 21:03:17 -07:00
Gregory Schier
7d82aa70a4 Rust CI to release 2024-06-08 20:51:03 -07:00
Gregory Schier
adea234987 Try again 2024-06-08 20:47:48 -07:00
Gregory Schier
37d0b487b8 Remove cache 2024-06-08 20:47:18 -07:00
Gregory Schier
d507f8c99f Try removing git db 2024-06-08 20:44:58 -07:00
Gregory Schier
60406ac83f Cargo check 2024-06-08 20:36:56 -07:00
Gregory Schier
8fe6f3a335 Remove Cargo fmt 2024-06-08 20:34:24 -07:00
Gregory Schier
69e027c302 Fix tests 2024-06-08 20:30:52 -07:00
Gregory Schier
4232bdd298 Cargo format 2024-06-08 20:28:45 -07:00
Gregory Schier
ef1c5da027 Set max dropdown width 2024-06-08 19:55:25 -07:00
Gregory Schier
e250326868 Bump version 2024-06-08 19:46:32 -07:00
Gregory Schier
125f503cfa Upgrade reqwest and add ALPN for http/2 2024-06-08 19:40:35 -07:00
Gregory Schier
8f086425fe Fix curl exporter 2024-06-08 19:40:11 -07:00
Gregory Schier
ae2da73873 Fix cmd+k filtering 2024-06-07 22:52:23 -07:00
Gregory Schier
3cd6688ffb Remove delete hotkey for request 2024-06-07 22:52:10 -07:00
Gregory Schier
8538da8879 Short method tags and hide active in cmd+k 2024-06-07 22:39:11 -07:00
Gregory Schier
b0e4ece278 Add command palette (#46)
This PR finished the initial PoC command palette. It currently only
supports switching between requests and workspaces, but can easily be
extended for more.
2024-06-07 21:59:57 -07:00
Gregory Schier
5e058af03e Bulk editor (#45)
Bulk editor for all pair editors except multipart/form-data
2024-06-07 13:42:08 -07:00
Gregory Schier
5108bc92f3 Fix rose pine and method tags 2024-06-07 12:01:31 -07:00
Gregory Schier
3c5fdcb18d Generate things 2024-06-07 11:58:08 -07:00
Gregory Schier
4672de4a47 Remove tauri-plugin-deep-link 2024-06-07 11:57:44 -07:00
Gregory Schier
239f6da141 Update CI script 2024-06-07 11:01:21 -07:00
Gregory Schier
ec148d1736 Fix workflow 2024-06-07 10:54:50 -07:00
Gregory Schier
392b549646 Deno plugins (#42)
Switch from BoaJS to Deno core
2024-06-07 10:47:41 -07:00
Gregory Schier
993d4dc65d Open workspace pref (#44)
Ability to remember workspace window opening selection.
2024-06-07 09:04:53 -07:00
Gregory Schier
e326405f4f Templating (#43)
Add new `templating` crate with custom parser/renderer for dealing with
variables
2024-06-07 08:39:12 -07:00
Gregory Schier
a83e094f00 Fix copy-as-curl variables 2024-06-05 06:53:38 -07:00
Gregory Schier
e683a2cb2a Bump version 2024-06-04 23:53:45 -07:00
Gregory Schier
1f231c2722 Only release on tag again 2024-06-04 23:53:31 -07:00
Gregory Schier
0fc2575ef6 Fix default workspace settings on initial Workspace 2024-06-04 17:06:40 -07:00
Gregory Schier
44c718e6bc Better analytics error log 2024-06-04 16:27:22 -07:00
Gregory Schier
495df847ab Merge branch 'beta' into master 2024-06-04 15:01:55 -07:00
Gregory Schier
5dbb9852f3 Bump version 2024-06-04 15:00:34 -07:00
Gregory Schier
82d3304c38 Hopefully fix AppImage build not finding migrations. I think it was because the productName had a capital Yaak in it. 2024-06-04 14:59:40 -07:00
Gregory Schier
5e2218fd64 Remove Windows plugin 2024-06-04 02:56:52 -07:00
Gregory Schier
5b12fad173 2024.5.0-beta.2 (#38) 2024-06-03 14:03:25 -07:00
Gregory Schier
8d6f23eacb Bump version 2024-06-03 14:00:49 -07:00
Gregory Schier
75a09859bc Move Postman to first plugin 2024-06-03 14:00:40 -07:00
Gregory Schier
dc47c4ceba Preserve JSON/XPath filter (Closes #22) 2024-06-03 13:49:51 -07:00
Gregory Schier
8ae0290aed Don't send request on completion (Fixes #27) 2024-06-03 07:49:13 -07:00
Gregory Schier
f01d1e704b Don't always change request method. Closes #29 2024-06-03 07:26:40 -07:00
Gregory Schier
3f72996e64 Tweak settings labels 2024-06-02 23:54:00 -07:00
Gregory Schier
fe862517fb Fix dropdown icon color 2024-06-02 23:50:26 -07:00
Gregory Schier
b39335dc4f Don't call is_fullscreen so much 2024-06-02 23:38:56 -07:00
Gregory Schier
8f3bdb5039 Fix autocomplete for environment editor names 2024-06-02 17:52:51 -07:00
Gregory Schier
b47ec01f9c <Select> uses custom component on Windows 2024-06-02 16:57:23 -07:00
Gregory Schier
36728d1d1f Tweak Moonlight theme 2024-06-02 15:48:27 -07:00
Gregory Schier
c3f0351445 Fix font size 2024-06-02 11:53:41 -07:00
Gregory Schier
9a5364187c Better invalid URL errors 2024-06-02 11:53:35 -07:00
Gregory Schier
a9db14994f Import content-type from Postman multi-part form 2024-06-02 11:53:25 -07:00
Gregory Schier
2383e8468f Also release on beta branch 2024-05-31 10:37:21 -07:00
Gregory Schier
a79d485b6a Bump version 2024-05-31 09:46:57 -07:00
Gregory Schier
7eb931d689 Fix multipart files 2024-05-31 09:32:16 -07:00
Gregory Schier
995cd2aa7b Fade in window contents (Layout) 2024-05-31 09:16:52 -07:00
Gregory Schier
1ce50e0c1b Window border on Linux 2024-05-31 08:43:35 -07:00
Gregory Schier
bce3d26a1a Try tweaking settings/theme for Windows. Setting the theme didn't work. 2024-05-30 23:38:49 -07:00
Gregory Schier
d9680ad0fa Ignore stoplights when centering settings title 2024-05-30 12:33:59 -07:00
Gregory Schier
e2e026e1ff Tweak appearance settings 2024-05-30 12:32:12 -07:00
Gregory Schier
16739d9a37 Dracula theme 2024-05-30 11:56:57 -07:00
Gregory Schier
524a4f2275 Tweak 2024-05-30 11:45:40 -07:00
Gregory Schier
ba66883dc2 Theme analytics and Moonlight 2024-05-30 11:00:50 -07:00
Gregory Schier
2caa735a2e Tweak settings for release 2024-05-30 10:28:59 -07:00
Gregory Schier
90637fda6b Unlisten to window event and fix hotkeys 2024-05-30 00:29:01 -07:00
Gregory Schier
2cef46b46a Window title working again 2024-05-30 00:11:55 -07:00
Gregory Schier
14b3abf76c Fix window stoplights 2024-05-29 22:59:34 -07:00
Gregory Schier
8cd3961f87 Custom font sizes and better zoom 2024-05-29 12:10:01 -07:00
Gregory Schier
5eb2e2b5a2 Merge branch 'refs/heads/release'
# Conflicts:
#	src-tauri/src/updates.rs
2024-05-26 09:11:29 -07:00
Gregory Schier
5dd897e042 Initial handler for yaak:// protocol 2024-05-26 08:45:15 -07:00
Gregory Schier
9c77ec296d Better theme export 2024-05-24 18:54:30 -07:00
Gregory Schier
696e72323b More theme stuff 2024-05-24 17:36:48 -07:00
Gregory Schier
3e8c01f436 Tweak themes 2024-05-23 10:16:29 -07:00
Gregory Schier
80fc4dec09 Hotdog stand 2024-05-23 10:14:07 -07:00
Gregory Schier
671885fc8c More themes! 2024-05-23 09:40:11 -07:00
Gregory Schier
002b61f0d7 Set window title on Mac 2024-05-23 09:40:00 -07:00
Gregory Schier
d32b462bd9 More tweaks 2024-05-22 23:44:47 -07:00
Gregory Schier
5c8b47288a Tweak Yaak default themes 2024-05-22 23:28:53 -07:00
Gregory Schier
8e662e6feb A bunch more theme stuff 2024-05-22 23:14:53 -07:00
Gregory Schier
83aaeb94f6 Theme system refactor (#31) 2024-05-21 17:56:06 -07:00
Gregory Schier
8606940dee Move is_dev check for updates 2024-05-16 10:28:25 -07:00
Gregory Schier
57d548743f Merge remote-tracking branch 'refs/remotes/origin/release'
# Conflicts:
#	src-tauri/tauri.conf.json
2024-05-14 15:35:33 -07:00
Gregory Schier
dab7ee2492 Bump version 2024-05-14 15:34:34 -07:00
Gregory Schier
9360fd7e43 Oops 2024-05-14 15:33:27 -07:00
Gregory Schier
0f7969d10a Fix maximize permission 2024-05-14 14:54:09 -07:00
Gregory Schier
6b373b5985 Fix autocomplete 2024-05-14 14:47:33 -07:00
380 changed files with 20919 additions and 29617 deletions

View File

@@ -12,7 +12,7 @@ module.exports = {
parserOptions: {
project: ["./tsconfig.json"]
},
ignorePatterns: ["src-tauri/**/*", "plugins/**/*"],
ignorePatterns: ["scripts/**/*", "plugin-runtime/**/*", "src-tauri/**/*", "plugins/**/*", "checkout/**/*"],
settings: {
react: {
version: "detect"

18
.github/workflows/ci-js.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
on:
pull_request:
branches: [develop]
name: CI (JS)
jobs:
test:
name: Lint/Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run lint
- run: npm test

36
.github/workflows/ci-rust.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
on:
pull_request:
branches: [develop]
paths:
- src-tauri/**
- .github/workflows/**
name: CI (Rust)
defaults:
run:
working-directory: src-tauri
jobs:
test:
name: Check/Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev
- uses: dtolnay/rust-toolchain@stable
- uses: actions/cache@v3
continue-on-error: false
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
- run: cargo check --all
- run: cargo test --all

View File

@@ -1,50 +1,109 @@
name: Generate Artifacts
on:
push:
branches:
- release
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.
node_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.
node_arch: 'x64'
- platform: 'ubuntu-22.04' # for Tauri v1, you could replace this with ubuntu-20.04.
args: ''
node_arch: 'x64'
- platform: 'windows-latest'
args: ''
node_arch: 'x64'
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- name: setup node
- name: Checkout yaakapp/app
uses: actions/checkout@v4
- name: Checkout yaakapp/plugins
uses: actions/checkout@v4
with:
repository: yaakapp/plugins
path: ${{ env.YAAK_PLUGINS_DIR }}
- 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:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
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.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
# webkitgtk 4.0 is for Tauri v1 - webkitgtk 4.1 is for Tauri v2.
# You can remove the one that doesn't apply to your app to speed up the workflow a bit.
- name: Install dependencies
run: npm ci
sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
- 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: 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 }}
NODE_ARCH: ${{ matrix.node_arch }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}

5
.gitignore vendored
View File

@@ -27,4 +27,7 @@ dist-ssr
*.sqlite
*.sqlite-*
.cargo
.cargo
.tmp
tmp

View File

@@ -1 +0,0 @@
plugins

Binary file not shown.

View File

@@ -1,27 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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: black;
}
@media (prefers-color-scheme: dark) {
html, body {
background-color: #1b1a29;
}
}
</style>
</head>
<body>
<body class="text-base">
<div id="root"></div>
<div id="cm-portal" class="cm-portal"></div>
<div id="react-portal"></div>

1459
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,32 +4,29 @@
"version": "0.0.0",
"type": "module",
"scripts": {
"start": "npm run build:plugins && npm run tauri-dev:desktop",
"start": "npm run tauri-dev:desktop",
"tauri-dev:desktop": "tauri dev --no-watch --config ./src-tauri/tauri-dev.conf.json",
"tauri-dev:ios": "tauri ios dev --no-watch --config ./src-tauri/tauri-dev.conf.json",
"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: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",
"build": "run-p build:*",
"build:js": "vite 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",
"build:plugin-runtime": "npm run --prefix plugin-runtime build",
"test": "vitest",
"coverage": "vitest run --coverage",
"prepare": "husky install"
"prepare": "husky install",
"replace-version": "node scripts/replace-version.cjs"
},
"dependencies": {
"@codemirror/commands": "^6.2.1",
"@codemirror/lang-javascript": "^6.1.4",
"@codemirror/lang-javascript": "^6.2.2",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-xml": "^6.0.2",
"@codemirror/language": "^6.6.0",
@@ -39,7 +36,7 @@
"@lezer/lr": "^1.3.3",
"@react-hook/resize-observer": "^1.2.6",
"@tailwindcss/container-queries": "^0.1.0",
"@tanstack/react-query": "^5.35.5",
"@tanstack/react-query": "^5.45.1",
"@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",
@@ -52,6 +49,7 @@
"codemirror": "^6.0.1",
"codemirror-json-schema": "^0.6.1",
"date-fns": "^3.3.1",
"fast-fuzzy": "^1.12.0",
"focus-trap-react": "^10.1.1",
"format-graphql": "^1.4.0",
"framer-motion": "^9.0.4",
@@ -64,6 +62,7 @@
"react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0",
"react-pdf": "^9.0.0",
"react-router-dom": "^6.8.1",
"react-use": "^17.4.0",
"slugify": "^1.6.6",
@@ -73,7 +72,7 @@
},
"devDependencies": {
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
"@tanstack/react-query-devtools": "^5.35.5",
"@tanstack/react-query-devtools": "^5.45.1",
"@tauri-apps/cli": ">=2.0.0-beta.0",
"@types/node": "^18.7.10",
"@types/papaparse": "^5.3.7",
@@ -101,8 +100,12 @@
"prettier": "^2.8.4",
"react-devtools": "^4.27.2",
"tailwindcss": "^3.2.7",
"typescript": "^5.3.3",
"typescript": "^5.4.5",
"vite": "^5.0.0",
"vite-plugin-static-copy": "^1.0.5",
"decompress": "^4.2.1",
"nodejs-file-downloader": "^4.13.0",
"rimraf": "^5.0.7",
"vite-plugin-svgr": "^4.2.0",
"vite-plugin-top-level-await": "^1.4.1",
"vitest": "^1.3.0"

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"
}

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"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": {
"long": "^5.2.3",
"nice-grpc": "^2.1.9",
"protobufjs": "^7.3.2"
},
"devDependencies": {
"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,92 @@
import { randomUUID } from 'node:crypto';
import path from 'node:path';
import { Worker } from 'node:worker_threads';
import { PluginInfo } from './plugins';
export interface ParentToWorkerEvent<T = any> {
callbackId: string;
name: string;
payload: T;
}
export type WorkerToParentSuccessEvent<T> = {
callbackId: string;
payload: T;
};
export type WorkerToParentErrorEvent = {
callbackId: string;
error: string;
};
export type WorkerToParentEvent<T = any> = WorkerToParentErrorEvent | WorkerToParentSuccessEvent<T>;
export class PluginHandle {
readonly pluginDir: string;
readonly #worker: Worker;
constructor(pluginDir: string) {
this.pluginDir = pluginDir;
const workerPath = path.join(__dirname, 'index.worker.cjs');
this.#worker = new Worker(workerPath, {
workerData: {
pluginDir: this.pluginDir,
},
});
this.#worker.on('error', this.#handleError.bind(this));
this.#worker.on('exit', this.#handleExit.bind(this));
}
async getInfo(): Promise<PluginInfo> {
return this.#callPlugin('info', null);
}
async runResponseFilter({ filter, body }: { filter: string; body: string }): Promise<string> {
return this.#callPlugin('run-filter', { filter, body });
}
async runExport(request: any): Promise<string> {
return this.#callPlugin('run-export', request);
}
async runImport(data: string): Promise<string> {
const result = await this.#callPlugin('run-import', data);
// Plugin returns object, but we convert to string
return JSON.stringify(result, null, 2);
}
#callPlugin<P, R>(name: string, payload: P): Promise<R> {
const callbackId = `cb_${randomUUID().replaceAll('-', '')}`;
return new Promise((resolve, reject) => {
const cb = (e: WorkerToParentEvent<R>) => {
if (e.callbackId !== callbackId) return;
if ('error' in e) {
reject(e.error);
} else {
resolve(e.payload as R);
}
this.#worker.removeListener('message', cb);
};
this.#worker.addListener('message', cb);
this.#worker.postMessage({ callbackId, name, payload });
});
}
async #handleError(err: Error) {
console.error('PLUGIN ERROR', this.pluginDir, err);
}
async #handleExit(code: number) {
if (code === 0) {
console.log('PLUGIN EXITED SUCCESSFULLY');
} else {
console.log('PLUGIN EXITED CODE', code);
}
}
}

View File

@@ -0,0 +1,44 @@
import { PluginHandle } from './PluginHandle';
import { loadPlugins, PluginInfo } from './plugins';
export class PluginManager {
#handles: PluginHandle[] | null = null;
static #instance: PluginManager | null = null;
public static instance(): PluginManager {
if (PluginManager.#instance == null) {
PluginManager.#instance = new PluginManager();
PluginManager.#instance.plugins(); // Trigger workers to boot, as it takes a few seconds
}
return PluginManager.#instance;
}
async plugins(): Promise<PluginHandle[]> {
this.#handles = this.#handles ?? loadPlugins();
return this.#handles;
}
async #pluginsWithInfo(): Promise<{ plugin: PluginHandle; info: PluginInfo }[]> {
const plugins = await this.plugins();
return Promise.all(plugins.map(async (plugin) => ({ plugin, info: await plugin.getInfo() })));
}
async pluginsWith(capability: PluginInfo['capabilities'][0]): Promise<PluginHandle[]> {
return (await this.#pluginsWithInfo())
.filter((v) => v.info.capabilities.includes(capability))
.map((v) => v.plugin);
}
async plugin(name: string): Promise<PluginHandle | null> {
return (await this.#pluginsWithInfo()).find((v) => v.info.name === name)?.plugin ?? null;
}
async pluginOrThrow(name: string): Promise<PluginHandle> {
const plugin = await this.plugin(name);
if (plugin == null) {
throw new Error(`Failed to find plugin by ${name}`);
}
return plugin;
}
}

View File

@@ -0,0 +1,432 @@
// 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 PluginInfo {
plugin: string;
}
export interface HookResponse {
info: PluginInfo | undefined;
data: string;
}
export interface HookImportRequest {
data: string;
}
export interface HookResponseFilterRequest {
filter: string;
body: string;
contentType: string;
}
export interface HookExportRequest {
request: string;
}
function createBasePluginInfo(): PluginInfo {
return { plugin: "" };
}
export const PluginInfo = {
encode(message: PluginInfo, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.plugin !== "") {
writer.uint32(10).string(message.plugin);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): PluginInfo {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBasePluginInfo();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.plugin = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): PluginInfo {
return { plugin: isSet(object.plugin) ? globalThis.String(object.plugin) : "" };
},
toJSON(message: PluginInfo): unknown {
const obj: any = {};
if (message.plugin !== "") {
obj.plugin = message.plugin;
}
return obj;
},
create(base?: DeepPartial<PluginInfo>): PluginInfo {
return PluginInfo.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<PluginInfo>): PluginInfo {
const message = createBasePluginInfo();
message.plugin = object.plugin ?? "";
return message;
},
};
function createBaseHookResponse(): HookResponse {
return { info: undefined, data: "" };
}
export const HookResponse = {
encode(message: HookResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.info !== undefined) {
PluginInfo.encode(message.info, writer.uint32(10).fork()).ldelim();
}
if (message.data !== "") {
writer.uint32(18).string(message.data);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): HookResponse {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseHookResponse();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.info = PluginInfo.decode(reader, reader.uint32());
continue;
case 2:
if (tag !== 18) {
break;
}
message.data = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): HookResponse {
return {
info: isSet(object.info) ? PluginInfo.fromJSON(object.info) : undefined,
data: isSet(object.data) ? globalThis.String(object.data) : "",
};
},
toJSON(message: HookResponse): unknown {
const obj: any = {};
if (message.info !== undefined) {
obj.info = PluginInfo.toJSON(message.info);
}
if (message.data !== "") {
obj.data = message.data;
}
return obj;
},
create(base?: DeepPartial<HookResponse>): HookResponse {
return HookResponse.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<HookResponse>): HookResponse {
const message = createBaseHookResponse();
message.info = (object.info !== undefined && object.info !== null)
? PluginInfo.fromPartial(object.info)
: undefined;
message.data = object.data ?? "";
return message;
},
};
function createBaseHookImportRequest(): HookImportRequest {
return { data: "" };
}
export const HookImportRequest = {
encode(message: HookImportRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.data !== "") {
writer.uint32(10).string(message.data);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): HookImportRequest {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseHookImportRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.data = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): HookImportRequest {
return { data: isSet(object.data) ? globalThis.String(object.data) : "" };
},
toJSON(message: HookImportRequest): unknown {
const obj: any = {};
if (message.data !== "") {
obj.data = message.data;
}
return obj;
},
create(base?: DeepPartial<HookImportRequest>): HookImportRequest {
return HookImportRequest.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<HookImportRequest>): HookImportRequest {
const message = createBaseHookImportRequest();
message.data = object.data ?? "";
return message;
},
};
function createBaseHookResponseFilterRequest(): HookResponseFilterRequest {
return { filter: "", body: "", contentType: "" };
}
export const HookResponseFilterRequest = {
encode(message: HookResponseFilterRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.filter !== "") {
writer.uint32(10).string(message.filter);
}
if (message.body !== "") {
writer.uint32(18).string(message.body);
}
if (message.contentType !== "") {
writer.uint32(26).string(message.contentType);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): HookResponseFilterRequest {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseHookResponseFilterRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.filter = reader.string();
continue;
case 2:
if (tag !== 18) {
break;
}
message.body = reader.string();
continue;
case 3:
if (tag !== 26) {
break;
}
message.contentType = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): HookResponseFilterRequest {
return {
filter: isSet(object.filter) ? globalThis.String(object.filter) : "",
body: isSet(object.body) ? globalThis.String(object.body) : "",
contentType: isSet(object.contentType) ? globalThis.String(object.contentType) : "",
};
},
toJSON(message: HookResponseFilterRequest): unknown {
const obj: any = {};
if (message.filter !== "") {
obj.filter = message.filter;
}
if (message.body !== "") {
obj.body = message.body;
}
if (message.contentType !== "") {
obj.contentType = message.contentType;
}
return obj;
},
create(base?: DeepPartial<HookResponseFilterRequest>): HookResponseFilterRequest {
return HookResponseFilterRequest.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<HookResponseFilterRequest>): HookResponseFilterRequest {
const message = createBaseHookResponseFilterRequest();
message.filter = object.filter ?? "";
message.body = object.body ?? "";
message.contentType = object.contentType ?? "";
return message;
},
};
function createBaseHookExportRequest(): HookExportRequest {
return { request: "" };
}
export const HookExportRequest = {
encode(message: HookExportRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer {
if (message.request !== "") {
writer.uint32(10).string(message.request);
}
return writer;
},
decode(input: _m0.Reader | Uint8Array, length?: number): HookExportRequest {
const reader = input instanceof _m0.Reader ? input : _m0.Reader.create(input);
let end = length === undefined ? reader.len : reader.pos + length;
const message = createBaseHookExportRequest();
while (reader.pos < end) {
const tag = reader.uint32();
switch (tag >>> 3) {
case 1:
if (tag !== 10) {
break;
}
message.request = reader.string();
continue;
}
if ((tag & 7) === 4 || tag === 0) {
break;
}
reader.skipType(tag & 7);
}
return message;
},
fromJSON(object: any): HookExportRequest {
return { request: isSet(object.request) ? globalThis.String(object.request) : "" };
},
toJSON(message: HookExportRequest): unknown {
const obj: any = {};
if (message.request !== "") {
obj.request = message.request;
}
return obj;
},
create(base?: DeepPartial<HookExportRequest>): HookExportRequest {
return HookExportRequest.fromPartial(base ?? {});
},
fromPartial(object: DeepPartial<HookExportRequest>): HookExportRequest {
const message = createBaseHookExportRequest();
message.request = object.request ?? "";
return message;
},
};
export type PluginRuntimeDefinition = typeof PluginRuntimeDefinition;
export const PluginRuntimeDefinition = {
name: "PluginRuntime",
fullName: "yaak.plugins.runtime.PluginRuntime",
methods: {
hookImport: {
name: "hookImport",
requestType: HookImportRequest,
requestStream: false,
responseType: HookResponse,
responseStream: false,
options: {},
},
hookResponseFilter: {
name: "hookResponseFilter",
requestType: HookResponseFilterRequest,
requestStream: false,
responseType: HookResponse,
responseStream: false,
options: {},
},
hookExport: {
name: "hookExport",
requestType: HookExportRequest,
requestStream: false,
responseType: HookResponse,
responseStream: false,
options: {},
},
},
} as const;
export interface PluginRuntimeServiceImplementation<CallContextExt = {}> {
hookImport(request: HookImportRequest, context: CallContext & CallContextExt): Promise<DeepPartial<HookResponse>>;
hookResponseFilter(
request: HookResponseFilterRequest,
context: CallContext & CallContextExt,
): Promise<DeepPartial<HookResponse>>;
hookExport(request: HookExportRequest, context: CallContext & CallContextExt): Promise<DeepPartial<HookResponse>>;
}
export interface PluginRuntimeClient<CallOptionsExt = {}> {
hookImport(request: DeepPartial<HookImportRequest>, options?: CallOptions & CallOptionsExt): Promise<HookResponse>;
hookResponseFilter(
request: DeepPartial<HookResponseFilterRequest>,
options?: CallOptions & CallOptionsExt,
): Promise<HookResponse>;
hookExport(request: DeepPartial<HookExportRequest>, options?: CallOptions & CallOptionsExt): Promise<HookResponse>;
}
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;
}

View File

@@ -0,0 +1,87 @@
import { isAbortError } from 'abort-controller-x';
import { createServer, ServerError, ServerMiddlewareCall, Status } from 'nice-grpc';
import { CallContext } from 'nice-grpc-common';
import * as fs from 'node:fs';
import {
DeepPartial,
HookExportRequest,
HookImportRequest,
HookResponse,
HookResponseFilterRequest,
PluginRuntimeDefinition,
PluginRuntimeServiceImplementation,
} from './gen/plugins/runtime';
import { PluginManager } from './PluginManager';
class PluginRuntimeService implements PluginRuntimeServiceImplementation {
#manager: PluginManager;
constructor() {
this.#manager = PluginManager.instance();
}
async hookExport(request: HookExportRequest): Promise<DeepPartial<HookResponse>> {
const plugin = await this.#manager.pluginOrThrow('exporter-curl');
const data = await plugin.runExport(JSON.parse(request.request));
const info = { plugin: (await plugin.getInfo()).name };
return { info, data };
}
async hookImport(request: HookImportRequest): Promise<DeepPartial<HookResponse>> {
const plugins = await this.#manager.pluginsWith('import');
for (const p of plugins) {
const data = await p.runImport(request.data);
if (data != null && data !== 'null') {
const info = { plugin: (await p.getInfo()).name };
return { info, data };
}
}
throw new ServerError(Status.UNKNOWN, 'No importers found for data');
}
async hookResponseFilter(request: HookResponseFilterRequest): Promise<DeepPartial<HookResponse>> {
const pluginName = request.contentType.includes('json') ? 'filter-jsonpath' : 'filter-xpath';
const plugin = await this.#manager.pluginOrThrow(pluginName);
const data = await plugin.runResponseFilter(request);
const info = { plugin: (await plugin.getInfo()).name };
return { info, data };
}
}
let server = createServer();
async function* errorHandlingMiddleware<Request, Response>(
call: ServerMiddlewareCall<Request, Response>,
context: CallContext,
) {
try {
return yield* call.next(call.request, context);
} catch (error: unknown) {
if (error instanceof ServerError || isAbortError(error)) {
throw error;
}
let details = String(error);
if (process.env.NODE_ENV === 'development') {
// @ts-ignore
details += `: ${error.stack}`;
}
throw new ServerError(Status.UNKNOWN, details);
}
}
server = server.use(errorHandlingMiddleware);
server.add(PluginRuntimeDefinition, new PluginRuntimeService());
// Start on random port if YAAK_GRPC_PORT_FILE_PATH is set, or :4000
const addr = process.env.YAAK_GRPC_PORT_FILE_PATH ? 'localhost:0' : 'localhost:4000';
server.listen(addr).then((port) => {
console.log('gRPC server listening on', `http://localhost:${port}`);
if (process.env.YAAK_GRPC_PORT_FILE_PATH) {
console.log('Wrote port file to', process.env.YAAK_GRPC_PORT_FILE_PATH);
fs.writeFileSync(process.env.YAAK_GRPC_PORT_FILE_PATH, JSON.stringify({ port }, null, 2));
}
});

View File

@@ -0,0 +1,64 @@
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { parentPort, workerData } from 'node:worker_threads';
import { ParentToWorkerEvent } from './PluginHandle';
import { PluginInfo } from './plugins';
new Promise(async () => {
const { pluginDir } = workerData;
const pathMod = path.join(pluginDir, 'build/index.js');
const pathPkg = path.join(pluginDir, 'package.json');
const pkg = JSON.parse(readFileSync(pathPkg, 'utf8'));
const mod = (await import(`file://${pathMod}`)).default ?? {};
const info: PluginInfo = {
capabilities: [],
name: pkg['name'] ?? 'n/a',
dir: pluginDir,
};
if (typeof mod['pluginHookImport'] === 'function') {
info.capabilities.push('import');
}
if (typeof mod['pluginHookExport'] === 'function') {
info.capabilities.push('export');
}
if (typeof mod['pluginHookResponseFilter'] === 'function') {
info.capabilities.push('filter');
}
console.log('Loaded plugin', info.name, info.capabilities, info.dir);
function reply<T>(originalMsg: ParentToWorkerEvent, payload: T) {
parentPort!.postMessage({ payload, callbackId: originalMsg.callbackId });
}
function replyErr(originalMsg: ParentToWorkerEvent, error: unknown) {
parentPort!.postMessage({
error: String(error),
callbackId: originalMsg.callbackId,
});
}
parentPort!.on('message', (msg: ParentToWorkerEvent) => {
try {
const ctx = { todo: 'implement me' };
if (msg.name === 'run-import') {
reply(msg, mod.pluginHookImport(ctx, msg.payload));
} else if (msg.name === 'run-filter') {
reply(msg, mod.pluginHookResponseFilter(ctx, msg.payload));
} else if (msg.name === 'run-export') {
reply(msg, mod.pluginHookExport(ctx, msg.payload));
} else if (msg.name === 'info') {
reply(msg, info);
} else {
console.log('Unknown message', msg);
}
} catch (err: unknown) {
replyErr(msg, err);
}
});
}).catch((err) => console.log('failed to boot plugin', err));

View File

@@ -0,0 +1,18 @@
import * as fs from 'node:fs';
import path from 'node:path';
import { PluginHandle } from './PluginHandle';
export interface PluginInfo {
name: string;
dir: string;
capabilities: ('import' | 'export' | 'filter')[];
}
export function loadPlugins(): PluginHandle[] {
const pluginsDir = process.env.YAAK_PLUGINS_DIR;
if (!pluginsDir) throw new Error('PLUGINS_DIR is not set');
console.log('Loading plugins from', pluginsDir);
const pluginDirs = fs.readdirSync(pluginsDir).map((p) => path.join(pluginsDir, p));
return pluginDirs.map((pluginDir) => new PluginHandle(pluginDir));
}

View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "node16",
"strict": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"target": "es2021",
"lib": ["es2021"],
"noImplicitAny": false,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist",
"baseUrl": ".",
"skipLibCheck": true,
"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(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;
}

View File

@@ -1,175 +0,0 @@
import { describe, expect, test } from 'vitest';
import { pluginHookExport } from '../src';
describe('exporter-curl', () => {
test('Exports GET with params', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
urlParameters: [
{ name: 'a', value: 'aaa' },
{ name: 'b', value: 'bbb', enabled: true },
{ name: 'c', value: 'ccc', enabled: false },
],
}),
).toEqual(
[`curl 'https://yaak.app'`, `--url-query 'a=aaa'`, `--url-query 'b=bbb'`].join(` \\\n `),
);
});
test('Exports POST with url form data', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/x-www-form-urlencoded',
body: {
form: [
{ name: 'a', value: 'aaa' },
{ name: 'b', value: 'bbb', enabled: true },
{ name: 'c', value: 'ccc', enabled: false },
],
},
}),
).toEqual(
[`curl -X POST 'https://yaak.app'`, `--data 'a=aaa'`, `--data 'b=bbb'`].join(` \\\n `),
);
});
test('Exports PUT with multipart form', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
method: 'PUT',
bodyType: 'multipart/form-data',
body: {
form: [
{ name: 'a', value: 'aaa' },
{ name: 'b', value: 'bbb', enabled: true },
{ name: 'c', value: 'ccc', enabled: false },
{ name: 'f', file: '/foo/bar.png', contentType: 'image/png' },
],
},
}),
).toEqual(
[
`curl -X PUT 'https://yaak.app'`,
`--form 'a=aaa'`,
`--form 'b=bbb'`,
`--form f=@/foo/bar.png;type=image/png`,
].join(` \\\n `),
);
});
test('Exports JSON body', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/json',
body: {
text: `{"foo":"bar's"}`,
},
headers: [{ name: 'Content-Type', value: 'application/json' }],
}),
).toEqual(
[
`curl -X POST 'https://yaak.app'`,
`--header 'Content-Type: application/json'`,
`--data-raw $'{"foo":"bar\\'s"}'`,
].join(` \\\n `),
);
});
test('Exports multi-line JSON body', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
method: 'POST',
bodyType: 'application/json',
body: {
text: `{"foo":"bar",\n"baz":"qux"}`,
},
headers: [{ name: 'Content-Type', value: 'application/json' }],
}),
).toEqual(
[
`curl -X POST 'https://yaak.app'`,
`--header 'Content-Type: application/json'`,
`--data-raw $'{"foo":"bar",\n"baz":"qux"}'`,
].join(` \\\n `),
);
});
test('Exports headers', () => {
expect(
pluginHookExport({
headers: [
{ name: 'a', value: 'aaa' },
{ name: 'b', value: 'bbb', enabled: true },
{ name: 'c', value: 'ccc', enabled: false },
],
}),
).toEqual([`curl`, `--header 'a: aaa'`, `--header 'b: bbb'`].join(` \\\n `));
});
test('Basic auth', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
authenticationType: 'basic',
authentication: {
username: 'user',
password: 'pass',
},
}),
).toEqual([`curl 'https://yaak.app'`, `--user 'user:pass'`].join(` \\\n `));
});
test('Broken basic auth', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
authenticationType: 'basic',
authentication: {},
}),
).toEqual([`curl 'https://yaak.app'`, `--user ':'`].join(` \\\n `));
});
test('Digest auth', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
authenticationType: 'digest',
authentication: {
username: 'user',
password: 'pass',
},
}),
).toEqual([`curl 'https://yaak.app'`, `--digest --user 'user:pass'`].join(` \\\n `));
});
test('Bearer auth', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
authenticationType: 'bearer',
authentication: {
token: 'tok',
},
}),
).toEqual([`curl 'https://yaak.app'`, `--header 'Authorization: Bearer tok'`].join(` \\\n `));
});
test('Broken bearer auth', () => {
expect(
pluginHookExport({
url: 'https://yaak.app',
authenticationType: 'bearer',
authentication: {
username: 'user',
password: 'pass',
},
}),
).toEqual([`curl 'https://yaak.app'`, `--header 'Authorization: Bearer '`].join(` \\\n `));
});
});

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/exporter-curl'),
},
});

View File

@@ -1,173 +0,0 @@
{
"name": "filter-jsonpath",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "filter-jsonpath",
"version": "0.0.1",
"dependencies": {
"jsonpath": "^1.1.1"
}
},
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"node_modules/escodegen": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
"dependencies": {
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1"
},
"bin": {
"escodegen": "bin/escodegen.js",
"esgenerate": "bin/esgenerate.js"
},
"engines": {
"node": ">=4.0"
},
"optionalDependencies": {
"source-map": "~0.6.1"
}
},
"node_modules/escodegen/node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/esprima": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz",
"integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"engines": {
"node": ">=4.0"
}
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
"node_modules/jsonpath": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz",
"integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==",
"dependencies": {
"esprima": "1.2.2",
"static-eval": "2.0.2",
"underscore": "1.12.1"
}
},
"node_modules/levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
"dependencies": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"dependencies": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"optional": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/static-eval": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz",
"integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==",
"dependencies": {
"escodegen": "^1.8.1"
}
},
"node_modules/type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==",
"dependencies": {
"prelude-ls": "~1.1.2"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/underscore": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz",
"integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw=="
},
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"engines": {
"node": ">=0.10.0"
}
}
}
}

View File

@@ -1,7 +0,0 @@
{
"name": "filter-jsonpath",
"version": "0.0.1",
"dependencies": {
"jsonpath": "^1.1.1"
}
}

View File

@@ -1,12 +0,0 @@
import jp from 'jsonpath';
export function pluginHookResponseFilter(filter, text) {
let parsed;
try {
parsed = JSON.parse(text);
} catch (e) {
return;
}
const filtered = jp.query(parsed, filter);
return { filtered: JSON.stringify(filtered, null, 2) };
}

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/filter-jsonpath'),
},
});

View File

@@ -1,32 +0,0 @@
{
"name": "filter-xpath",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "filter-xpath",
"version": "0.0.1",
"dependencies": {
"@xmldom/xmldom": "^0.8.10",
"xpath": "^0.0.34"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
"integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/xpath": {
"version": "0.0.34",
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.34.tgz",
"integrity": "sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==",
"engines": {
"node": ">=0.6.0"
}
}
}
}

View File

@@ -1,8 +0,0 @@
{
"name": "filter-xpath",
"version": "0.0.1",
"dependencies": {
"@xmldom/xmldom": "^0.8.10",
"xpath": "^0.0.34"
}
}

View File

@@ -1,8 +0,0 @@
import xpath from 'xpath';
import { DOMParser } from '@xmldom/xmldom';
export function pluginHookResponseFilter(filter, text) {
const doc = new DOMParser().parseFromString(text, 'text/xml');
const filtered = `${xpath.select(filter, doc)}`;
return { filtered };
}

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.js'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/filter-xpath'),
},
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +0,0 @@
{
"name": "importer-curl",
"version": "0.0.1",
"dependencies": {
"shell-quote": "^1.8.1"
},
"devDependencies": {
"@types/shell-quote": "^1.7.5",
"vitest": "^1.4.0"
}
}

View File

@@ -1,421 +0,0 @@
import { ControlOperator, parse, ParseEntry } from 'shell-quote';
import {
Environment,
Folder,
HttpRequest,
HttpUrlParameter,
Model,
Workspace,
} from '../../../src-web/lib/models';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
interface ExportResources {
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 const id = 'curl';
export const name = 'cURL';
export const description = 'cURL command line tool';
const DATA_FLAGS = ['d', 'data', 'data-raw', 'data-urlencode', 'data-binary', 'data-ascii'];
const SUPPORTED_ARGS = [
['url'], // Specify the URL explicitly
['user', 'u'], // Authentication
['digest'], // Apply auth as digest
['header', 'H'],
['cookie', 'b'],
['get', 'G'], // Put the post data in the URL
['d', 'data'], // Add url encoded data
['data-raw'],
['data-urlencode'],
['data-binary'],
['data-ascii'],
['form', 'F'], // Add multipart data
['request', 'X'], // Request method
DATA_FLAGS,
].flatMap((v) => v);
type Pair = string | boolean;
type PairsByName = Record<string, Pair[]>;
export function pluginHookImport(rawData: string) {
if (!rawData.match(/^\s*curl /)) {
return null;
}
const commands: ParseEntry[][] = [];
// Replace non-escaped newlines with semicolons to make parsing easier
// NOTE: This is really slow in debug build but fast in release mode
const normalizedData = rawData.replace(/\ncurl/g, '; curl');
let currentCommand: ParseEntry[] = [];
const parsed = parse(normalizedData);
// Break up `-XPOST` into `-X POST`
const normalizedParseEntries = parsed.flatMap((entry) => {
if (
typeof entry === 'string' &&
entry.startsWith('-') &&
!entry.startsWith('--') &&
entry.length > 2
) {
return [entry.slice(0, 2), entry.slice(2)];
}
return entry;
});
for (const parseEntry of normalizedParseEntries) {
if (typeof parseEntry === 'string') {
if (parseEntry.startsWith('$')) {
currentCommand.push(parseEntry.slice(1));
} else {
currentCommand.push(parseEntry);
}
continue;
}
if ('comment' in parseEntry) {
continue;
}
const { op } = parseEntry as { op: 'glob'; pattern: string } | { op: ControlOperator };
// `;` separates commands
if (op === ';') {
commands.push(currentCommand);
currentCommand = [];
continue;
}
if (op?.startsWith('$')) {
// Handle the case where literal like -H $'Header: \'Some Quoted Thing\''
const str = op.slice(2, op.length - 1).replace(/\\'/g, "'");
currentCommand.push(str);
continue;
}
if (op === 'glob') {
currentCommand.push((parseEntry as { op: 'glob'; pattern: string }).pattern);
}
}
commands.push(currentCommand);
const workspace: ExportResources['workspaces'][0] = {
model: 'workspace',
id: generateId('workspace'),
name: 'Curl Import',
};
const requests: ExportResources['httpRequests'] = commands
.filter((command) => command[0] === 'curl')
.map((v) => importCommand(v, workspace.id));
return {
resources: {
httpRequests: requests,
workspaces: [workspace],
},
};
}
export function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
// ~~~~~~~~~~~~~~~~~~~~~ //
// Collect all the flags //
// ~~~~~~~~~~~~~~~~~~~~~ //
const pairsByName: PairsByName = {};
const singletons: ParseEntry[] = [];
// Start at 1 so we can skip the ^curl part
for (let i = 1; i < parseEntries.length; i++) {
let parseEntry = parseEntries[i];
if (typeof parseEntry === 'string') {
parseEntry = parseEntry.trim();
}
if (typeof parseEntry === 'string' && parseEntry.match(/^-{1,2}[\w-]+/)) {
const isSingleDash = parseEntry[0] === '-' && parseEntry[1] !== '-';
let name = parseEntry.replace(/^-{1,2}/, '');
if (!SUPPORTED_ARGS.includes(name)) {
continue;
}
let value;
const nextEntry = parseEntries[i + 1];
if (isSingleDash && name.length > 1) {
// Handle squished arguments like -XPOST
value = name.slice(1);
name = name.slice(0, 1);
} else if (typeof nextEntry === 'string' && !nextEntry.startsWith('-')) {
// Next arg is not a flag, so assign it as the value
value = nextEntry;
i++; // Skip next one
} else {
value = true;
}
pairsByName[name] = pairsByName[name] || [];
pairsByName[name]!.push(value);
} else if (parseEntry) {
singletons.push(parseEntry);
}
}
// ~~~~~~~~~~~~~~~~~ //
// Build the request //
// ~~~~~~~~~~~~~~~~~ //
// Url & parameters
let urlParameters: HttpUrlParameter[];
let url: string;
const urlArg = getPairValue(pairsByName, (singletons[0] as string) || '', ['url']);
const [baseUrl, search] = splitOnce(urlArg, '?');
urlParameters =
search?.split('&').map((p) => {
const v = splitOnce(p, '=');
return { name: v[0] ?? '', value: v[1] ?? '', enabled: true };
}) ?? [];
url = baseUrl ?? urlArg;
// Authentication
const [username, password] = getPairValue(pairsByName, '', ['u', 'user']).split(/:(.*)$/);
const isDigest = getPairValue(pairsByName, false, ['digest']);
const authenticationType = username ? (isDigest ? 'digest' : 'basic') : null;
const authentication = username
? {
username: username.trim(),
password: (password ?? '').trim(),
}
: {};
// Headers
const headers = [
...((pairsByName.header as string[] | undefined) || []),
...((pairsByName.H as string[] | undefined) || []),
].map((header) => {
const [name, value] = header.split(/:(.*)$/);
// remove final colon from header name if present
if (!value) {
return {
name: (name ?? '').trim().replace(/;$/, ''),
value: '',
enabled: true,
};
}
return {
name: (name ?? '').trim(),
value: value.trim(),
enabled: true,
};
});
// Cookies
const cookieHeaderValue = [
...((pairsByName.cookie as string[] | undefined) || []),
...((pairsByName.b as string[] | undefined) || []),
]
.map((str) => {
const name = str.split('=', 1)[0];
const value = str.replace(`${name}=`, '');
return `${name}=${value}`;
})
.join('; ');
// Convert cookie value to header
const existingCookieHeader = headers.find((header) => header.name.toLowerCase() === 'cookie');
if (cookieHeaderValue && existingCookieHeader) {
// Has existing cookie header, so let's update it
existingCookieHeader.value += `; ${cookieHeaderValue}`;
} else if (cookieHeaderValue) {
// No existing cookie header, so let's make a new one
headers.push({
name: 'Cookie',
value: cookieHeaderValue,
enabled: true,
});
}
///Body (Text or Blob)
const dataParameters = pairsToDataParameters(pairsByName);
const contentTypeHeader = headers.find((header) => header.name.toLowerCase() === 'content-type');
const mimeType = contentTypeHeader ? contentTypeHeader.value.split(';')[0] : null;
// Body (Multipart Form Data)
const formDataParams = [
...((pairsByName.form as string[] | undefined) || []),
...((pairsByName.F as string[] | undefined) || []),
].map((str) => {
const parts = str.split('=');
const name = parts[0] ?? '';
const value = parts[1] ?? '';
const item: { name: string; value?: string; file?: string; enabled: boolean } = {
name,
enabled: true,
};
if (value.indexOf('@') === 0) {
item.file = value.slice(1);
} else {
item.value = value;
}
return item;
});
// Body
let body = {};
let bodyType: string | null = null;
const bodyAsGET = getPairValue(pairsByName, false, ['G', 'get']);
if (dataParameters.length > 0 && bodyAsGET) {
urlParameters.push(...dataParameters);
} else if (
dataParameters.length > 0 &&
(mimeType == null || mimeType === 'application/x-www-form-urlencoded')
) {
bodyType = mimeType ?? 'application/x-www-form-urlencoded';
body = {
form: dataParameters.map((parameter) => ({
...parameter,
name: decodeURIComponent(parameter.name || ''),
value: decodeURIComponent(parameter.value || ''),
})),
};
headers.push({
name: 'Content-Type',
value: 'application/x-www-form-urlencoded',
enabled: true,
});
} else if (dataParameters.length > 0) {
bodyType =
mimeType === 'application/json' || mimeType === 'text/xml' || mimeType === 'text/plain'
? mimeType
: 'other';
body = {
text: dataParameters
.map(({ name, value }) => (name && value ? `${name}=${value}` : name || value))
.join('&'),
};
} else if (formDataParams.length) {
bodyType = mimeType ?? 'multipart/form-data';
body = {
form: formDataParams,
};
if (mimeType == null) {
headers.push({
name: 'Content-Type',
value: 'multipart/form-data',
enabled: true,
});
}
}
// Method
let method = getPairValue(pairsByName, '', ['X', 'request']).toUpperCase();
if (method === '' && body) {
method = 'text' in body || 'form' in body ? 'POST' : 'GET';
}
const request: ExportResources['httpRequests'][0] = {
id: generateId('http_request'),
model: 'http_request',
workspaceId,
name: '',
urlParameters,
url,
method,
headers,
authentication,
authenticationType,
body,
bodyType,
folderId: null,
sortPriority: 0,
};
return request;
}
const pairsToDataParameters = (keyedPairs: PairsByName) => {
let dataParameters: {
name: string;
value: string;
contentType?: string;
filePath?: string;
enabled?: boolean;
}[] = [];
for (const flagName of DATA_FLAGS) {
const pairs = keyedPairs[flagName];
if (!pairs || pairs.length === 0) {
continue;
}
for (const p of pairs) {
if (typeof p !== 'string') continue;
const [name, value] = p.split('=');
if (p.startsWith('@')) {
// Yaak doesn't support files in url-encoded data, so
dataParameters.push({
name: name ?? '',
value: '',
filePath: p.slice(1),
enabled: true,
});
} else {
dataParameters.push({
name: name ?? '',
value: flagName === 'data-urlencode' ? encodeURIComponent(value ?? '') : value ?? '',
enabled: true,
});
}
}
}
return dataParameters;
};
const getPairValue = <T extends string | boolean>(
pairsByName: PairsByName,
defaultValue: T,
names: string[],
) => {
for (const name of names) {
if (pairsByName[name] && pairsByName[name]!.length) {
return pairsByName[name]![0] as T;
}
}
return defaultValue;
};
function splitOnce(str: string, sep: string): string[] {
const index = str.indexOf(sep);
if (index > -1) {
return [str.slice(0, index), str.slice(index + 1)];
}
return [str];
}
const idCount: Partial<Record<Model['model'], number>> = {};
function generateId(model: Model['model']): string {
idCount[model] = (idCount[model] ?? -1) + 1;
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
}

View File

@@ -1,335 +0,0 @@
import { describe, expect, test } from 'vitest';
import { HttpRequest, Model, Workspace } from '../../../src-web/lib/models';
import { pluginHookImport } from '../src';
describe('importer-curl', () => {
test('Imports basic GET', () => {
expect(pluginHookImport('curl https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
}),
],
},
});
});
test('Explicit URL', () => {
expect(pluginHookImport('curl --url https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
}),
],
},
});
});
test('Missing URL', () => {
expect(pluginHookImport('curl -X POST')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'POST',
}),
],
},
});
});
test('URL between', () => {
expect(pluginHookImport('curl -v https://yaak.app -X POST')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
method: 'POST',
}),
],
},
});
});
test('Random flags', () => {
expect(pluginHookImport('curl --random -Z -Y -S --foo https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
}),
],
},
});
});
test('Imports --request method', () => {
expect(pluginHookImport('curl --request POST https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
method: 'POST',
}),
],
},
});
});
test('Imports -XPOST method', () => {
expect(pluginHookImport('curl -XPOST --request POST https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
method: 'POST',
}),
],
},
});
});
test('Imports multiple requests', () => {
expect(
pluginHookImport('curl \\\n https://yaak.app\necho "foo"\ncurl example.com;curl foo.com'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({ url: 'https://yaak.app' }),
baseRequest({ url: 'example.com' }),
baseRequest({ url: 'foo.com' }),
],
},
});
});
test('Imports form data', () => {
expect(
pluginHookImport('curl -X POST -F "a=aaa" -F b=bbb" -F f=@filepath https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'POST',
url: 'https://yaak.app',
headers: [
{
name: 'Content-Type',
value: 'multipart/form-data',
enabled: true,
},
],
bodyType: 'multipart/form-data',
body: {
form: [
{ enabled: true, name: 'a', value: 'aaa' },
{ enabled: true, name: 'b', value: 'bbb' },
{ enabled: true, name: 'f', file: 'filepath' },
],
},
}),
],
},
});
});
test('Imports data params as form url-encoded', () => {
expect(pluginHookImport('curl -d a -d b -d c=ccc https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'POST',
url: 'https://yaak.app',
bodyType: 'application/x-www-form-urlencoded',
headers: [
{
name: 'Content-Type',
value: 'application/x-www-form-urlencoded',
enabled: true,
},
],
body: {
form: [
{ name: 'a', value: '', enabled: true },
{ name: 'b', value: '', enabled: true },
{ name: 'c', value: 'ccc', enabled: true },
],
},
}),
],
},
});
});
test('Imports data params as text', () => {
expect(
pluginHookImport('curl -H Content-Type:text/plain -d a -d b -d c=ccc https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'POST',
url: 'https://yaak.app',
headers: [{ name: 'Content-Type', value: 'text/plain', enabled: true }],
bodyType: 'text/plain',
body: { text: 'a&b&c=ccc' },
}),
],
},
});
});
test('Imports multi-line JSON', () => {
expect(
pluginHookImport(
`curl -H Content-Type:application/json -d $'{\n "foo":"bar"\n}' https://yaak.app`,
),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
method: 'POST',
url: 'https://yaak.app',
headers: [{ name: 'Content-Type', value: 'application/json', enabled: true }],
bodyType: 'application/json',
body: { text: '{\n "foo":"bar"\n}' },
}),
],
},
});
});
test('Imports multiple headers', () => {
expect(
pluginHookImport('curl -H Foo:bar --header Name -H AAA:bbb -H :ccc https://yaak.app'),
).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
headers: [
{ name: 'Name', value: '', enabled: true },
{ name: 'Foo', value: 'bar', enabled: true },
{ name: 'AAA', value: 'bbb', enabled: true },
{ name: '', value: 'ccc', enabled: true },
],
}),
],
},
});
});
test('Imports basic auth', () => {
expect(pluginHookImport('curl --user user:pass https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
authenticationType: 'basic',
authentication: {
username: 'user',
password: 'pass',
},
}),
],
},
});
});
test('Imports digest auth', () => {
expect(pluginHookImport('curl --digest --user user:pass https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
authenticationType: 'digest',
authentication: {
username: 'user',
password: 'pass',
},
}),
],
},
});
});
test('Imports cookie as header', () => {
expect(pluginHookImport('curl --cookie "foo=bar" https://yaak.app')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
headers: [{ name: 'Cookie', value: 'foo=bar', enabled: true }],
}),
],
},
});
});
test('Imports query params from the URL', () => {
expect(pluginHookImport('curl "https://yaak.app?foo=bar&baz=a%20a"')).toEqual({
resources: {
workspaces: [baseWorkspace()],
httpRequests: [
baseRequest({
url: 'https://yaak.app',
urlParameters: [
{ name: 'foo', value: 'bar', enabled: true },
{ name: 'baz', value: 'a%20a', enabled: true },
],
}),
],
},
});
});
});
const idCount: Partial<Record<Model['model'], number>> = {};
function baseRequest(mergeWith: Partial<HttpRequest>) {
idCount.http_request = (idCount.http_request ?? -1) + 1;
return {
id: `GENERATE_ID::HTTP_REQUEST_${idCount.http_request}`,
model: 'http_request',
authentication: {},
authenticationType: null,
body: {},
bodyType: null,
folderId: null,
headers: [],
method: 'GET',
name: '',
sortPriority: 0,
url: '',
urlParameters: [],
workspaceId: `GENERATE_ID::WORKSPACE_${idCount.workspace}`,
...mergeWith,
};
}
function baseWorkspace(mergeWith: Partial<Workspace> = {}) {
idCount.workspace = (idCount.workspace ?? -1) + 1;
return {
id: `GENERATE_ID::WORKSPACE_${idCount.workspace}`,
model: 'workspace',
name: 'Curl Import',
...mergeWith,
};
}

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/importer-curl'),
},
});

View File

@@ -1,26 +0,0 @@
{
"name": "importer-insomnia",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "importer-insomnia",
"version": "0.0.1",
"dependencies": {
"yaml": "^2.4.2"
}
},
"node_modules/yaml": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
"integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
}
}
}

View File

@@ -1,7 +0,0 @@
{
"name": "importer-insomnia",
"version": "0.0.1",
"dependencies": {
"yaml": "^2.4.2"
}
}

View File

@@ -1,278 +0,0 @@
import {
Environment,
Folder,
GrpcRequest,
HttpRequest,
Workspace,
} from '../../../src-web/lib/models';
import { parse as parseYaml } from 'yaml';
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
export interface ExportResources {
workspaces: AtLeast<Workspace, 'name' | 'id' | 'model'>[];
environments: AtLeast<Environment, 'name' | 'id' | 'model' | 'workspaceId'>[];
httpRequests: AtLeast<HttpRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
grpcRequests: AtLeast<GrpcRequest, 'name' | 'id' | 'model' | 'workspaceId'>[];
folders: AtLeast<Folder, 'name' | 'id' | 'model' | 'workspaceId'>[];
}
export function pluginHookImport(contents: string) {
let parsed: any;
try {
parsed = JSON.parse(contents);
} catch (e) {}
try {
parsed = parseYaml(contents);
} catch (e) {}
if (!isJSObject(parsed)) return;
if (!Array.isArray(parsed.resources)) return;
const resources: ExportResources = {
workspaces: [],
httpRequests: [],
grpcRequests: [],
environments: [],
folders: [],
};
// Import workspaces
const workspacesToImport = parsed.resources.filter(isWorkspace);
for (const workspaceToImport of workspacesToImport) {
const baseEnvironment = parsed.resources.find(
(r: any) => isEnvironment(r) && r.parentId === workspaceToImport._id,
);
resources.workspaces.push({
id: convertId(workspaceToImport._id),
createdAt: new Date(workspacesToImport.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(workspacesToImport.updated ?? Date.now()).toISOString().replace('Z', ''),
model: 'workspace',
name: workspaceToImport.name,
variables: baseEnvironment ? parseVariables(baseEnvironment.data) : [],
});
const environmentsToImport = parsed.resources.filter(
(r: any) => isEnvironment(r) && r.parentId === baseEnvironment?._id,
);
resources.environments.push(
...environmentsToImport.map((r: any) => importEnvironment(r, workspaceToImport._id)),
);
const nextFolder = (parentId: string) => {
const children = parsed.resources.filter((r: any) => r.parentId === parentId);
let sortPriority = 0;
for (const child of children) {
if (isRequestGroup(child)) {
resources.folders.push(importFolder(child, workspaceToImport._id));
nextFolder(child._id);
} else if (isHttpRequest(child)) {
resources.httpRequests.push(
importHttpRequest(child, workspaceToImport._id, sortPriority++),
);
} else if (isGrpcRequest(child)) {
resources.grpcRequests.push(
importGrpcRequest(child, workspaceToImport._id, sortPriority++),
);
}
}
};
// Import folders
nextFolder(workspaceToImport._id);
}
// Filter out any `null` values
resources.httpRequests = resources.httpRequests.filter(Boolean);
resources.grpcRequests = resources.grpcRequests.filter(Boolean);
resources.environments = resources.environments.filter(Boolean);
resources.workspaces = resources.workspaces.filter(Boolean);
return { resources };
}
function importEnvironment(e: any, workspaceId: string): ExportResources['environments'][0] {
return {
id: convertId(e._id),
createdAt: new Date(e.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(e.updated ?? Date.now()).toISOString().replace('Z', ''),
workspaceId: convertId(workspaceId),
model: 'environment',
name: e.name,
variables: Object.entries(e.data).map(([name, value]) => ({
enabled: true,
name,
value: `${value}`,
})),
};
}
function importFolder(f: any, workspaceId: string): ExportResources['folders'][0] {
return {
id: convertId(f._id),
createdAt: new Date(f.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(f.updated ?? Date.now()).toISOString().replace('Z', ''),
folderId: f.parentId === workspaceId ? null : convertId(f.parentId),
workspaceId: convertId(workspaceId),
model: 'folder',
name: f.name,
};
}
function importGrpcRequest(
r: any,
workspaceId: string,
sortPriority = 0,
): ExportResources['grpcRequests'][0] {
const parts = r.protoMethodName.split('/').filter((p: any) => p !== '');
const service = parts[0] ?? null;
const method = parts[1] ?? null;
return {
id: convertId(r._id),
createdAt: new Date(r.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(r.updated ?? Date.now()).toISOString().replace('Z', ''),
workspaceId: convertId(workspaceId),
folderId: r.parentId === workspaceId ? null : convertId(r.parentId),
model: 'grpc_request',
sortPriority,
name: r.name,
url: convertSyntax(r.url),
service,
method,
message: r.body?.text ?? '',
metadata: (r.metadata ?? [])
.map((h: any) => ({
enabled: !h.disabled,
name: h.name ?? '',
value: h.value ?? '',
}))
.filter(({ name, value }: any) => name !== '' || value !== ''),
};
}
function importHttpRequest(
r: any,
workspaceId: string,
sortPriority = 0,
): ExportResources['httpRequests'][0] {
let bodyType = null;
let body = {};
if (r.body.mimeType === 'application/octet-stream') {
bodyType = 'binary';
body = { filePath: r.body.fileName ?? '' };
} else if (r.body?.mimeType === 'application/x-www-form-urlencoded') {
bodyType = 'application/x-www-form-urlencoded';
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? '',
value: p.value ?? '',
})),
};
} else if (r.body?.mimeType === 'multipart/form-data') {
bodyType = 'multipart/form-data';
body = {
form: (r.body.params ?? []).map((p: any) => ({
enabled: !p.disabled,
name: p.name ?? '',
value: p.value ?? '',
file: p.fileName ?? null,
})),
};
} else if (r.body?.mimeType === 'application/graphql') {
bodyType = 'graphql';
body = { text: convertSyntax(r.body.text ?? '') };
} else if (r.body?.mimeType === 'application/json') {
bodyType = 'application/json';
body = { text: convertSyntax(r.body.text ?? '') };
}
let authenticationType = null;
let authentication = {};
if (r.authentication.type === 'bearer') {
authenticationType = 'bearer';
authentication = {
token: convertSyntax(r.authentication.token),
};
} else if (r.authentication.type === 'basic') {
authenticationType = 'basic';
authentication = {
username: convertSyntax(r.authentication.username),
password: convertSyntax(r.authentication.password),
};
}
return {
id: convertId(r._id),
createdAt: new Date(r.created ?? Date.now()).toISOString().replace('Z', ''),
updatedAt: new Date(r.updated ?? Date.now()).toISOString().replace('Z', ''),
workspaceId: convertId(workspaceId),
folderId: r.parentId === workspaceId ? null : convertId(r.parentId),
model: 'http_request',
sortPriority,
name: r.name,
url: convertSyntax(r.url),
body,
bodyType,
authentication,
authenticationType,
method: r.method,
headers: (r.headers ?? [])
.map((h: any) => ({
enabled: !h.disabled,
name: h.name ?? '',
value: h.value ?? '',
}))
.filter(({ name, value }: any) => name !== '' || value !== ''),
};
}
function parseVariables(data: Record<string, string>) {
return Object.entries(data).map(([name, value]) => ({
enabled: true,
name,
value: `${value}`,
}));
}
function convertSyntax(variable: string): string {
if (!isJSString(variable)) return variable;
return variable.replaceAll(/{{\s*(_\.)?([^}]+)\s*}}/g, '${[$2]}');
}
function isWorkspace(obj: any) {
return isJSObject(obj) && obj._type === 'workspace';
}
function isRequestGroup(obj: any) {
return isJSObject(obj) && obj._type === 'request_group';
}
function isHttpRequest(obj: any) {
return isJSObject(obj) && obj._type === 'request';
}
function isGrpcRequest(obj: any) {
return isJSObject(obj) && obj._type === 'grpc_request';
}
function isEnvironment(obj: any) {
return isJSObject(obj) && obj._type === 'environment';
}
function isJSObject(obj: any) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
function isJSString(obj: any) {
return Object.prototype.toString.call(obj) === '[object String]';
}
function convertId(id: string): string {
if (id.startsWith('GENERATE_ID::')) {
return id;
}
return `GENERATE_ID::${id}`;
}

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/importer-insomnia'),
},
});

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,250 +0,0 @@
import { Environment, Folder, HttpRequest, Model, Workspace } from '../../../src-web/lib/models';
const POSTMAN_2_1_0_SCHEMA = 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json';
const POSTMAN_2_0_0_SCHEMA = 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json';
const VALID_SCHEMAS = [POSTMAN_2_0_0_SCHEMA, POSTMAN_2_1_0_SCHEMA];
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
interface ExportResources {
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 function pluginHookImport(contents: string): { resources: ExportResources } | undefined {
const root = parseJSONToRecord(contents);
if (root == null) return;
const info = toRecord(root.info);
const isValidSchema = VALID_SCHEMAS.includes(info.schema);
if (!isValidSchema || !Array.isArray(root.item)) {
return;
}
const globalAuth = importAuth(root.auth);
const exportResources: ExportResources = {
workspaces: [],
environments: [],
httpRequests: [],
folders: [],
};
const workspace: ExportResources['workspaces'][0] = {
model: 'workspace',
id: generateId('workspace'),
name: info.name || 'Postman Import',
description: info.description || '',
variables:
root.variable?.map((v: any) => ({
name: v.key,
value: v.value,
})) ?? [],
};
exportResources.workspaces.push(workspace);
const importItem = (v: Record<string, any>, folderId: string | null = null) => {
if (typeof v.name === 'string' && Array.isArray(v.item)) {
const folder: ExportResources['folders'][0] = {
model: 'folder',
workspaceId: workspace.id,
id: generateId('folder'),
name: v.name,
folderId,
};
exportResources.folders.push(folder);
for (const child of v.item) {
importItem(child, folder.id);
}
} else if (typeof v.name === 'string' && 'request' in v) {
const r = toRecord(v.request);
const bodyPatch = importBody(r.body);
const requestAuthPath = importAuth(r.auth);
const authPatch = requestAuthPath.authenticationType == null ? globalAuth : requestAuthPath;
const request: ExportResources['httpRequests'][0] = {
model: 'http_request',
id: generateId('http_request'),
workspaceId: workspace.id,
folderId,
name: v.name,
method: r.method || 'GET',
url: typeof r.url === 'string' ? r.url : toRecord(r.url).raw,
body: bodyPatch.body,
bodyType: bodyPatch.bodyType,
authentication: authPatch.authentication,
authenticationType: authPatch.authenticationType,
headers: [
...bodyPatch.headers,
...authPatch.headers,
...toArray(r.header).map((h) => {
return {
name: h.key,
value: h.value,
enabled: !h.disabled,
};
}),
],
};
exportResources.httpRequests.push(request);
} else {
console.log('Unknown item', v, folderId);
}
};
for (const item of root.item) {
importItem(item);
}
return { resources: convertTemplateSyntax(exportResources) };
}
function importAuth(
rawAuth: any,
): Pick<HttpRequest, 'authentication' | 'authenticationType' | 'headers'> {
const auth = toRecord(rawAuth);
if ('basic' in auth) {
return {
headers: [],
authenticationType: 'basic',
authentication: {
username: auth.basic.username || '',
password: auth.basic.password || '',
},
};
} else if ('bearer' in auth) {
return {
headers: [],
authenticationType: 'bearer',
authentication: {
token: auth.bearer.token || '',
},
};
} else {
// TODO: support other auth types
return { headers: [], authenticationType: null, authentication: {} };
}
}
function importBody(rawBody: any): Pick<HttpRequest, 'body' | 'bodyType' | 'headers'> {
const body = toRecord(rawBody);
if ('graphql' in body) {
return {
headers: [
{
name: 'Content-Type',
value: 'application/json',
enabled: true,
},
],
bodyType: 'graphql',
body: {
text: JSON.stringify(
{ query: body.graphql.query, variables: parseJSONToRecord(body.graphql.variables) },
null,
2,
),
},
};
} else if ('urlencoded' in body) {
return {
headers: [
{
name: 'Content-Type',
value: 'application/x-www-form-urlencoded',
enabled: true,
},
],
bodyType: 'application/x-www-form-urlencoded',
body: {
form: toArray(body.urlencoded).map((f) => ({
enabled: !f.disabled,
name: f.key ?? '',
value: f.value ?? '',
})),
},
};
} else if ('formdata' in body) {
return {
headers: [
{
name: 'Content-Type',
value: 'multipart/form-data',
enabled: true,
},
],
bodyType: 'multipart/form-data',
body: {
form: toArray(body.formdata).map((f) =>
f.src != null
? {
enabled: !f.disabled,
name: f.key ?? '',
file: f.src ?? '',
}
: {
enabled: !f.disabled,
name: f.key ?? '',
value: f.value ?? '',
},
),
},
};
} else if ('raw' in body) {
return {
headers: [
{
name: 'Content-Type',
value: body.options?.raw?.language === 'json' ? 'application/json' : '',
enabled: true,
},
],
bodyType: body.options?.raw?.language === 'json' ? 'application/json' : 'other',
body: {
text: body.raw ?? '',
},
};
} else {
// TODO: support other body types
return { headers: [], bodyType: null, body: {} };
}
}
function parseJSONToRecord(jsonStr: string): Record<string, any> | null {
try {
return toRecord(JSON.parse(jsonStr));
} catch (err) {}
return null;
}
function toRecord(value: any): Record<string, any> {
if (Object.prototype.toString.call(value) === '[object Object]') return value;
else return {};
}
function toArray(value: any): any[] {
if (Object.prototype.toString.call(value) === '[object Array]') return value;
else return [];
}
/** Recursively render all nested object properties */
function convertTemplateSyntax<T>(obj: T): T {
if (typeof obj === 'string') {
return obj.replace(/{{\s*(_\.)?([^}]+)\s*}}/g, '${[$2]}') as T;
} else if (Array.isArray(obj) && obj != null) {
return obj.map(convertTemplateSyntax) as T;
} else if (typeof obj === 'object' && obj != null) {
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, convertTemplateSyntax(v)]),
) as T;
} else {
return obj;
}
}
const idCount: Partial<Record<Model['model'], number>> = {};
function generateId(model: Model['model']): string {
idCount[model] = (idCount[model] ?? -1) + 1;
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
}

View File

@@ -1,38 +0,0 @@
{
"info": {
"_postman_id": "9e6dfada-256c-49ea-a38f-7d1b05b7ca2d",
"name": "New Collection",
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json",
"_exporter_id": "18798"
},
"item": [
{
"name": "Top Folder",
"item": [
{
"name": "Nested Folder",
"item": [
{
"name": "Request 1",
"request": {
"method": "GET"
}
}
]
},
{
"name": "Request 2",
"request": {
"method": "GET"
}
}
]
},
{
"name": "Request 3",
"request": {
"method": "GET"
}
}
]
}

View File

@@ -1,90 +0,0 @@
import * as fs from 'node:fs';
import * as path from 'node:path';
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
import { Model } from '../../../src-web/lib/models';
import { pluginHookImport } from '../src';
let originalRandom = Math.random;
describe('importer-postman', () => {
beforeEach(() => {
let i = 0;
// Psuedo-random number generator to ensure consistent ID generation
Math.random = vi.fn(() => ((i++ * 1000) % 133) / 100);
});
afterEach(() => {
Math.random = originalRandom;
});
const p = path.join(__dirname, 'fixtures');
const fixtures = fs.readdirSync(p);
for (const fixture of fixtures) {
test('Imports ' + fixture, () => {
const contents = fs.readFileSync(path.join(p, fixture), 'utf-8');
const imported = pluginHookImport(contents);
const folder0 = newId('folder');
const folder1 = newId('folder');
expect(imported).toEqual({
resources: expect.objectContaining({
workspaces: [
expect.objectContaining({
id: newId('workspace'),
model: 'workspace',
name: 'New Collection',
}),
],
folders: expect.arrayContaining([
expect.objectContaining({
id: folder0,
model: 'folder',
workspaceId: existingId('workspace'),
name: 'Top Folder',
}),
expect.objectContaining({
folderId: folder0,
id: folder1,
model: 'folder',
workspaceId: existingId('workspace'),
name: 'Nested Folder',
}),
]),
httpRequests: expect.arrayContaining([
expect.objectContaining({
id: newId('http_request'),
model: 'http_request',
name: 'Request 1',
workspaceId: existingId('workspace'),
folderId: folder1,
}),
expect.objectContaining({
id: newId('http_request'),
model: 'http_request',
name: 'Request 2',
workspaceId: existingId('workspace'),
folderId: folder0,
}),
expect.objectContaining({
id: newId('http_request'),
model: 'http_request',
name: 'Request 3',
workspaceId: existingId('workspace'),
folderId: null,
}),
]),
}),
});
});
}
});
const idCount: Partial<Record<Model['model'], number>> = {};
function newId(model: Model['model']): string {
idCount[model] = (idCount[model] ?? -1) + 1;
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`;
}
function existingId(model: Model['model']): string {
return `GENERATE_ID::${model.toUpperCase()}_${idCount[model] ?? 0}`;
}

View File

@@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": [
"ESNext",
],
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": [
"./src"
]
}

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/importer-postman'),
},
});

View File

@@ -1,12 +0,0 @@
{
"name": "importer-yaak",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "importer-yaak",
"version": "0.0.1"
}
}
}

View File

@@ -1,4 +0,0 @@
{
"name": "importer-yaak",
"version": "0.0.1"
}

View File

@@ -1,29 +0,0 @@
export function pluginHookImport(contents: string) {
let parsed;
try {
parsed = JSON.parse(contents);
} catch (err) {
return undefined;
}
if (!isJSObject(parsed)) {
return undefined;
}
const isYaakExport = 'yaakSchema' in parsed;
if (!isYaakExport) {
return;
}
// Migrate v1 to v2 -- changes requests to httpRequests
if ('requests' in parsed.resources) {
parsed.resources.httpRequests = parsed.resources.requests;
delete parsed.resources.requests;
}
return { resources: parsed.resources }; // Should already be in the correct format
}
export function isJSObject(obj: any) {
return Object.prototype.toString.call(obj) === '[object Object]';
}

View File

@@ -1,29 +0,0 @@
import { describe, expect, test } from 'vitest';
import { pluginHookImport } from '../src';
describe('importer-yaak', () => {
test('Skips invalid imports', () => {
expect(pluginHookImport('not JSON')).toBeUndefined();
expect(pluginHookImport('[]')).toBeUndefined();
expect(pluginHookImport(JSON.stringify({ resources: {} }))).toBeUndefined();
});
test('converts schema 1 to 2', () => {
const imported = pluginHookImport(
JSON.stringify({
yaakSchema: 1,
resources: {
requests: [],
},
}),
);
expect(imported).toEqual(
expect.objectContaining({
resources: {
httpRequests: [],
},
}),
);
});
});

View File

@@ -1,13 +0,0 @@
import { resolve } from 'path';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
fileName: 'index',
formats: ['es'],
},
outDir: resolve(__dirname, '../../src-tauri/plugins/importer-yaak'),
},
});

View File

@@ -0,0 +1,32 @@
syntax = "proto3";
package yaak.plugins.runtime;
service PluginRuntime {
rpc hookImport (HookImportRequest) returns (HookResponse);
rpc hookResponseFilter (HookResponseFilterRequest) returns (HookResponse);
rpc hookExport (HookExportRequest) returns (HookResponse);
}
message PluginInfo {
string plugin = 1;
}
message HookResponse {
PluginInfo info = 1;
string data = 2;
}
message HookImportRequest {
string data = 1;
}
message HookResponseFilterRequest {
string filter = 1;
string body = 2;
string contentType = 3;
}
message HookExportRequest {
string request = 1;
}

View File

@@ -0,0 +1,15 @@
const path = require('path');
const fs = require('fs');
const version = process.env.YAAK_VERSION?.replace('v', '');
if (!version) {
throw new Error('YAAK_VERSION environment variable not set')
}
const tauriConfigPath = path.join(__dirname, '../src-tauri/tauri.conf.json');
const tauriConfig = JSON.parse(fs.readFileSync(tauriConfigPath, 'utf8'));
tauriConfig.version = version;
console.log('Writing version ' + version + ' to ' + tauriConfigPath)
fs.writeFileSync(tauriConfigPath, JSON.stringify(tauriConfig, null, 2));

22
scripts/vendor-node.cjs Normal file
View File

@@ -0,0 +1,22 @@
const path = require('node:path');
const {cpSync} = require('node:fs');
const destDir = path.join(__dirname, '..', 'src-tauri', 'vendored', 'node');
const DST_BIN_MAP = {
darwin_arm64: 'node-aarch64-apple-darwin',
darwin_x64: 'node-x86_64-apple-darwin',
linux_x64: 'node-x86_64-unknown-linux-gnu',
win32_x64: 'node-x86_64-pc-windows-msvc.exe',
};
// Build the sea
console.log('Vendoring NodeJS binary');
// console.log('Changing Node.js binary permissions');
// chmodSync(tmpNodePath, 0o755);
const key = `${process.platform}_${process.env.NODE_ARCH ?? process.arch}`;
const dstPath = path.join(destDir, DST_BIN_MAP[key]);
cpSync(process.execPath, dstPath);
console.log(`Copied NodeJS to ${dstPath}`)

View File

@@ -0,0 +1,25 @@
const {readdirSync, cpSync} = require("node:fs");
const path = require("node:path");
const {execSync} = require("node:child_process");
const pluginsDir = process.env.YAAK_PLUGINS_DIR;
if (!pluginsDir) {
console.log("YAAK_PLUGINS_DIR is not set");
process.exit(1);
}
console.log('Installing Yaak plugins dependencies', pluginsDir);
execSync('npm ci', {cwd: pluginsDir});
console.log('Building Yaak plugins', pluginsDir);
execSync('npm run build', {cwd: pluginsDir});
console.log('Copying Yaak plugins to', pluginsDir);
const pluginsRoot = path.join(pluginsDir, 'plugins');
for (const name of readdirSync(pluginsRoot)) {
const dir = path.join(pluginsRoot, name);
if (name.startsWith('.')) 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'));
cpSync(path.join(dir, 'build/index.js'), path.join(destDir, 'build/index.js'));
}

64
scripts/vendor-protoc.cjs Normal file
View File

@@ -0,0 +1,64 @@
const decompress = require('decompress');
const Downloader = require("nodejs-file-downloader");
const path = require("node:path");
const fs = require("node:fs");
const rimraf = require('rimraf');
const {rmSync} = require("node:fs");
// `${process.platform}_${process.arch}`
const MAC_ARM = 'darwin_arm64';
const MAC_X64 = 'darwin_x64';
const LNX_X64 = 'linux_x64';
const WIN_X64 = 'win32_x64';
const URL_MAP = {
[MAC_ARM]: 'https://github.com/protocolbuffers/protobuf/releases/download/v27.2/protoc-27.2-osx-aarch_64.zip',
[MAC_X64]: 'https://github.com/protocolbuffers/protobuf/releases/download/v27.2/protoc-27.2-osx-x86_64.zip',
[LNX_X64]: 'https://github.com/protocolbuffers/protobuf/releases/download/v27.2/protoc-27.2-linux-x86_64.zip',
[WIN_X64]: 'https://github.com/protocolbuffers/protobuf/releases/download/v27.2/protoc-27.2-win64.zip',
};
const DST_BIN_MAP = {
[MAC_ARM]: 'protoc-aarch64-apple-darwin',
[MAC_X64]: 'protoc-x86_64-apple-darwin',
[LNX_X64]: 'protoc-x86_64-unknown-linux-gnu',
[WIN_X64]: 'protoc-x86_64-pc-windows-msvc.exe',
};
const SRC_BIN_MAP = {
[MAC_ARM]: 'protoc',
[MAC_X64]: 'protoc',
[LNX_X64]: 'protoc',
[WIN_X64]: 'protoc.exe',
};
(async function () {
const key = `${process.platform}_${process.env.NODE_ARCH ?? process.arch}`;
const url = URL_MAP[key];
const tmpDir = path.join(__dirname, 'tmp', `${Math.random()}`);
const dstDir = path.join(__dirname, `..`, 'src-tauri', 'vendored', 'protoc');
rimraf.sync(dstDir);
// Download GitHub release artifact
const {filePath} = await new Downloader({url, directory: tmpDir,}).download();
// Decompress to the same directory
await decompress(filePath, tmpDir, {});
// Remove the original archive
fs.unlinkSync(filePath);
// Copy binary
const binSrc = path.join(tmpDir, 'bin', SRC_BIN_MAP[key]);
const binDst = path.join(dstDir, DST_BIN_MAP[key]);
fs.cpSync(binSrc, binDst);
// Copy other files
const includeSrc = path.join(tmpDir, 'include');
const includeDst = path.join(dstDir, 'include');
fs.cpSync(includeSrc, includeDst, {recursive: true});
rmSync(tmpDir, {recursive: true, force: true});
console.log("Downloaded protoc to", binDst);
})().catch(err => console.log('Script failed:', err));

View File

@@ -2,3 +2,4 @@
# will have compiled files and executables
/target/
vendored

View File

@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO http_requests (\n id, workspace_id, folder_id, name, url, url_parameters, method, body, body_type,\n authentication, authentication_type, headers, sort_priority\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n method = excluded.method,\n headers = excluded.headers,\n body = excluded.body,\n body_type = excluded.body_type,\n authentication = excluded.authentication,\n authentication_type = excluded.authentication_type,\n url = excluded.url,\n url_parameters = excluded.url_parameters,\n sort_priority = excluded.sort_priority\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 13
},
"nullable": []
},
"hash": "11394af12419cca3be3a26dff9275514ea2a44504e3c7a568a9578c64b5713d1"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n authentication_type, authentication, metadata\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n authentication_type = excluded.authentication_type,\n authentication = excluded.authentication,\n metadata = excluded.metadata\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "467b87ad1209a4653b1dc8462d79236a655240c5b402fa9fd75c12ebd9bb6b86"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "SQLite",
"query": "\n UPDATE settings SET (\n theme, appearance, update_channel\n ) = (?, ?, ?) WHERE id = 'default';\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
},
"hash": "48ec5fdf20f34add763c540061caa25054545503704e19f149987f99b1a0e4f0"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO grpc_requests (\n id, name, workspace_id, folder_id, sort_priority, url, service, method, message,\n authentication_type, authentication, metadata\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n workspace_id = excluded.workspace_id,\n name = excluded.name,\n folder_id = excluded.folder_id,\n sort_priority = excluded.sort_priority,\n url = excluded.url,\n service = excluded.service,\n method = excluded.method,\n message = excluded.message,\n authentication_type = excluded.authentication_type,\n authentication = excluded.authentication,\n metadata = excluded.metadata\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 12
},
"nullable": []
},
"hash": "5af82cd333895d3d7d67a92f37b0feb338f615b88aea2bd09cb5809008c645a3"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n INSERT INTO http_requests (\n id, workspace_id, folder_id, name, url, url_parameters, method, body, body_type,\n authentication, authentication_type, headers, sort_priority\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n workspace_id = excluded.workspace_id,\n name = excluded.name,\n folder_id = excluded.folder_id,\n method = excluded.method,\n headers = excluded.headers,\n body = excluded.body,\n body_type = excluded.body_type,\n authentication = excluded.authentication,\n authentication_type = excluded.authentication_type,\n url = excluded.url,\n url_parameters = excluded.url_parameters,\n sort_priority = excluded.sort_priority\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 13
},
"nullable": []
},
"hash": "5f2f40062abbe93e23b38876319cf16d4d2b3f8d0be32ffe7848528c725e1429"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "SQLite",
"query": "\n UPDATE settings SET (\n theme, appearance, theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap,\n open_workspace_new_window\n ) = (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) WHERE id = 'default';\n ",
"describe": {
"columns": [],
"parameters": {
"Right": 10
},
"nullable": []
},
"hash": "6b5edf45a6799cd7f87c23a3c7f818ad110d58c601f694a619d9345ae9e8e11d"
}

View File

@@ -1,56 +0,0 @@
{
"db_name": "SQLite",
"query": "\n SELECT\n id, model, created_at, updated_at, theme, appearance, update_channel\n FROM settings\n WHERE id = 'default'\n ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "model",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "theme",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "appearance",
"ordinal": 5,
"type_info": "Text"
},
{
"name": "update_channel",
"ordinal": 6,
"type_info": "Text"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false,
false,
false,
false,
false,
false,
false
]
},
"hash": "b32994b09ae7a06eb0f031069d327e55127a5bce60cbb499b83d1701386a23cb"
}

View File

@@ -0,0 +1,98 @@
{
"db_name": "SQLite",
"query": "\n SELECT\n id, model, created_at, updated_at, theme, appearance,\n theme_dark, theme_light, update_channel,\n interface_font_size, interface_scale, editor_font_size, editor_soft_wrap,\n open_workspace_new_window\n FROM settings\n WHERE id = 'default'\n ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Text"
},
{
"name": "model",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "created_at",
"ordinal": 2,
"type_info": "Datetime"
},
{
"name": "updated_at",
"ordinal": 3,
"type_info": "Datetime"
},
{
"name": "theme",
"ordinal": 4,
"type_info": "Text"
},
{
"name": "appearance",
"ordinal": 5,
"type_info": "Text"
},
{
"name": "theme_dark",
"ordinal": 6,
"type_info": "Text"
},
{
"name": "theme_light",
"ordinal": 7,
"type_info": "Text"
},
{
"name": "update_channel",
"ordinal": 8,
"type_info": "Text"
},
{
"name": "interface_font_size",
"ordinal": 9,
"type_info": "Int64"
},
{
"name": "interface_scale",
"ordinal": 10,
"type_info": "Int64"
},
{
"name": "editor_font_size",
"ordinal": 11,
"type_info": "Int64"
},
{
"name": "editor_soft_wrap",
"ordinal": 12,
"type_info": "Bool"
},
{
"name": "open_workspace_new_window",
"ordinal": 13,
"type_info": "Bool"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true
]
},
"hash": "daa61066517df649e7c80a8ce407839ad502e8e5e43aa8c02e049865acbbae75"
}

2442
src-tauri/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
workspace = { members = ["grpc"] }
workspace = { members = ["grpc", "templates", "tauri-plugin-plugin-runtime"] }
[package]
name = "yaak-app"
@@ -8,7 +8,7 @@ edition = "2021"
# Produce a library for mobile support
[lib]
name = "tauri_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
crate-type = ["staticlib", "cdylib", "lib"]
[profile.release]
strip = true # Automatically strip symbols from the binary.
@@ -24,30 +24,34 @@ cocoa = "0.25.0"
openssl-sys = { version = "0.9", features = ["vendored"] } # For Ubuntu installation to work
[dependencies]
grpc = { path = "./grpc" }
templates = { path = "./templates" }
plugin_runtime = { path = "tauri-plugin-plugin-runtime" }
anyhow = "1.0.86"
base64 = "0.22.0"
boa_engine = { version = "0.18.0", features = ["annex-b"] }
boa_runtime = { version = "0.18.0" }
chrono = { version = "0.4.31", features = ["serde"] }
http = "0.2.10"
datetime = "0.5.2"
hex_color = "3.0.0"
http = "1"
log = "0.4.21"
rand = "0.8.5"
reqwest = { version = "0.11.23", features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json"] }
regex = "1.10.2"
reqwest = { version = "0.12.4", features = ["multipart", "cookies", "gzip", "brotli", "deflate", "json", "native-tls-alpn"] }
reqwest_cookie_store = "0.8.0"
serde = { version = "1.0.198", features = ["derive"] }
serde_json = { version = "1.0.116", features = ["raw_value"] }
serde_yaml = "0.9.34"
sqlx = { version = "0.7.4", features = ["sqlite", "runtime-tokio-rustls", "json", "chrono", "time"] }
tauri = { version = "2.0.0-beta.19", features = ["config-toml", "devtools", "protocol-asset"] }
tauri-plugin-clipboard-manager = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-dialog = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2", features = ["colored"] }
tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-os = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-updater = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
tauri = { version = "2.0.0-beta", features = ["devtools", "protocol-asset"] }
tauri-plugin-clipboard-manager = "2.1.0-beta"
tauri-plugin-dialog = "2.0.0-beta"
tauri-plugin-fs = "2.0.0-beta"
tauri-plugin-log = { version = "2.0.0-beta", features = ["colored"] }
tauri-plugin-os = "2.0.0-beta"
tauri-plugin-shell = "2.0.0-beta"
tauri-plugin-updater = "2.0.0-beta"
tauri-plugin-window-state = "2.0.0-beta"
tokio = { version = "1.36.0", features = ["sync"] }
uuid = "1.7.0"
log = "0.4.21"
datetime = "0.5.2"
reqwest_cookie_store = "0.6.0"
grpc = { path = "./grpc" }
tokio-stream = "0.1.15"
regex = "1.10.2"
uuid = "1.7.0"
thiserror = "1.0.61"

View File

@@ -39,6 +39,7 @@
}
]
},
"webview:allow-set-webview-zoom",
"window:allow-close",
"window:allow-is-fullscreen",
"window:allow-maximize",
@@ -48,6 +49,7 @@
"window:allow-set-title",
"window:allow-start-dragging",
"window:allow-unmaximize",
"window:allow-theme",
"clipboard-manager:allow-read-text",
"clipboard-manager:allow-write-text"
]

View File

@@ -1,3 +0,0 @@
xcuserdata/
build/
Externals/

Binary file not shown.

Before

Width:  |  Height:  |  Size: 844 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,116 +0,0 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "AppIcon-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "AppIcon-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "AppIcon-29x29@2x-1.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "AppIcon-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "AppIcon-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "AppIcon-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "AppIcon-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "AppIcon-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "AppIcon-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "AppIcon-20x20@2x-1.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "AppIcon-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "AppIcon-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "AppIcon-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "AppIcon-40x40@2x-1.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "AppIcon-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "AppIcon-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "AppIcon-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "AppIcon-512@2x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -1,6 +0,0 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>development</string>
</dict>
</plist>

View File

@@ -1,21 +0,0 @@
# Uncomment the next line to define a global platform for your project
target 'yaak-app_iOS' do
platform :ios, '13.0'
# Pods for yaak-app_iOS
end
target 'yaak-app_macOS' do
platform :osx, '11.0'
# Pods for yaak-app_macOS
end
# Delete the deployment target for iOS and macOS, causing it to be inherited from the Podfile
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET'
end
end
end

View File

@@ -1,8 +0,0 @@
#pragma once
namespace ffi {
extern "C" {
void start_app();
}
}

View File

@@ -1,6 +0,0 @@
#include "bindings/bindings.h"
int main(int argc, char * argv[]) {
ffi::start_app();
return 0;
}

View File

@@ -1,90 +0,0 @@
name: yaak-app
options:
bundleIdPrefix: app.yaak
deploymentTarget:
iOS: 13.0
fileGroups: [../../src]
configs:
debug: debug
release: release
settingGroups:
app:
base:
PRODUCT_NAME: Yaak
PRODUCT_BUNDLE_IDENTIFIER: app.yaak.yaak-app
DEVELOPMENT_TEAM: 7PU3P6ELJ8
targetTemplates:
app:
type: application
sources:
- path: Sources
scheme:
environmentVariables:
RUST_BACKTRACE: full
RUST_LOG: info
settings:
groups: [app]
targets:
yaak-app_iOS:
type: application
platform: iOS
sources:
- path: Sources
- path: Assets.xcassets
- path: Externals
- path: yaak-app_iOS
- path: assets
buildPhase: resources
type: folder
info:
path: yaak-app_iOS/Info.plist
properties:
LSRequiresIPhoneOS: true
UILaunchStoryboardName: LaunchScreen
UIRequiredDeviceCapabilities: [arm64, metal]
UISupportedInterfaceOrientations:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad:
- UIInterfaceOrientationPortrait
- UIInterfaceOrientationPortraitUpsideDown
- UIInterfaceOrientationLandscapeLeft
- UIInterfaceOrientationLandscapeRight
CFBundleShortVersionString: 2024.3.10
CFBundleVersion: 2024.3.10
entitlements:
path: yaak-app_iOS/yaak-app_iOS.entitlements
scheme:
environmentVariables:
RUST_BACKTRACE: full
RUST_LOG: info
settings:
base:
ENABLE_BITCODE: false
ARCHS: [arm64, arm64-sim]
VALID_ARCHS: arm64 arm64-sim
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true
EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
groups: [app]
dependencies:
- framework: libapp_lib.a
embed: false
- sdk: CoreGraphics.framework
- sdk: Metal.framework
- sdk: MetalKit.framework
- sdk: QuartzCore.framework
- sdk: Security.framework
- sdk: UIKit.framework
- sdk: WebKit.framework
preBuildScripts:
- script: node tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}
name: Build Rust Code
basedOnDependencyAnalysis: false
outputFiles:
- $(SRCROOT)/target/aarch64-apple-ios/${CONFIGURATION}/deps/libapp_lib.a
- $(SRCROOT)/target/x86_64-apple-ios/${CONFIGURATION}/deps/libapp_lib.a

View File

@@ -1,481 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
0AC23E163631EF3775908406 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEF0D2E01608E7F464F71B6 /* WebKit.framework */; };
1B1BFDF8BC345D0D980E4427 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EF0B8CF73BE8166011E2CEAB /* QuartzCore.framework */; };
36588BE1A75B386BB2FEDAC5 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A93A95F6B2F31FA92AA099E0 /* MetalKit.framework */; };
38E2C1B0E9FCC9A5FDE8876D /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF2908761467DF191C2A8939 /* Metal.framework */; };
8D518C1A67069BD7D339D055 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F34A96C5084EFDF1802A634 /* CoreGraphics.framework */; };
8DF67739DC49E577EB0FAE3F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 396F45DCFBE2C71866817528 /* Assets.xcassets */; };
A1D932F0E7399066AD07DC6D /* libapp_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 75D938BE0FA8770BA965AE1E /* libapp_lib.a */; };
AF0EEC868306E1D1C85994D0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B5BF2E39256494269E65F8E /* Security.framework */; };
BE9FFDF51EB7DEBF707BB39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5415A3F2D217A47DD3BA40B3 /* UIKit.framework */; };
F0627C04787F4E187EF416F4 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 2A615609009B3AE2728043E4 /* assets */; };
FEE5934F5FFB0FBE10883AF2 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = C754460F1DAF2D414038A7EA /* main.mm */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
106BE62BE01A35403424018C /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = "<group>"; };
14F240DAC31C5C52D7B4BB96 /* window_ext.rs */ = {isa = PBXFileReference; path = window_ext.rs; sourceTree = "<group>"; };
1B5226A88D8B805E878524C8 /* updates.rs */ = {isa = PBXFileReference; path = updates.rs; sourceTree = "<group>"; };
1F34A96C5084EFDF1802A634 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
1F5A647F82A24722F3C830BB /* plugin.rs */ = {isa = PBXFileReference; path = plugin.rs; sourceTree = "<group>"; };
2A615609009B3AE2728043E4 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; };
396F45DCFBE2C71866817528 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
53872C1120171EDC4A6DFEDD /* analytics.rs */ = {isa = PBXFileReference; path = analytics.rs; sourceTree = "<group>"; };
5415A3F2D217A47DD3BA40B3 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
5C1B6610F62B56E1947BEBBD /* http.rs */ = {isa = PBXFileReference; path = http.rs; sourceTree = "<group>"; };
6286C385ABAD2E04237679D7 /* yaak-app_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "yaak-app_iOS.entitlements"; sourceTree = "<group>"; };
75D938BE0FA8770BA965AE1E /* libapp_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapp_lib.a; sourceTree = "<group>"; };
7B5BF2E39256494269E65F8E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
A2CC02313D71CECB68031D53 /* grpc.rs */ = {isa = PBXFileReference; path = grpc.rs; sourceTree = "<group>"; };
A6DA9B210723CA84891876F8 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = "<group>"; };
A93A95F6B2F31FA92AA099E0 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
C754460F1DAF2D414038A7EA /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
D69BFB768591FDEEF65198EE /* yaak-app_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = "yaak-app_iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
DDDE197D9C6BC5680EEEEA00 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
DF2908761467DF191C2A8939 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
DF45D08D97DE587CABF9537E /* window_menu.rs */ = {isa = PBXFileReference; path = window_menu.rs; sourceTree = "<group>"; };
E1E84E267D81D6437901B1C6 /* render.rs */ = {isa = PBXFileReference; path = render.rs; sourceTree = "<group>"; };
E964D3637BAED49E34B91739 /* models.rs */ = {isa = PBXFileReference; path = models.rs; sourceTree = "<group>"; };
EDEF0D2E01608E7F464F71B6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
EF0B8CF73BE8166011E2CEAB /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
FB34CB48BB9F25D49F80D513 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D8E8888B0F3E4411B98AE8EE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
A1D932F0E7399066AD07DC6D /* libapp_lib.a in Frameworks */,
8D518C1A67069BD7D339D055 /* CoreGraphics.framework in Frameworks */,
38E2C1B0E9FCC9A5FDE8876D /* Metal.framework in Frameworks */,
36588BE1A75B386BB2FEDAC5 /* MetalKit.framework in Frameworks */,
1B1BFDF8BC345D0D980E4427 /* QuartzCore.framework in Frameworks */,
AF0EEC868306E1D1C85994D0 /* Security.framework in Frameworks */,
BE9FFDF51EB7DEBF707BB39A /* UIKit.framework in Frameworks */,
0AC23E163631EF3775908406 /* WebKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0844ACEFE550685042AC6029 /* Products */ = {
isa = PBXGroup;
children = (
D69BFB768591FDEEF65198EE /* yaak-app_iOS.app */,
);
name = Products;
sourceTree = "<group>";
};
6D0B6FF641B88DAF74C78B00 /* Externals */ = {
isa = PBXGroup;
children = (
);
path = Externals;
sourceTree = "<group>";
};
8A07575CB8654BB9107F9A32 /* bindings */ = {
isa = PBXGroup;
children = (
A6DA9B210723CA84891876F8 /* bindings.h */,
);
path = bindings;
sourceTree = "<group>";
};
8F0B46911FBEF2B246BE3385 /* yaak-app */ = {
isa = PBXGroup;
children = (
C754460F1DAF2D414038A7EA /* main.mm */,
8A07575CB8654BB9107F9A32 /* bindings */,
);
path = "yaak-app";
sourceTree = "<group>";
};
90E982C0E9B45CBAAE66E16D /* Frameworks */ = {
isa = PBXGroup;
children = (
1F34A96C5084EFDF1802A634 /* CoreGraphics.framework */,
75D938BE0FA8770BA965AE1E /* libapp_lib.a */,
DF2908761467DF191C2A8939 /* Metal.framework */,
A93A95F6B2F31FA92AA099E0 /* MetalKit.framework */,
EF0B8CF73BE8166011E2CEAB /* QuartzCore.framework */,
7B5BF2E39256494269E65F8E /* Security.framework */,
5415A3F2D217A47DD3BA40B3 /* UIKit.framework */,
EDEF0D2E01608E7F464F71B6 /* WebKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
C88F9D29DC52F052255C35A3 = {
isa = PBXGroup;
children = (
2A615609009B3AE2728043E4 /* assets */,
396F45DCFBE2C71866817528 /* Assets.xcassets */,
6D0B6FF641B88DAF74C78B00 /* Externals */,
EBC83899FBFA4A3D0A92837F /* Sources */,
F3A6B45E25E23922AB1BDB34 /* src */,
D49CF68C9105CE84E2084C14 /* yaak-app_iOS */,
90E982C0E9B45CBAAE66E16D /* Frameworks */,
0844ACEFE550685042AC6029 /* Products */,
);
sourceTree = "<group>";
};
D49CF68C9105CE84E2084C14 /* yaak-app_iOS */ = {
isa = PBXGroup;
children = (
DDDE197D9C6BC5680EEEEA00 /* Info.plist */,
6286C385ABAD2E04237679D7 /* yaak-app_iOS.entitlements */,
);
path = "yaak-app_iOS";
sourceTree = "<group>";
};
EBC83899FBFA4A3D0A92837F /* Sources */ = {
isa = PBXGroup;
children = (
8F0B46911FBEF2B246BE3385 /* yaak-app */,
);
path = Sources;
sourceTree = "<group>";
};
F3A6B45E25E23922AB1BDB34 /* src */ = {
isa = PBXGroup;
children = (
53872C1120171EDC4A6DFEDD /* analytics.rs */,
A2CC02313D71CECB68031D53 /* grpc.rs */,
5C1B6610F62B56E1947BEBBD /* http.rs */,
FB34CB48BB9F25D49F80D513 /* lib.rs */,
106BE62BE01A35403424018C /* main.rs */,
E964D3637BAED49E34B91739 /* models.rs */,
1F5A647F82A24722F3C830BB /* plugin.rs */,
E1E84E267D81D6437901B1C6 /* render.rs */,
1B5226A88D8B805E878524C8 /* updates.rs */,
14F240DAC31C5C52D7B4BB96 /* window_ext.rs */,
DF45D08D97DE587CABF9537E /* window_menu.rs */,
);
name = src;
path = ../../src;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7C3E2AC18A0A227C2DF356E2 /* yaak-app_iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = C05E07AE7C7B25CACFADCDD4 /* Build configuration list for PBXNativeTarget "yaak-app_iOS" */;
buildPhases = (
5454ED506FC51D41C81A0318 /* Build Rust Code */,
C3495A2849227C6276D3876E /* Sources */,
E148188313FB67F061AB4E59 /* Resources */,
D8E8888B0F3E4411B98AE8EE /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "yaak-app_iOS";
productName = "yaak-app_iOS";
productReference = D69BFB768591FDEEF65198EE /* yaak-app_iOS.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A8F6206BC76F061F1FEFD439 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastUpgradeCheck = 1430;
TargetAttributes = {
7C3E2AC18A0A227C2DF356E2 = {
DevelopmentTeam = 7PU3P6ELJ8;
};
};
};
buildConfigurationList = 24EF8D1B948FFF6B275FB0F4 /* Build configuration list for PBXProject "yaak-app" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Base,
en,
);
mainGroup = C88F9D29DC52F052255C35A3;
projectDirPath = "";
projectRoot = "";
targets = (
7C3E2AC18A0A227C2DF356E2 /* yaak-app_iOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
E148188313FB67F061AB4E59 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8DF67739DC49E577EB0FAE3F /* Assets.xcassets in Resources */,
F0627C04787F4E187EF416F4 /* assets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
5454ED506FC51D41C81A0318 /* Build Rust Code */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Build Rust Code";
outputFileListPaths = (
);
outputPaths = (
"$(SRCROOT)/target/aarch64-apple-ios/${CONFIGURATION}/deps/libapp_lib.a",
"$(SRCROOT)/target/x86_64-apple-ios/${CONFIGURATION}/deps/libapp_lib.a",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "node tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
C3495A2849227C6276D3876E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FEE5934F5FFB0FBE10883AF2 /* main.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
35D1DB294FFD067C835186C7 /* debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"DEBUG=1",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = debug;
};
368BB1E364597E7675463634 /* release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = (
arm64,
"arm64-sim",
);
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "yaak-app_iOS/yaak-app_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = 7PU3P6ELJ8;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\".\"",
);
INFOPLIST_FILE = "yaak-app_iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "app.yaak.yaak-app";
PRODUCT_NAME = Yaak;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = "arm64 arm64-sim";
};
name = release;
};
45382E89556BF93E8D1F1C2D /* debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = (
arm64,
"arm64-sim",
);
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "yaak-app_iOS/yaak-app_iOS.entitlements";
CODE_SIGN_IDENTITY = "iPhone Developer";
DEVELOPMENT_TEAM = 7PU3P6ELJ8;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64";
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\".\"",
);
INFOPLIST_FILE = "yaak-app_iOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = "app.yaak.yaak-app";
PRODUCT_NAME = Yaak;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALID_ARCHS = "arm64 arm64-sim";
};
name = debug;
};
ABD0A3DD3D5C66C839496F44 /* release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
};
name = release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
24EF8D1B948FFF6B275FB0F4 /* Build configuration list for PBXProject "yaak-app" */ = {
isa = XCConfigurationList;
buildConfigurations = (
35D1DB294FFD067C835186C7 /* debug */,
ABD0A3DD3D5C66C839496F44 /* release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = debug;
};
C05E07AE7C7B25CACFADCDD4 /* Build configuration list for PBXNativeTarget "yaak-app_iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
45382E89556BF93E8D1F1C2D /* debug */,
368BB1E364597E7675463634 /* release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = debug;
};
/* End XCConfigurationList section */
};
rootObject = A8F6206BC76F061F1FEFD439 /* Project object */;
}

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