diff --git a/.nvmrc b/.nvmrc
deleted file mode 100644
index 209e3ef4..00000000
--- a/.nvmrc
+++ /dev/null
@@ -1 +0,0 @@
-20
diff --git a/.oxfmtrc.json b/.oxfmtrc.json
new file mode 100644
index 00000000..682f3b97
--- /dev/null
+++ b/.oxfmtrc.json
@@ -0,0 +1,8 @@
+{
+ "printWidth": 100,
+ "ignorePatterns": [
+ "**/bindings/**",
+ "crates/yaak-templates/pkg/**",
+ "apps/yaak-client/routeTree.gen.ts"
+ ]
+}
diff --git a/Cargo.lock b/Cargo.lock
index dcb67ada..477efc5a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1169,7 +1169,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static 1.5.0",
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -5791,9 +5791,9 @@ dependencies = [
[[package]]
name = "quinn-proto"
-version = "0.11.12"
+version = "0.11.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
+checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
dependencies = [
"bytes",
"getrandom 0.3.3",
@@ -6856,9 +6856,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]]
name = "rustls-webpki"
-version = "0.103.7"
+version = "0.103.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf"
+checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
dependencies = [
"aws-lc-rs",
"ring",
@@ -7746,9 +7746,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
[[package]]
name = "tar"
-version = "0.4.44"
+version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a"
+checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973"
dependencies = [
"filetime",
"libc",
@@ -9549,7 +9549,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.48.0",
]
[[package]]
diff --git a/apps/yaak-client/components/core/Editor/Editor.css b/apps/yaak-client/components/core/Editor/Editor.css
index 6b80aa03..5143aca6 100644
--- a/apps/yaak-client/components/core/Editor/Editor.css
+++ b/apps/yaak-client/components/core/Editor/Editor.css
@@ -67,6 +67,13 @@
@apply bg-selection !important;
}
+ /* Fix WebKit/WKWebView rendering bug where selection layer leaves a ghost
+ residual line below wrapped lines after deselecting (CodeMirror issue #1600, #1627).
+ The layer div must be hidden when empty to force a repaint. */
+ .cm-selectionLayer:empty {
+ display: none;
+ }
+
/* Style gutters */
.cm-gutters {
diff --git a/apps/yaak-client/components/core/HttpMethodTag.tsx b/apps/yaak-client/components/core/HttpMethodTag.tsx
index 057971e2..90124825 100644
--- a/apps/yaak-client/components/core/HttpMethodTag.tsx
+++ b/apps/yaak-client/components/core/HttpMethodTag.tsx
@@ -57,7 +57,7 @@ export function HttpMethodTagRaw({
let label = method.toUpperCase();
if (short) {
label = methodNames[method.toLowerCase()] ?? method.slice(0, 4);
- label = label.padStart(4, " ");
+ label = label.padEnd(4, " ");
}
const m = method.toUpperCase();
diff --git a/apps/yaak-client/package.json b/apps/yaak-client/package.json
index 7b6a8d52..d2026395 100644
--- a/apps/yaak-client/package.json
+++ b/apps/yaak-client/package.json
@@ -59,9 +59,9 @@
"nanoid": "^5.0.9",
"papaparse": "^5.4.1",
"parse-color": "^1.0.0",
- "react": "^19.1.0",
+ "react": "^19.2.0",
"react-colorful": "^5.6.1",
- "react-dom": "^19.1.0",
+ "react-dom": "^19.2.0",
"react-markdown": "^10.1.0",
"react-pdf": "^10.0.1",
"react-syntax-highlighter": "^16.1.0",
@@ -70,10 +70,10 @@
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"slugify": "^1.6.6",
- "uuid": "^11.1.0",
+ "uuid": "^14.0.0",
"vkbeautify": "^0.99.3",
"whatwg-mimetype": "^4.0.0",
- "yaml": "^2.6.1"
+ "yaml": "^2.8.3"
},
"devDependencies": {
"@lezer/generator": "^1.8.0",
@@ -83,12 +83,12 @@
"@types/node": "^24.0.13",
"@types/papaparse": "^5.3.16",
"@types/parse-color": "^1.0.3",
- "@types/react": "^19.1.8",
- "@types/react-dom": "^19.1.6",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^10.0.0",
"@types/whatwg-mimetype": "^3.0.2",
- "@vitejs/plugin-react": "^4.6.0",
+ "@vitejs/plugin-react": "^6.0.0",
"@yaakapp-internal/theme": "^1.0.0",
"@yaakapp-internal/ui": "^1.0.0",
"autoprefixer": "^10.4.21",
@@ -98,8 +98,8 @@
"postcss-nesting": "^13.0.2",
"tailwindcss": "^3.4.17",
"vite": "^7.0.8",
- "vite-plugin-static-copy": "^3.1.2",
- "vite-plugin-svgr": "^4.3.0",
+ "vite-plugin-static-copy": "^3.3.0",
+ "vite-plugin-svgr": "^4.5.0",
"vite-plugin-top-level-await": "^1.5.0",
"vite-plugin-wasm": "^3.5.0"
}
diff --git a/apps/yaak-proxy/package.json b/apps/yaak-proxy/package.json
index 9db380c6..2ca719cd 100644
--- a/apps/yaak-proxy/package.json
+++ b/apps/yaak-proxy/package.json
@@ -19,13 +19,13 @@
"classnames": "^2.5.1",
"jotai": "^2.18.0",
"motion": "^12.4.7",
- "react": "^19.1.0",
- "react-dom": "^19.1.0"
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
},
"devDependencies": {
- "@types/react": "^19.1.8",
- "@types/react-dom": "^19.1.6",
- "@vitejs/plugin-react": "^4.6.0",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
+ "@vitejs/plugin-react": "^6.0.0",
"typescript": "^5.8.3",
"vite": "^7.0.8"
}
diff --git a/apps/yaak-proxy/tsconfig.node.json b/apps/yaak-proxy/tsconfig.node.json
index c87264aa..4c74079e 100644
--- a/apps/yaak-proxy/tsconfig.node.json
+++ b/apps/yaak-proxy/tsconfig.node.json
@@ -2,9 +2,10 @@
"compilerOptions": {
"composite": true,
"module": "ESNext",
- "moduleResolution": "Node",
+ "moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
- "noUncheckedIndexedAccess": true
+ "noUncheckedIndexedAccess": true,
+ "skipLibCheck": true
},
"include": ["vite.config.ts"]
}
diff --git a/apps/yaak-proxy/vite-env.d.ts b/apps/yaak-proxy/vite-env.d.ts
index 11f02fe2..bc2d8a36 100644
--- a/apps/yaak-proxy/vite-env.d.ts
+++ b/apps/yaak-proxy/vite-env.d.ts
@@ -1 +1 @@
-///
+///
diff --git a/biome.json b/biome.json
deleted file mode 100644
index 257fc380..00000000
--- a/biome.json
+++ /dev/null
@@ -1,80 +0,0 @@
-{
- "$schema": "https://biomejs.dev/schemas/2.3.13/schema.json",
- "linter": {
- "enabled": true,
- "rules": {
- "recommended": true,
- "a11y": {
- "useKeyWithClickEvents": "off"
- },
- "style": {
- "noRestrictedImports": {
- "level": "error",
- "options": {
- "paths": {
- "@tauri-apps/api/core": "Use lib/tauri.ts instead of importing @tauri-apps directly",
- "@tauri-apps/api/event": "Use lib/tauri.ts instead of importing @tauri-apps directly",
- "@tauri-apps/api/webviewWindow": "Use lib/tauri.ts instead of importing @tauri-apps directly",
- "@tauri-apps/plugin-os": "Use lib/tauri.ts instead of importing @tauri-apps directly"
- }
- }
- }
- }
- }
- },
- "formatter": {
- "enabled": true,
- "indentStyle": "space",
- "indentWidth": 2,
- "lineWidth": 100,
- "bracketSpacing": true
- },
- "css": {
- "parser": {
- "tailwindDirectives": true
- },
- "linter": {
- "enabled": false
- }
- },
- "javascript": {
- "formatter": {
- "quoteStyle": "single",
- "jsxQuoteStyle": "double",
- "trailingCommas": "all",
- "semicolons": "always"
- }
- },
- "overrides": [
- {
- "includes": ["apps/yaak-proxy/lib/tauri.ts"],
- "linter": {
- "rules": {
- "style": {
- "noRestrictedImports": "off"
- }
- }
- }
- }
- ],
- "files": {
- "includes": [
- "**",
- "!**/node_modules",
- "!**/dist",
- "!**/build",
- "!target",
- "!scripts",
- "!crates",
- "!crates-tauri",
- "!apps/yaak-client/tailwind.config.cjs",
- "!apps/yaak-client/postcss.config.cjs",
- "!apps/yaak-client/vite.config.ts",
- "!apps/yaak-client/routeTree.gen.ts",
- "!packages/plugin-runtime-types/lib",
- "!**/bindings",
- "!flatpak",
- "!npm"
- ]
- }
-}
diff --git a/crates-cli/yaak-cli/src/plugin_events.rs b/crates-cli/yaak-cli/src/plugin_events.rs
index cadc42dc..bdd37e7e 100644
--- a/crates-cli/yaak-cli/src/plugin_events.rs
+++ b/crates-cli/yaak-cli/src/plugin_events.rs
@@ -14,6 +14,7 @@ use yaak::plugin_events::{
use yaak::render::{render_grpc_request, render_http_request};
use yaak::send::{SendHttpRequestWithPluginsParams, send_http_request_with_plugins};
use yaak_crypto::manager::EncryptionManager;
+use yaak_http::cookies::get_cookie_value_from_jar;
use yaak_models::blob_manager::BlobManager;
use yaak_models::models::Environment;
use yaak_models::queries::any_request::AnyRequest;
@@ -496,10 +497,8 @@ async fn build_plugin_reply(
}
};
- let value = cookie_jar.cookies.into_iter().find_map(|c| {
- let (name, value) = parse_cookie_name_value(&c.raw_cookie)?;
- if name == req.name { Some(value) } else { None }
- });
+ let value =
+ get_cookie_value_from_jar(cookie_jar.cookies, &req.name, req.domain.as_deref());
Some(InternalEventPayload::GetCookieValueResponse(GetCookieValueResponse { value }))
}
HostRequest::WindowInfo(req) => {
@@ -532,7 +531,6 @@ async fn render_json_value_for_cli(
render_json_value_raw(value, vars, cb, opt).await
}
-
fn parse_cookie_name_value(raw_cookie: &str) -> Option<(String, String)> {
let first_part = raw_cookie.split(';').next()?.trim();
let (name, value) = first_part.split_once('=')?;
diff --git a/crates-tauri/yaak-app-client/src/import.rs b/crates-tauri/yaak-app-client/src/import.rs
index e8b960ef..53c94a5e 100644
--- a/crates-tauri/yaak-app-client/src/import.rs
+++ b/crates-tauri/yaak-app-client/src/import.rs
@@ -1,9 +1,10 @@
use crate::PluginContextExt;
-use crate::error::Result;
+use crate::error::{Error, Result};
use crate::models_ext::QueryManagerExt;
use log::info;
use std::collections::BTreeMap;
use std::fs::read_to_string;
+use std::io::ErrorKind;
use tauri::{Manager, Runtime, WebviewWindow};
use yaak_core::WorkspaceContext;
use yaak_models::models::{
@@ -18,8 +19,7 @@ pub(crate) async fn import_data(
file_path: &str,
) -> Result {
let plugin_manager = window.state::();
- let file =
- read_to_string(file_path).unwrap_or_else(|_| panic!("Unable to read file {}", file_path));
+ let file = read_import_file(file_path)?;
let file_contents = file.as_str();
let import_result = plugin_manager.import_data(&window.plugin_context(), file_contents).await?;
@@ -127,3 +127,41 @@ pub(crate) async fn import_data(
Ok(upserted)
}
+
+fn read_import_file(file_path: &str) -> Result {
+ read_to_string(file_path).map_err(|err| {
+ if err.kind() == ErrorKind::InvalidData {
+ Error::GenericError(format!(
+ "Import file must be UTF-8 text; binary files are not supported: {file_path}"
+ ))
+ } else {
+ Error::GenericError(format!("Unable to read import file {file_path}: {err}"))
+ }
+ })
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::fs::{remove_file, write};
+ use std::time::{SystemTime, UNIX_EPOCH};
+
+ #[test]
+ fn read_import_file_returns_error_for_binary_file() {
+ let path = std::env::temp_dir().join(format!(
+ "yaak-import-binary-{}.pftrace",
+ SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .expect("system time before unix epoch")
+ .as_nanos()
+ ));
+ write(&path, [0xff, 0xfe, 0xfd]).expect("write binary fixture");
+
+ let err = read_import_file(path.to_str().expect("temp path is utf-8"))
+ .expect_err("binary import should return an error");
+
+ assert!(err.to_string().contains("binary files are not supported"));
+
+ remove_file(path).expect("remove binary fixture");
+ }
+}
diff --git a/crates-tauri/yaak-app-client/src/lib.rs b/crates-tauri/yaak-app-client/src/lib.rs
index c67a96b7..aea200c5 100644
--- a/crates-tauri/yaak-app-client/src/lib.rs
+++ b/crates-tauri/yaak-app-client/src/lib.rs
@@ -34,8 +34,7 @@ use tokio::time;
use yaak_common::command::new_checked_command;
use yaak_crypto::manager::EncryptionManager;
use yaak_grpc::manager::{GrpcConfig, GrpcHandle};
-use yaak_templates::strip_json_comments::strip_json_comments;
-use yaak_grpc::{Code, ServiceDefinition, serialize_message};
+use yaak_grpc::{Code, ServiceDefinition};
use yaak_mac_window::AppHandleMacWindowExt;
use yaak_models::models::{
AnyModel, CookieJar, Environment, GrpcConnection, GrpcConnectionState, GrpcEvent,
@@ -60,6 +59,7 @@ use yaak_plugins::template_callback::PluginTemplateCallback;
use yaak_sse::sse::ServerSentEvent;
use yaak_tauri_utils::window::WorkspaceWindowTrait;
use yaak_templates::format_json::format_json;
+use yaak_templates::strip_json_comments::strip_json_comments;
use yaak_templates::{RenderErrorBehavior, RenderOptions, Tokens, transform_args};
use yaak_tls::find_client_certificate;
@@ -591,7 +591,7 @@ async fn cmd_grpc_go(
&method,
in_msg_stream,
&metadata,
- client_cert,
+ client_cert.clone(),
on_message.clone(),
)
.await,
@@ -607,7 +607,7 @@ async fn cmd_grpc_go(
&method,
in_msg_stream,
&metadata,
- client_cert,
+ client_cert.clone(),
on_message.clone(),
)
.await,
@@ -620,7 +620,9 @@ async fn cmd_grpc_go(
(false, false) => (
None,
Some(
- connection.unary(&service, &method, &msg, &metadata, client_cert).await,
+ connection
+ .unary(&service, &method, &msg, &metadata, client_cert.clone())
+ .await,
),
),
};
@@ -658,11 +660,34 @@ async fn cmd_grpc_go(
&UpdateSource::from_window_label(window.label()),
)
.unwrap();
+ let response_message = msg.into_inner();
+ let content = match connection
+ .serialize_message(&response_message, &metadata, client_cert.clone())
+ .await
+ {
+ Ok(content) => content,
+ Err(err) => {
+ app_handle
+ .db()
+ .upsert_grpc_event(
+ &GrpcEvent {
+ content: "Failed to read response".to_string(),
+ error: Some(err.to_string()),
+ status: Some(Code::Internal as i32),
+ event_type: GrpcEventType::ConnectionEnd,
+ ..base_event.clone()
+ },
+ &UpdateSource::from_window_label(window.label()),
+ )
+ .unwrap();
+ return;
+ }
+ };
app_handle
.db()
.upsert_grpc_event(
&GrpcEvent {
- content: serialize_message(&msg.into_inner()).unwrap(),
+ content,
event_type: GrpcEventType::ServerMessage,
..base_event.clone()
},
@@ -797,7 +822,28 @@ async fn cmd_grpc_go(
loop {
match stream.message().await {
Ok(Some(msg)) => {
- let message = serialize_message(&msg).unwrap();
+ let message = match connection
+ .serialize_message(&msg, &metadata, client_cert.clone())
+ .await
+ {
+ Ok(message) => message,
+ Err(err) => {
+ app_handle
+ .db()
+ .upsert_grpc_event(
+ &GrpcEvent {
+ content: "Failed to read response".to_string(),
+ error: Some(err.to_string()),
+ status: Some(Code::Internal as i32),
+ event_type: GrpcEventType::ConnectionEnd,
+ ..base_event.clone()
+ },
+ &UpdateSource::from_window_label(window.label()),
+ )
+ .unwrap();
+ break;
+ }
+ };
app_handle
.db()
.upsert_grpc_event(
diff --git a/crates-tauri/yaak-app-client/src/plugin_events.rs b/crates-tauri/yaak-app-client/src/plugin_events.rs
index 1066a60e..6afe6e4a 100644
--- a/crates-tauri/yaak-app-client/src/plugin_events.rs
+++ b/crates-tauri/yaak-app-client/src/plugin_events.rs
@@ -19,6 +19,7 @@ use yaak::plugin_events::{
GroupedPluginEvent, HostRequest, SharedPluginEventContext, handle_shared_plugin_event,
};
use yaak_crypto::manager::EncryptionManager;
+use yaak_http::cookies::get_cookie_value_from_jar;
use yaak_models::models::{HttpResponse, Plugin};
use yaak_models::queries::any_request::AnyRequest;
use yaak_models::util::UpdateSource;
@@ -422,12 +423,7 @@ async fn handle_host_plugin_request(
let window = get_window_from_plugin_context(app_handle, plugin_context)?;
let value = match cookie_jar_from_window(&window) {
None => None,
- Some(j) => j.cookies.into_iter().find_map(|c| match Cookie::parse(c.raw_cookie) {
- Ok(c) if c.name().to_string().eq(&req.name) => {
- Some(c.value_trimmed().to_string())
- }
- _ => None,
- }),
+ Some(j) => get_cookie_value_from_jar(j.cookies, &req.name, req.domain.as_deref()),
};
Ok(Some(InternalEventPayload::GetCookieValueResponse(GetCookieValueResponse { value })))
}
diff --git a/crates/yaak-grpc/src/lib.rs b/crates/yaak-grpc/src/lib.rs
index f38cf64a..a8c770a8 100644
--- a/crates/yaak-grpc/src/lib.rs
+++ b/crates/yaak-grpc/src/lib.rs
@@ -37,7 +37,7 @@ pub struct MethodDefinition {
static SERIALIZE_OPTIONS: &'static SerializeOptions =
&SerializeOptions::new().skip_default_fields(false).stringify_64_bit_integers(false);
-pub fn serialize_message(msg: &DynamicMessage) -> Result {
+pub(crate) fn serialize_dynamic_message_json(msg: &DynamicMessage) -> Result {
let mut buf = Vec::new();
let mut se = serde_json::Serializer::pretty(&mut buf);
msg.serialize_with_options(&mut se, SERIALIZE_OPTIONS).map_err(|e| e.to_string())?;
diff --git a/crates/yaak-grpc/src/manager.rs b/crates/yaak-grpc/src/manager.rs
index dd2c1c53..80a71b55 100644
--- a/crates/yaak-grpc/src/manager.rs
+++ b/crates/yaak-grpc/src/manager.rs
@@ -2,7 +2,8 @@ use crate::codec::DynamicCodec;
use crate::error::Error::GenericError;
use crate::error::Result;
use crate::reflection::{
- fill_pool_from_files, fill_pool_from_reflection, method_desc_to_path, reflect_types_for_message,
+ fill_pool_from_files, fill_pool_from_reflection, method_desc_to_path,
+ reflect_types_for_dynamic_message, reflect_types_for_message,
};
use crate::transport::get_transport;
use crate::{MethodDefinition, ServiceDefinition, json_schema};
@@ -11,8 +12,11 @@ use hyper_util::client::legacy::Client;
use hyper_util::client::legacy::connect::HttpConnector;
use log::{info, warn};
pub use prost_reflect::DynamicMessage;
+use prost_reflect::ReflectMessage;
+use prost_reflect::prost::Message;
use prost_reflect::{DescriptorPool, MethodDescriptor, ServiceDescriptor};
use serde_json::Deserializer;
+use std::borrow::Cow;
use std::collections::BTreeMap;
use std::error::Error;
use std::fmt;
@@ -115,6 +119,38 @@ impl GrpcConnection {
Ok(client.unary(req, path, codec).await?)
}
+ pub async fn serialize_message(
+ &self,
+ message: &DynamicMessage,
+ metadata: &BTreeMap,
+ client_cert: Option,
+ ) -> Result {
+ let message = if self.use_reflection {
+ reflect_types_for_dynamic_message(
+ self.pool.clone(),
+ &self.uri,
+ message,
+ metadata,
+ client_cert,
+ )
+ .await?;
+
+ let message_name = message.descriptor().full_name().to_string();
+ let message_desc = {
+ let pool = self.pool.read().await;
+ pool.get_message_by_name(&message_name)
+ .ok_or(GenericError(format!("Failed to find message {message_name}")))?
+ };
+ let mut message_with_updated_pool = DynamicMessage::new(message_desc);
+ message_with_updated_pool.merge(message.encode_to_vec().as_slice())?;
+ Cow::Owned(message_with_updated_pool)
+ } else {
+ Cow::Borrowed(message)
+ };
+
+ crate::serialize_dynamic_message_json(message.as_ref()).map_err(GenericError)
+ }
+
pub async fn streaming(
&self,
service: &str,
diff --git a/crates/yaak-grpc/src/reflection.rs b/crates/yaak-grpc/src/reflection.rs
index ca41a9c1..7ea95266 100644
--- a/crates/yaak-grpc/src/reflection.rs
+++ b/crates/yaak-grpc/src/reflection.rs
@@ -7,7 +7,7 @@ use anyhow::anyhow;
use async_recursion::async_recursion;
use log::{debug, info, warn};
use prost::Message;
-use prost_reflect::{DescriptorPool, MethodDescriptor};
+use prost_reflect::{DescriptorPool, DynamicMessage, MethodDescriptor, ReflectMessage, Value};
use prost_types::{FileDescriptorProto, FileDescriptorSet};
use std::collections::{BTreeMap, HashSet};
use std::env::temp_dir;
@@ -233,6 +233,83 @@ pub(crate) async fn reflect_types_for_message(
Ok(())
}
+pub(crate) async fn reflect_types_for_dynamic_message(
+ pool: Arc>,
+ uri: &Uri,
+ message: &DynamicMessage,
+ metadata: &BTreeMap,
+ client_cert: Option,
+) -> Result<()> {
+ let mut extra_types = HashSet::new();
+ collect_any_types_from_dynamic_message(message, &mut extra_types);
+
+ if extra_types.is_empty() {
+ return Ok(());
+ }
+
+ let mut client = AutoReflectionClient::new(uri, false, client_cert)?;
+ for extra_type in extra_types {
+ {
+ let guard = pool.read().await;
+ if guard.get_message_by_name(&extra_type).is_some() {
+ continue;
+ }
+ }
+ info!("Adding response file descriptor for {:?} from reflection", extra_type);
+ let req = MessageRequest::FileContainingSymbol(extra_type.clone().into());
+ let resp = match client.send_reflection_request(req, metadata).await {
+ Ok(r) => r,
+ Err(e) => {
+ return Err(GenericError(format!(
+ "Error sending reflection request for response @type \"{extra_type}\": {e:?}",
+ )));
+ }
+ };
+ let files = match resp {
+ MessageResponse::FileDescriptorResponse(resp) => resp.file_descriptor_proto,
+ _ => panic!("Expected a FileDescriptorResponse variant"),
+ };
+
+ {
+ let mut guard = pool.write().await;
+ add_file_descriptors_to_pool(files, &mut *guard, &mut client, metadata).await;
+ }
+ }
+
+ Ok(())
+}
+
+fn collect_any_types_from_dynamic_message(message: &DynamicMessage, out: &mut HashSet) {
+ if message.descriptor().full_name() == "google.protobuf.Any" {
+ if let Some(Value::String(type_url)) = message.get_field_by_name("type_url").as_deref() {
+ if let Some(full_name) = type_url.rsplit_once('/').map(|(_, name)| name) {
+ out.insert(full_name.to_string());
+ }
+ }
+ }
+
+ for (_, value) in message.fields() {
+ collect_any_types_from_value(value, out);
+ }
+}
+
+fn collect_any_types_from_value(value: &Value, out: &mut HashSet) {
+ match value {
+ Value::Message(message) => collect_any_types_from_dynamic_message(message, out),
+ Value::List(values) => {
+ for value in values {
+ collect_any_types_from_value(value, out);
+ }
+ }
+ Value::Map(values) => {
+ for value in values.values() {
+ collect_any_types_from_value(value, out);
+ }
+ }
+ _ => {}
+ }
+}
+
#[async_recursion]
pub(crate) async fn add_file_descriptors_to_pool(
fds: Vec>,
diff --git a/crates/yaak-http/src/client.rs b/crates/yaak-http/src/client.rs
index 4f5bf423..10bfd18f 100644
--- a/crates/yaak-http/src/client.rs
+++ b/crates/yaak-http/src/client.rs
@@ -1,11 +1,36 @@
use crate::dns::LocalhostResolver;
use crate::error::Result;
use log::{debug, info, warn};
-use reqwest::{Client, Proxy, redirect};
+use reqwest::{Client, ClientBuilder, Proxy, redirect};
use std::sync::Arc;
use yaak_models::models::DnsOverride;
use yaak_tls::{ClientCertificateConfig, get_tls_config};
+pub const HTTP2_MAX_RESPONSE_HEADER_LIST_SIZE: u32 = 1024 * 1024;
+
+fn client_builder() -> ClientBuilder {
+ Client::builder().http2_max_header_list_size(HTTP2_MAX_RESPONSE_HEADER_LIST_SIZE)
+}
+
+#[derive(Clone)]
+pub struct ConfiguredClient {
+ inner: Client,
+}
+
+impl ConfiguredClient {
+ pub(crate) fn build_default() -> Result {
+ Ok(Self { inner: client_builder().build()? })
+ }
+
+ pub(crate) fn from_inner(inner: Client) -> Self {
+ Self { inner }
+ }
+
+ pub(crate) fn inner(&self) -> &Client {
+ &self.inner
+ }
+}
+
/// Build a native-tls connector for maximum compatibility when certificate
/// validation is disabled. Unlike rustls, native-tls uses the OS TLS stack
/// (Secure Transport on macOS, SChannel on Windows, OpenSSL on Linux) which
@@ -87,8 +112,8 @@ impl HttpConnectionOptions {
/// Build a reqwest Client and return it along with the DNS resolver.
/// The resolver is returned separately so it can be configured per-request
/// to emit DNS timing events to the appropriate channel.
- pub(crate) fn build_client(&self) -> Result<(Client, Arc)> {
- let mut client = Client::builder()
+ pub(crate) fn build_client(&self) -> Result<(ConfiguredClient, Arc)> {
+ let mut client = client_builder()
.connection_verbose(true)
.redirect(redirect::Policy::none())
// Decompression is handled by HttpTransaction, not reqwest
@@ -108,8 +133,7 @@ impl HttpConnectionOptions {
client = client.use_preconfigured_tls(config);
} else {
// Use native TLS for maximum compatibility (supports TLS 1.0+)
- let connector =
- build_native_tls_connector(self.client_certificate.clone())?;
+ let connector = build_native_tls_connector(self.client_certificate.clone())?;
client = client.use_preconfigured_tls(connector);
}
@@ -136,7 +160,7 @@ impl HttpConnectionOptions {
self.client_certificate.is_some()
);
- Ok((client.build()?, resolver))
+ Ok((ConfiguredClient::from_inner(client.build()?), resolver))
}
}
diff --git a/crates/yaak-http/src/cookies.rs b/crates/yaak-http/src/cookies.rs
index 50940ad5..fa4d91f6 100644
--- a/crates/yaak-http/src/cookies.rs
+++ b/crates/yaak-http/src/cookies.rs
@@ -124,6 +124,30 @@ impl CookieStore {
}
}
+/// Get a stored cookie value by name, optionally scoped to an exact stored domain.
+pub fn get_cookie_value_from_jar(
+ cookies: impl IntoIterator- ,
+ name: &str,
+ domain: Option<&str>,
+) -> Option {
+ let domain = domain.and_then(normalize_cookie_domain_filter);
+
+ cookies.into_iter().find_map(|cookie| {
+ let (cookie_name, value) = parse_cookie_name_value(&cookie.raw_cookie)?;
+ if cookie_name != name {
+ return None;
+ }
+
+ if let Some(domain) = domain.as_deref() {
+ if !cookie_domain_matches_filter(&cookie.domain, domain) {
+ return None;
+ }
+ }
+
+ Some(value)
+ })
+}
+
/// Parse name=value from a cookie string (raw_cookie format)
fn parse_cookie_name_value(raw_cookie: &str) -> Option<(String, String)> {
// The raw_cookie typically looks like "name=value" or "name=value; attr1; attr2=..."
@@ -135,6 +159,20 @@ fn parse_cookie_name_value(raw_cookie: &str) -> Option<(String, String)> {
if name.is_empty() { None } else { Some((name, value)) }
}
+fn normalize_cookie_domain_filter(domain: &str) -> Option {
+ let domain = domain.trim().trim_start_matches('.').to_lowercase();
+ if domain.is_empty() { None } else { Some(domain) }
+}
+
+fn cookie_domain_matches_filter(cookie_domain: &CookieDomain, domain: &str) -> bool {
+ match cookie_domain {
+ CookieDomain::HostOnly(cookie_domain) | CookieDomain::Suffix(cookie_domain) => {
+ normalize_cookie_domain_filter(cookie_domain).is_some_and(|d| d == domain)
+ }
+ CookieDomain::NotPresent | CookieDomain::Empty => false,
+ }
+}
+
/// Parse a Set-Cookie header into a Cookie
fn parse_set_cookie(header_value: &str, request_url: &Url) -> Option {
let parsed = cookie::Cookie::parse(header_value).ok()?;
@@ -278,6 +316,15 @@ fn is_localhost(domain: &str) -> bool {
mod tests {
use super::*;
+ fn cookie(raw_cookie: &str, domain: CookieDomain) -> Cookie {
+ Cookie {
+ raw_cookie: raw_cookie.to_string(),
+ domain,
+ expires: CookieExpires::SessionEnd,
+ path: ("/".to_string(), false),
+ }
+ }
+
#[test]
fn test_parse_cookie_name_value() {
assert_eq!(
@@ -387,6 +434,52 @@ mod tests {
assert_eq!(store.get_all_cookies().len(), 1);
}
+ #[test]
+ fn test_get_cookie_value_preserves_name_only_first_match() {
+ let cookies = vec![
+ cookie("co-auth=", CookieDomain::HostOnly("foo.example.com".to_string())),
+ cookie("co-auth=token", CookieDomain::Suffix("example.com".to_string())),
+ ];
+
+ assert_eq!(get_cookie_value_from_jar(cookies, "co-auth", None), Some("".to_string()));
+ }
+
+ #[test]
+ fn test_get_cookie_value_matches_domain() {
+ let cookies = vec![
+ cookie("co-auth=", CookieDomain::HostOnly("foo.example.com".to_string())),
+ cookie("co-auth=token", CookieDomain::Suffix("example.com".to_string())),
+ ];
+
+ assert_eq!(
+ get_cookie_value_from_jar(cookies, "co-auth", Some("example.com")),
+ Some("token".to_string())
+ );
+ }
+
+ #[test]
+ fn test_get_cookie_value_normalizes_domain_filter() {
+ let cookies = vec![cookie(
+ "co-auth=token",
+ CookieDomain::Suffix("Example.COM".to_string()),
+ )];
+
+ assert_eq!(
+ get_cookie_value_from_jar(cookies, "co-auth", Some(" .example.com ")),
+ Some("token".to_string())
+ );
+ }
+
+ #[test]
+ fn test_get_cookie_value_requires_exact_stored_domain_match() {
+ let cookies = vec![cookie(
+ "co-auth=token",
+ CookieDomain::HostOnly("foo.example.com".to_string()),
+ )];
+
+ assert_eq!(get_cookie_value_from_jar(cookies, "co-auth", Some("example.com")), None);
+ }
+
#[test]
fn test_is_single_component_domain() {
// Single-component domains (TLDs)
diff --git a/crates/yaak-http/src/manager.rs b/crates/yaak-http/src/manager.rs
index 2034f124..cb9555d7 100644
--- a/crates/yaak-http/src/manager.rs
+++ b/crates/yaak-http/src/manager.rs
@@ -1,7 +1,6 @@
-use crate::client::HttpConnectionOptions;
+use crate::client::{ConfiguredClient, HttpConnectionOptions};
use crate::dns::LocalhostResolver;
use crate::error::Result;
-use reqwest::Client;
use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
@@ -10,7 +9,7 @@ use tokio::sync::RwLock;
/// A cached HTTP client along with its DNS resolver.
/// The resolver is needed to set the event sender per-request.
pub struct CachedClient {
- pub client: Client,
+ pub client: ConfiguredClient,
pub resolver: Arc,
}
diff --git a/crates/yaak-http/src/sender.rs b/crates/yaak-http/src/sender.rs
index 32059a68..063f0a47 100644
--- a/crates/yaak-http/src/sender.rs
+++ b/crates/yaak-http/src/sender.rs
@@ -5,7 +5,7 @@ use async_trait::async_trait;
use bytes::Bytes;
use futures_util::StreamExt;
use http_body::{Body as HttpBody, Frame, SizeHint};
-use reqwest::{Client, Method, Version};
+use reqwest::{Method, Version};
use std::fmt::Display;
use std::pin::Pin;
use std::task::{Context, Poll};
@@ -411,18 +411,18 @@ pub trait HttpSender: Send + Sync {
/// Reqwest-based implementation of HttpSender
pub struct ReqwestSender {
- client: Client,
+ client: crate::client::ConfiguredClient,
}
impl ReqwestSender {
/// Create a new ReqwestSender with a default client
pub fn new() -> Result {
- let client = Client::builder().build().map_err(Error::Client)?;
+ let client = crate::client::ConfiguredClient::build_default()?;
Ok(Self { client })
}
- /// Create a new ReqwestSender with a custom client
- pub fn with_client(client: Client) -> Self {
+ /// Create a new ReqwestSender with a configured client
+ pub fn with_client(client: crate::client::ConfiguredClient) -> Self {
Self { client }
}
}
@@ -444,7 +444,7 @@ impl HttpSender for ReqwestSender {
.map_err(|e| Error::RequestError(format!("Invalid HTTP method: {}", e)))?;
// Build the request
- let mut req_builder = self.client.request(method, &request.url);
+ let mut req_builder = self.client.inner().request(method, &request.url);
// Add headers
for header in request.headers {
@@ -513,7 +513,7 @@ impl HttpSender for ReqwestSender {
send_event(HttpResponseEvent::Info("Sending request to server".to_string()));
// Map some errors to our own, so they look nicer
- let response = self.client.execute(sendable_req).await.map_err(|e| {
+ let response = self.client.inner().execute(sendable_req).await.map_err(|e| {
if reqwest::Error::is_timeout(&e) {
Error::RequestTimeout(
request.options.timeout.unwrap_or(Duration::from_secs(0)).clone(),
diff --git a/crates/yaak-http/src/types.rs b/crates/yaak-http/src/types.rs
index b1e6e655..ed113752 100644
--- a/crates/yaak-http/src/types.rs
+++ b/crates/yaak-http/src/types.rs
@@ -226,10 +226,8 @@ async fn build_body(
let (body, content_type) = match body_type.as_str() {
"binary" => (build_binary_body(&body).await?, None),
- "graphql" => (build_graphql_body(&method, &body), Some("application/json".to_string())),
- "application/x-www-form-urlencoded" => {
- (build_form_body(&body), Some("application/x-www-form-urlencoded".to_string()))
- }
+ "graphql" => (build_graphql_body(&method, &body), None),
+ "application/x-www-form-urlencoded" => (build_form_body(&body), None),
"multipart/form-data" => build_multipart_body(&body, &headers).await?,
_ if body.contains_key("text") => (build_text_body(&body, body_type), None),
t => {
diff --git a/crates/yaak-models/guest-js/store.ts b/crates/yaak-models/guest-js/store.ts
index 4d8bbe52..573d3c84 100644
--- a/crates/yaak-models/guest-js/store.ts
+++ b/crates/yaak-models/guest-js/store.ts
@@ -144,9 +144,10 @@ export function duplicateModel {
diff --git a/crates/yaak-plugins/bindings/gen_events.ts b/crates/yaak-plugins/bindings/gen_events.ts
index ba130b7b..df3a1378 100644
--- a/crates/yaak-plugins/bindings/gen_events.ts
+++ b/crates/yaak-plugins/bindings/gen_events.ts
@@ -396,7 +396,7 @@ description?: string, };
export type GenericCompletionOption = { label: string, detail?: string, info?: string, type?: CompletionOptionType, boost?: number, };
-export type GetCookieValueRequest = { name: string, };
+export type GetCookieValueRequest = { name: string, domain?: string | null, };
export type GetCookieValueResponse = { value: string | null, };
diff --git a/crates/yaak-plugins/src/events.rs b/crates/yaak-plugins/src/events.rs
index 13e19096..5c9fdbd1 100644
--- a/crates/yaak-plugins/src/events.rs
+++ b/crates/yaak-plugins/src/events.rs
@@ -307,6 +307,9 @@ pub struct ListCookieNamesResponse {
#[ts(export, export_to = "gen_events.ts")]
pub struct GetCookieValueRequest {
pub name: String,
+
+ #[ts(optional = nullable)]
+ pub domain: Option,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, TS)]
diff --git a/crates/yaak-templates/pkg/yaak_templates.d.ts b/crates/yaak-templates/pkg/yaak_templates.d.ts
index df962dbc..5d24deef 100644
--- a/crates/yaak-templates/pkg/yaak_templates.d.ts
+++ b/crates/yaak-templates/pkg/yaak_templates.d.ts
@@ -1,5 +1,5 @@
/* tslint:disable */
/* eslint-disable */
+export function unescape_template(template: string): any;
export function escape_template(template: string): any;
export function parse_template(template: string): any;
-export function unescape_template(template: string): any;
diff --git a/crates/yaak-templates/pkg/yaak_templates_bg.js b/crates/yaak-templates/pkg/yaak_templates_bg.js
index 900d4685..4d11efa6 100644
--- a/crates/yaak-templates/pkg/yaak_templates_bg.js
+++ b/crates/yaak-templates/pkg/yaak_templates_bg.js
@@ -161,6 +161,20 @@ function takeFromExternrefTable0(idx) {
wasm.__externref_table_dealloc(idx);
return value;
}
+/**
+ * @param {string} template
+ * @returns {any}
+ */
+export function unescape_template(template) {
+ const ptr0 = passStringToWasm0(template, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
+ const len0 = WASM_VECTOR_LEN;
+ const ret = wasm.unescape_template(ptr0, len0);
+ if (ret[2]) {
+ throw takeFromExternrefTable0(ret[1]);
+ }
+ return takeFromExternrefTable0(ret[0]);
+}
+
/**
* @param {string} template
* @returns {any}
@@ -189,20 +203,6 @@ export function parse_template(template) {
return takeFromExternrefTable0(ret[0]);
}
-/**
- * @param {string} template
- * @returns {any}
- */
-export function unescape_template(template) {
- const ptr0 = passStringToWasm0(template, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
- const len0 = WASM_VECTOR_LEN;
- const ret = wasm.unescape_template(ptr0, len0);
- if (ret[2]) {
- throw takeFromExternrefTable0(ret[1]);
- }
- return takeFromExternrefTable0(ret[0]);
-}
-
export function __wbg_new_405e22f390576ce2() {
const ret = new Object();
return ret;
diff --git a/crates/yaak-templates/pkg/yaak_templates_bg.wasm b/crates/yaak-templates/pkg/yaak_templates_bg.wasm
index 11bc3ada..b29f4b9b 100644
Binary files a/crates/yaak-templates/pkg/yaak_templates_bg.wasm and b/crates/yaak-templates/pkg/yaak_templates_bg.wasm differ
diff --git a/package-lock.json b/package-lock.json
index 4fc9d6e8..f78805d9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -142,9 +142,9 @@
"nanoid": "^5.0.9",
"papaparse": "^5.4.1",
"parse-color": "^1.0.0",
- "react": "^19.1.0",
+ "react": "^19.2.0",
"react-colorful": "^5.6.1",
- "react-dom": "^19.1.0",
+ "react-dom": "^19.2.0",
"react-markdown": "^10.1.0",
"react-pdf": "^10.0.1",
"react-syntax-highlighter": "^16.1.0",
@@ -153,10 +153,10 @@
"remark-frontmatter": "^5.0.0",
"remark-gfm": "^4.0.1",
"slugify": "^1.6.6",
- "uuid": "^11.1.0",
+ "uuid": "^14.0.0",
"vkbeautify": "^0.99.3",
"whatwg-mimetype": "^4.0.0",
- "yaml": "^2.6.1"
+ "yaml": "^2.8.3"
},
"devDependencies": {
"@lezer/generator": "^1.8.0",
@@ -166,12 +166,12 @@
"@types/node": "^24.0.13",
"@types/papaparse": "^5.3.16",
"@types/parse-color": "^1.0.3",
- "@types/react": "^19.1.8",
- "@types/react-dom": "^19.1.6",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
"@types/react-syntax-highlighter": "^15.5.13",
"@types/uuid": "^10.0.0",
"@types/whatwg-mimetype": "^3.0.2",
- "@vitejs/plugin-react": "^4.6.0",
+ "@vitejs/plugin-react": "^6.0.0",
"@yaakapp-internal/theme": "^1.0.0",
"@yaakapp-internal/ui": "^1.0.0",
"autoprefixer": "^10.4.21",
@@ -181,8 +181,8 @@
"postcss-nesting": "^13.0.2",
"tailwindcss": "^3.4.17",
"vite": "^7.0.8",
- "vite-plugin-static-copy": "^3.1.2",
- "vite-plugin-svgr": "^4.3.0",
+ "vite-plugin-static-copy": "^3.3.0",
+ "vite-plugin-svgr": "^4.5.0",
"vite-plugin-top-level-await": "^1.5.0",
"vite-plugin-wasm": "^3.5.0"
}
@@ -213,14 +213,16 @@
}
},
"apps/yaak-client/node_modules/uuid": {
- "version": "11.1.0",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz",
+ "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
- "uuid": "dist/esm/bin/uuid"
+ "uuid": "dist-node/bin/uuid"
}
},
"apps/yaak-proxy": {
@@ -237,13 +239,13 @@
"classnames": "^2.5.1",
"jotai": "^2.18.0",
"motion": "^12.4.7",
- "react": "^19.1.0",
- "react-dom": "^19.1.0"
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0"
},
"devDependencies": {
- "@types/react": "^19.1.8",
- "@types/react-dom": "^19.1.6",
- "@vitejs/plugin-react": "^4.6.0",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
+ "@vitejs/plugin-react": "^6.0.0",
"typescript": "^5.8.3",
"vite": "^7.0.8"
}
@@ -592,38 +594,6 @@
"@babel/core": "^7.0.0-0"
}
},
- "node_modules/@babel/plugin-transform-react-jsx-self": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
- "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
- "node_modules/@babel/plugin-transform-react-jsx-source": {
- "version": "7.27.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
- "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/helper-plugin-utils": "^7.27.1"
- },
- "engines": {
- "node": ">=6.9.0"
- },
- "peerDependencies": {
- "@babel/core": "^7.0.0-0"
- }
- },
"node_modules/@babel/runtime": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz",
@@ -1490,9 +1460,9 @@
}
},
"node_modules/@hono/node-server": {
- "version": "1.19.9",
- "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz",
- "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==",
+ "version": "1.19.14",
+ "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz",
+ "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==",
"license": "MIT",
"engines": {
"node": ">=18.14.1"
@@ -2928,9 +2898,9 @@
}
},
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.27",
- "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
- "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
+ "version": "1.0.0-rc.7",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz",
+ "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==",
"dev": true,
"license": "MIT"
},
@@ -4457,51 +4427,6 @@
"@types/node": "*"
}
},
- "node_modules/@types/babel__core": {
- "version": "7.20.5",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
- "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.20.7",
- "@babel/types": "^7.20.7",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "node_modules/@types/babel__generator": {
- "version": "7.27.0",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
- "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__template": {
- "version": "7.4.4",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
- "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "node_modules/@types/babel__traverse": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
- "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/types": "^7.28.2"
- }
- },
"node_modules/@types/chai": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
@@ -4723,24 +4648,29 @@
"license": "ISC"
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
- "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz",
+ "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.28.0",
- "@babel/plugin-transform-react-jsx-self": "^7.27.1",
- "@babel/plugin-transform-react-jsx-source": "^7.27.1",
- "@rolldown/pluginutils": "1.0.0-beta.27",
- "@types/babel__core": "^7.20.5",
- "react-refresh": "^0.17.0"
+ "@rolldown/pluginutils": "1.0.0-rc.7"
},
"engines": {
- "node": "^14.18.0 || >=16.0.0"
+ "node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
- "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
+ "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
+ "babel-plugin-react-compiler": "^1.0.0",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@rolldown/plugin-babel": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ }
}
},
"node_modules/@vitest/expect": {
@@ -5130,9 +5060,9 @@
}
},
"node_modules/@xmldom/xmldom": {
- "version": "0.9.8",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz",
- "integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==",
+ "version": "0.9.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
+ "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==",
"license": "MIT",
"engines": {
"node": ">=14.6"
@@ -8942,9 +8872,9 @@
}
},
"node_modules/hono": {
- "version": "4.11.10",
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.10.tgz",
- "integrity": "sha512-kyWP5PAiMooEvGrA9jcD3IXF7ATu8+o7B3KCbPXid5se52NPqnOpM/r9qeW2heMnOekF4kqR1fXJqCYeCLKrZg==",
+ "version": "4.12.18",
+ "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz",
+ "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==",
"license": "MIT",
"engines": {
"node": ">=16.9.0"
@@ -13753,16 +13683,6 @@
}
}
},
- "node_modules/react-refresh": {
- "version": "0.17.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
- "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/react-syntax-highlighter": {
"version": "16.1.0",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-16.1.0.tgz",
@@ -16544,22 +16464,26 @@
}
},
"node_modules/vite-plugin-static-copy": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.1.4.tgz",
- "integrity": "sha512-iCmr4GSw4eSnaB+G8zc2f4dxSuDjbkjwpuBLLGvQYR9IW7rnDzftnUjOH5p4RYR+d4GsiBqXRvzuFhs5bnzVyw==",
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.4.0.tgz",
+ "integrity": "sha512-ekryzCw0ouAOE8tw4RvVL/dfqguXzumsV3FBKoKso4MQ1MUUrUXtl5RI4KpJQUNGqFEsg9kxl4EvDl02YtA9VQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.6.0",
- "p-map": "^7.0.3",
+ "p-map": "^7.0.4",
"picocolors": "^1.1.1",
"tinyglobby": "^0.2.15"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
},
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/sapphi-red"
+ },
"peerDependencies": {
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/vite-plugin-svgr": {
@@ -17086,9 +17010,9 @@
"license": "ISC"
},
"node_modules/yaml": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
- "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
+ "version": "2.8.4",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
+ "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -17257,9 +17181,9 @@
"version": "0.2.1",
"dependencies": {
"@hono/mcp": "^0.2.3",
- "@hono/node-server": "^1.19.10",
+ "@hono/node-server": "^1.19.13",
"@modelcontextprotocol/sdk": "^1.26.0",
- "hono": "^4.12.4",
+ "hono": "^4.12.14",
"zod": "^3.25.76"
},
"devDependencies": {
@@ -17267,27 +17191,6 @@
"typescript": "^5.9.3"
}
},
- "plugins-external/mcp-server/node_modules/@hono/node-server": {
- "version": "1.19.11",
- "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
- "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==",
- "license": "MIT",
- "engines": {
- "node": ">=18.14.1"
- },
- "peerDependencies": {
- "hono": "^4"
- }
- },
- "plugins-external/mcp-server/node_modules/hono": {
- "version": "4.12.7",
- "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.7.tgz",
- "integrity": "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==",
- "license": "MIT",
- "engines": {
- "node": ">=16.9.0"
- }
- },
"plugins/action-copy-curl": {
"name": "@yaak/action-copy-curl",
"version": "0.1.0"
@@ -17370,7 +17273,7 @@
"name": "@yaak/filter-xpath",
"version": "0.1.0",
"dependencies": {
- "@xmldom/xmldom": "^0.9.8",
+ "@xmldom/xmldom": "^0.9.10",
"xpath": "^0.0.34"
}
},
@@ -17385,7 +17288,7 @@
"name": "@yaak/importer-insomnia",
"version": "0.1.0",
"dependencies": {
- "yaml": "^2.4.2"
+ "yaml": "^2.8.3"
}
},
"plugins/importer-openapi": {
@@ -17393,7 +17296,7 @@
"version": "0.1.0",
"dependencies": {
"openapi-to-postmanv2": "^5.8.0",
- "yaml": "^2.4.2"
+ "yaml": "^2.8.3"
},
"devDependencies": {
"@types/openapi-to-postmanv2": "^5.0.0"
@@ -17489,25 +17392,27 @@
"name": "@yaak/template-function-uuid",
"version": "0.1.0",
"dependencies": {
- "uuid": "^11.1.0"
+ "uuid": "^14.0.0"
}
},
"plugins/template-function-uuid/node_modules/uuid": {
- "version": "11.1.0",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz",
+ "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"license": "MIT",
"bin": {
- "uuid": "dist/esm/bin/uuid"
+ "uuid": "dist-node/bin/uuid"
}
},
"plugins/template-function-xml": {
"name": "@yaak/template-function-xml",
"version": "0.1.0",
"dependencies": {
- "@xmldom/xmldom": "^0.9.8",
+ "@xmldom/xmldom": "^0.9.10",
"xpath": "^0.0.34"
}
},
diff --git a/packages/plugin-runtime-types/src/bindings/gen_events.ts b/packages/plugin-runtime-types/src/bindings/gen_events.ts
index ba130b7b..df3a1378 100644
--- a/packages/plugin-runtime-types/src/bindings/gen_events.ts
+++ b/packages/plugin-runtime-types/src/bindings/gen_events.ts
@@ -396,7 +396,7 @@ description?: string, };
export type GenericCompletionOption = { label: string, detail?: string, info?: string, type?: CompletionOptionType, boost?: number, };
-export type GetCookieValueRequest = { name: string, };
+export type GetCookieValueRequest = { name: string, domain?: string | null, };
export type GetCookieValueResponse = { value: string | null, };
diff --git a/packages/plugin-runtime-types/tsconfig.json b/packages/plugin-runtime-types/tsconfig.json
index 9e49c5e4..9faeff51 100644
--- a/packages/plugin-runtime-types/tsconfig.json
+++ b/packages/plugin-runtime-types/tsconfig.json
@@ -5,6 +5,7 @@
"lib": ["es2021", "dom"],
"declaration": true,
"declarationDir": "./lib",
+ "rootDir": "./src",
"outDir": "./lib",
"strict": true,
"types": ["node"]
diff --git a/plugins-external/mcp-server/package.json b/plugins-external/mcp-server/package.json
index 05ad04d2..11a2b09e 100644
--- a/plugins-external/mcp-server/package.json
+++ b/plugins-external/mcp-server/package.json
@@ -15,9 +15,9 @@
},
"dependencies": {
"@hono/mcp": "^0.2.3",
- "@hono/node-server": "^1.19.10",
+ "@hono/node-server": "^1.19.13",
"@modelcontextprotocol/sdk": "^1.26.0",
- "hono": "^4.12.4",
+ "hono": "^4.12.14",
"zod": "^3.25.76"
},
"devDependencies": {
diff --git a/plugins/filter-xpath/package.json b/plugins/filter-xpath/package.json
index 792bc017..94fa642c 100644
--- a/plugins/filter-xpath/package.json
+++ b/plugins/filter-xpath/package.json
@@ -9,7 +9,7 @@
"dev": "yaakcli dev"
},
"dependencies": {
- "@xmldom/xmldom": "^0.9.8",
+ "@xmldom/xmldom": "^0.9.10",
"xpath": "^0.0.34"
}
}
diff --git a/plugins/importer-insomnia/package.json b/plugins/importer-insomnia/package.json
index 468b90ec..3266a05c 100644
--- a/plugins/importer-insomnia/package.json
+++ b/plugins/importer-insomnia/package.json
@@ -10,6 +10,6 @@
"test": "vp test --run tests"
},
"dependencies": {
- "yaml": "^2.4.2"
+ "yaml": "^2.8.3"
}
}
diff --git a/plugins/importer-openapi/package.json b/plugins/importer-openapi/package.json
index a78d90b1..5b119b53 100644
--- a/plugins/importer-openapi/package.json
+++ b/plugins/importer-openapi/package.json
@@ -11,7 +11,7 @@
},
"dependencies": {
"openapi-to-postmanv2": "^5.8.0",
- "yaml": "^2.4.2"
+ "yaml": "^2.8.3"
},
"devDependencies": {
"@types/openapi-to-postmanv2": "^5.0.0"
diff --git a/plugins/template-function-cookie/src/index.ts b/plugins/template-function-cookie/src/index.ts
index d2587edb..05199bb7 100644
--- a/plugins/template-function-cookie/src/index.ts
+++ b/plugins/template-function-cookie/src/index.ts
@@ -11,12 +11,26 @@ export const plugin: PluginDefinition = {
type: "text",
name: "name",
label: "Cookie Name",
+ placeholder: "cookie_name",
+ },
+ {
+ type: "text",
+ name: "domain",
+ label: "Domain",
+ placeholder: "example.com",
+ description: "Optionally filter by domain, useful if multiple cookies with the same name.",
+ optional: true,
},
],
async onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise {
// The legacy name was cookie_name, but we changed it
const name = args.values.cookie_name ?? args.values.name;
- return ctx.cookies.getValue({ name: String(name) });
+ const domain = String(args.values.domain ?? "").trim();
+
+ return ctx.cookies.getValue({
+ name: String(name),
+ ...(domain.length > 0 ? { domain } : {}),
+ });
},
},
],
diff --git a/plugins/template-function-uuid/package.json b/plugins/template-function-uuid/package.json
index 203f556f..ebeafb2f 100644
--- a/plugins/template-function-uuid/package.json
+++ b/plugins/template-function-uuid/package.json
@@ -9,6 +9,6 @@
"dev": "yaakcli dev"
},
"dependencies": {
- "uuid": "^11.1.0"
+ "uuid": "^14.0.0"
}
}
diff --git a/plugins/template-function-xml/package.json b/plugins/template-function-xml/package.json
old mode 100755
new mode 100644
index b381b4ab..4d564f56
--- a/plugins/template-function-xml/package.json
+++ b/plugins/template-function-xml/package.json
@@ -11,7 +11,7 @@
"dev": "yaakcli dev"
},
"dependencies": {
- "@xmldom/xmldom": "^0.9.8",
+ "@xmldom/xmldom": "^0.9.10",
"xpath": "^0.0.34"
}
}
diff --git a/tsconfig.json b/tsconfig.json
index ded9262c..077d0a81 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -10,10 +10,12 @@
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
- "moduleResolution": "Node",
+ "moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
- "jsx": "react-jsx"
- }
+ "jsx": "react-jsx",
+ "types": ["node"]
+ },
+ "exclude": ["flatpak", "npm", "crates/yaak-templates/pkg"]
}