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